이 페이지의 내용은 이전 릴리스에 관한 것입니다. 해당 영문 페이지는 최신 릴리스에서 제거되었습니다.

timetable을 사용하여 타임스탬프가 지정된 데이터 전처리 후 탐색하기

이 예제에서는 timetable 데이터 컨테이너를 사용하여 센서 데이터에서 자전거 통행량의 패턴을 분석하는 방법을 보여줍니다. timetable 데이터 컨테이너는 타임스탬프가 지정된 데이터를 구성하고 전처리하는 데 사용됩니다. 데이터는 매사추세츠주 케임브리지에 있는 브로드웨이 스트리트(Broadway Street)의 센서 데이터입니다. 케임브리지시는 일반인들이 케임브리지 오픈 데이터(Cambridge Open Data) 사이트에서 전체 데이터 세트에 액세스할 수 있도록 하고 있습니다.

이 예제에서는 누락된 값 제거, 여러 시간 스텝을 가진 타임스탬프 데이터의 동기화 등 다양한 데이터 정리, 먼징(Munging), 전처리 작업을 수행하는 방법을 보여줍니다. 또한 timetable 데이터 컨테이너로 다음 작업을 수행하여 시각화와 그룹형 계산을 비롯한 데이터 탐색을 강조 표시합니다.

  • 일일 자전거 통행량 탐색

  • 자전거 통행량과 현지 기상 조건 비교

  • 다양한 요일과 시간에 대한 자전거 통행량 분석

자전거 통행량 데이터를 타임테이블로 가져오기

쉼표로 구분된 텍스트 파일에서 자전거 통행량 데이터 샘플을 가져옵니다. readtable 함수는 데이터를 테이블 형식으로 반환합니다. head 함수를 사용하여 처음 8개 행을 표시합니다.

bikeTbl = readtable('BicycleCounts.csv');
head(bikeTbl)
ans=8×5 table
         Timestamp             Day        Total    Westbound    Eastbound
    ___________________    ___________    _____    _________    _________

    2015-06-24 00:00:00    'Wednesday'      13         9             4   
    2015-06-24 01:00:00    'Wednesday'       3         3             0   
    2015-06-24 02:00:00    'Wednesday'       1         1             0   
    2015-06-24 03:00:00    'Wednesday'       1         1             0   
    2015-06-24 04:00:00    'Wednesday'       1         1             0   
    2015-06-24 05:00:00    'Wednesday'       7         3             4   
    2015-06-24 06:00:00    'Wednesday'      36         6            30   
    2015-06-24 07:00:00    'Wednesday'     141        13           128   

이 데이터에는 타임스탬프가 있어 타임테이블을 사용하여 데이터를 저장하고 분석하기가 편리합니다. 타임테이블은 테이블과 유사하지만 데이터 행과 연결된 타임스탬프를 포함합니다. 타임스탬프와 행 시간값은 각각 datetime 값과 duration 값으로 표시됩니다. 시점과 경과 시간을 표시할 때는 각각 datetime 데이터형과 duration 데이터형을 사용하는 것이 좋습니다.

table2timetable 함수를 사용하여 bikeTbl을 타임테이블로 변환해 보겠습니다. readtable은 테이블을 반환하기 때문에 변환 함수를 사용해야 합니다. table2timetable은 테이블의 첫 번째 datetime 변수 또는 duration 변수를 타임테이블의 행 시간값으로 변환합니다. 행 시간값은 행에 레이블을 지정하는 메타데이터입니다. 그러나 타임테이블을 표시할 경우에는 행 시간값과 타임테이블 변수가 비슷한 방식으로 표시됩니다. 참고로, 테이블의 변수는 5개인 반면, 타임테이블의 변수는 4개입니다.

bikeData = table2timetable(bikeTbl);
head(bikeData)
ans=8×5 timetable
         Timestamp             Day        Total    Westbound    Eastbound
    ___________________    ___________    _____    _________    _________

    2015-06-24 00:00:00    'Wednesday'      13         9             4   
    2015-06-24 01:00:00    'Wednesday'       3         3             0   
    2015-06-24 02:00:00    'Wednesday'       1         1             0   
    2015-06-24 03:00:00    'Wednesday'       1         1             0   
    2015-06-24 04:00:00    'Wednesday'       1         1             0   
    2015-06-24 05:00:00    'Wednesday'       7         3             4   
    2015-06-24 06:00:00    'Wednesday'      36         6            30   
    2015-06-24 07:00:00    'Wednesday'     141        13           128   

whos bikeTbl bikeData
  Name             Size              Bytes  Class        Attributes

  bikeData      9387x4             1487627  timetable              
  bikeTbl       9387x5             1562953  table                  

시간값과 데이터에 액세스하기

Day 변수를 categorical형으로 변환합니다. categorical형 데이터는 유한한 이산 값 집합(예: 요일 이름)으로 구성된 데이터를 위해 설계되었습니다. 요일 순서대로 범주를 나열합니다. 점 첨자를 사용하여 이름으로 변수에 액세스해 보겠습니다.

bikeData.Day = categorical(bikeData.Day,{'Sunday','Monday','Tuesday',...
                       'Wednesday','Thursday','Friday','Saturday'});  

타임테이블에서 시간값은 데이터 변수와는 별도로 처리됩니다. 타임테이블의 Properties에 액세스하여 행 시간값이 타임테이블의 첫 번째 차원이고 변수가 두 번째 차원이라는 것을 확인합니다. DimensionNames 속성은 두 개 차원의 이름을 표시하고, VariableNames 속성은 두 번째 차원의 변수 이름들을 표시합니다.

bikeData.Properties
ans = 
  TimetableProperties with properties:

             Description: ''
                UserData: []
          DimensionNames: {'Timestamp'  'Variables'}
           VariableNames: {'Day'  'Total'  'Westbound'  'Eastbound'}
    VariableDescriptions: {}
           VariableUnits: {}
      VariableContinuity: []
                RowTimes: [9387x1 datetime]
               StartTime: 2015-06-24 00:00:00
              SampleRate: NaN
                TimeStep: NaN
        CustomProperties: No custom properties are set.
      Use addprop and rmprop to modify CustomProperties.

table2timetable이 테이블을 타임테이블로 변환할 때 기본적으로 Timestamp를 첫 번째 차원 이름으로 할당했습니다. Timestamp가 원래 테이블의 변수 이름이기 때문입니다. Properties를 통해 차원 이름과, 타임테이블의 기타 메타데이터를 변경할 수 있습니다.

차원 이름을 TimeData로 변경해 보겠습니다.

bikeData.Properties.DimensionNames = {'Time' 'Data'};
bikeData.Properties
ans = 
  TimetableProperties with properties:

             Description: ''
                UserData: []
          DimensionNames: {'Time'  'Data'}
           VariableNames: {'Day'  'Total'  'Westbound'  'Eastbound'}
    VariableDescriptions: {}
           VariableUnits: {}
      VariableContinuity: []
                RowTimes: [9387x1 datetime]
               StartTime: 2015-06-24 00:00:00
              SampleRate: NaN
                TimeStep: NaN
        CustomProperties: No custom properties are set.
      Use addprop and rmprop to modify CustomProperties.

타임테이블의 처음 8개 행을 표시합니다.

head(bikeData)
ans=8×5 timetable
           Time               Day       Total    Westbound    Eastbound
    ___________________    _________    _____    _________    _________

    2015-06-24 00:00:00    Wednesday      13         9             4   
    2015-06-24 01:00:00    Wednesday       3         3             0   
    2015-06-24 02:00:00    Wednesday       1         1             0   
    2015-06-24 03:00:00    Wednesday       1         1             0   
    2015-06-24 04:00:00    Wednesday       1         1             0   
    2015-06-24 05:00:00    Wednesday       7         3             4   
    2015-06-24 06:00:00    Wednesday      36         6            30   
    2015-06-24 07:00:00    Wednesday     141        13           128   

가장 늦은 행 시간값과 가장 이른 행 시간값 사이의 경과일을 확인합니다. 차례로 변수를 참조할 때 점 표기법을 사용하여 변수에 액세스할 수 있습니다.

elapsedTime = max(bikeData.Time) - min(bikeData.Time)
elapsedTime = duration
   9383:30:00

elapsedTime.Format = 'd'
elapsedTime = duration
   390.98 days

지정된 날짜의 일반적인 자전거 수를 검토하려면 총 자전거 수의 평균과 서쪽 방향과 동쪽 방향으로 이동한 횟수를 계산하십시오.

중괄호를 사용하여 bikeData의 내용을 참조하면 숫자형 데이터를 행렬로 반환할 수 있습니다. 처음 8개 행을 표시해 보겠습니다. 표준 테이블 첨자를 사용하여 여러 변수에 액세스합니다.

counts = bikeData{:,2:end};
counts(1:8,:)
ans = 8×3

    13     9     4
     3     3     0
     1     1     0
     1     1     0
     1     1     0
     7     3     4
    36     6    30
   141    13   128

평균은 숫자형 데이터에만 적합하므로 숫자형 변수 선택을 위해 vartype 함수를 사용합니다. 변수를 선택할 때 수동으로 테이블 또는 타임테이블의 요소를 참조하는 것보다 vartype을 사용하는 것이 더 편리합니다. 평균을 계산하고 NaN 값은 생략해 보겠습니다.

counts = bikeData{:,vartype('numeric')};
mean(counts,'omitnan')
ans = 1×3

   49.8860   24.2002   25.6857

날짜와 시간으로 데이터 선택하기

휴일에 얼마나 많은 사람들이 자전거를 이용하는지 확인하기 위해 7월 4일 공휴일의 데이터를 검토해 보겠습니다. 2015년 7월 4일의 행 시간값을 사용하여 타임테이블의 요소를 참조합니다. 행 시간값에 대해 인덱싱할 때는 시간이 정확히 일치해야 합니다. 시간 인덱스는 datetime 값, duration 값, 또는 날짜와 시간으로 변환할 수 있는 문자형 벡터로 지정할 수 있습니다. 여러 시간을 하나의 배열로 지정할 수 있습니다.

특정 날짜와 시간으로 bikeData의 요소를 참조하여 2015년 7월 4일의 데이터를 추출해 보겠습니다. 날짜만 지정하면 시간은 자정 또는 00:00:00으로 가정됩니다.

bikeData('2015-07-04',:)
ans=1×5 timetable
           Time              Day       Total    Westbound    Eastbound
    ___________________    ________    _____    _________    _________

    2015-07-04 00:00:00    Saturday      8          7            1    

d = {'2015-07-04 08:00:00','2015-07-04 09:00:00'};
bikeData(d,:)
ans=2×5 timetable
           Time              Day       Total    Westbound    Eastbound
    ___________________    ________    _____    _________    _________

    2015-07-04 08:00:00    Saturday     15          3           12    
    2015-07-04 09:00:00    Saturday     21          4           17    

이 방법을 사용하여 하루 전체에 대한 데이터를 추출하는 것은 번거로운 일입니다. 특정 시간값에 대해 인덱싱하지 않고 시간 범위를 지정해도 됩니다. 시간 범위 첨자를 헬퍼로 생성하려면 timerange 함수를 사용하십시오.

2015년 7월 4일 하루 동안의 시간 범위를 타임테이블에 첨자로 사용합니다. 시작 시간을 7월 4일 자정으로, 종료 시간을 7월 5일 자정으로 지정합니다. 기본적으로 timerange는 시작 시간부터 종료 시간까지의 모든 시간값을 포함하되, 종료 시간은 포함하지 않습니다. 하루 동안의 자전거 수를 플로팅해 보겠습니다.

tr = timerange('2015-07-04','2015-07-05');
jul4 = bikeData(tr,'Total');
head(jul4)
ans=8×2 timetable
           Time            Total
    ___________________    _____

    2015-07-04 00:00:00      8  
    2015-07-04 01:00:00     13  
    2015-07-04 02:00:00      4  
    2015-07-04 03:00:00      1  
    2015-07-04 04:00:00      0  
    2015-07-04 05:00:00      1  
    2015-07-04 06:00:00      8  
    2015-07-04 07:00:00     16  

bar(jul4.Time,jul4.Total)
ylabel('Bicycle Counts')
title('Bicycle Counts on July 4, 2015')

플롯에서 하루 동안 자전거 수는 점점 늘어나다가 오후가 되면 안정을 유지합니다. 많은 기업들이 근무를 하지 않기 때문에 플롯에서 출퇴근 시간에 일반적인 통행량이 표시되지 않습니다. 어두워지면 축하 불꽃놀이가 시작되어 늦은 저녁 시간에는 자전거 수가 최대치에 달합니다. 이러한 추세를 더 자세히 검토하려면 이 데이터를 보통날의 데이터와 비교해야 합니다.

7월 4월의 데이터와 나머지 7월 날짜들의 데이터를 비교해 보겠습니다.

jul = bikeData(timerange('2015-07-01','2015-08-01'),:);
plot(jul.Time,jul.Total)
hold on
plot(jul4.Time,jul4.Total)
ylabel('Total Count')
title('Bicycle Counts in July')
hold off
legend('Bicycle Count','July 4 Bicycle Count')

플롯은 주중과 주말의 통행량 차이로 인한 변동 추세를 보여줍니다. 7월 4일과 5일의 통행량 패턴은 주말 통행량 패턴과 일치합니다. 7월 5일은 월요일이지만 공휴일로 지정되어 있습니다. 이러한 추세는 추가적인 전처리와 분석을 통해 더 자세히 검토할 수 있습니다.

timetable을 사용하여 시간값과 데이터 전처리하기

보통 타임스탬프가 지정된 데이터 세트는 정리가 되지 않기 때문에 이상과 오류가 있을 수 있습니다. 타임테이블은 이상과 오류를 해결하는 데 매우 적합합니다.

타임테이블은 행 시간값을 특정 순서대로 정렬할 필요가 없습니다. 해당 행 시간값별로 정렬되지 않은 행을 포함할 수 있습니다. 또한 타임테이블에는 같은 행 시간값을 가진 행이 여러 개 포함될 수 있습니다. 물론 행에는 서로 다른 데이터 값이 있을 수도 있습니다. 행 시간값이 고유하고 정렬되어 있는 경우에도 행 시간값 간의 시간 스텝의 크기는 다를 수 있습니다. 타임테이블에는 누락된 행 시간값을 나타내는 NaT 값 또는 NaN 값도 포함될 수 있습니다.

timetable 데이터형은 누락된 시간값, 중복된 시간값 또는 균일하지 않은 시간값을 해결할 수 있는 다양한 방법들을 제공합니다. 또한 데이터를 리샘플링하거나 집계하여 규칙적인 타임테이블을 생성할 수도 있습니다. 타임테이블이 규칙적이면 여기에 포함된 행 시간값은 정렬되어 있고 고유하며 균일한 간격의 시간 스텝을 가집니다.

  • 누락된 행 시간값을 찾으려면 ismissing을 사용하십시오.

  • 누락된 시간값과 데이터를 제거하려면 rmmissing을 사용하십시오.

  • 타임테이블을 행 시간값을 기준으로 정렬하려면 sortrows를 사용하십시오.

  • 고유하고 정렬된 행 시간값이 포함된 타임테이블을 만들려면 uniqueretime을 사용하십시오.

  • 규칙적인 타임테이블을 만들려면 균일한 간격의 시간 벡터를 지정하고 retime을 사용하십시오.

시간순으로 정렬하기

타임테이블이 정렬되어 있는지 확인합니다. 행 시간값이 오름차순으로 나열되어 있으면 타임테이블이 정렬된 것입니다.

issorted(bikeData)
ans = logical
   0

타임테이블을 정렬해 보겠습니다. sortrows 함수는 행을 해당 행 시간값을 기준으로 가장 이른 시간에서 가장 늦은 시간으로 정렬합니다. 중복된 행 시간값을 가진 행이 있으면 sortrows는 모든 중복 항목을 출력값으로 복사합니다.

bikeData = sortrows(bikeData);
issorted(bikeData)
ans = logical
   1

누락된 시간값과 데이터를 식별하고 제거하기

타임테이블에서는 변수 또는 행 시간값에 누락된 데이터 지정자를 사용할 수 있습니다. 예를 들어, 누락된 숫자형 값은 NaN으로, 누락된 datetime형 값은 NaT로 표시할 수 있습니다. standardizeMissing 함수, ismissing 함수, rmmissing 함수, fillmissing 함수를 사용하여 각각 누락된 값을 할당하고 찾고 제거하고 채울 수 있습니다.

타임테이블 변수의 누락된 값을 찾아 개수를 세어 보겠습니다. 이 예제에서 누락된 값은 수집된 데이터가 없는 경우를 나타냅니다.

missData = ismissing(bikeData);
sum(missData)
ans = 1×4

     1     3     3     3

ismissing의 출력값은 테이블과 크기가 같은 logical 행렬로, 누락된 데이터 값을 true로 식별합니다. 누락된 데이터 지정자가 있는 행을 표시해 보겠습니다.

idx = any(missData,2);
bikeData(idx,:)
ans=3×5 timetable
           Time                Day        Total    Westbound    Eastbound
    ___________________    ___________    _____    _________    _________

    2015-08-03 00:00:00    Monday          NaN        NaN          NaN   
    2015-08-03 01:00:00    Monday          NaN        NaN          NaN   
    NaT                    <undefined>     NaN        NaN          NaN   

ismissing(bikeData)는 시간값이 아니라 타임테이블의 변수에서만 누락된 데이터를 찾습니다. 누락된 행 시간값을 찾으려면 행 시간값에 대해 ismissing을 호출하십시오.

missTimes = ismissing(bikeData.Time);
bikeData(missTimes,:)
ans=2×5 timetable
    Time        Day        Total    Westbound    Eastbound
    ____    ___________    _____    _________    _________

    NaT     <undefined>     NaN        NaN          NaN   
    NaT     Friday            6          3            3   

이 예제에서 누락된 시간값 또는 데이터 값은 계측 오류를 나타내므로 제외할 수 있습니다. rmmissing을 사용하여 누락된 데이터 값이나 누락된 행 시간값이 포함된 테이블 행을 제거해 보겠습니다.

bikeData = rmmissing(bikeData);
sum(ismissing(bikeData))
ans = 1×4

     0     0     0     0

sum(ismissing(bikeData.Time))
ans = 0

중복된 시간값이나 중복된 데이터 제거하기

데이터에 중복된 시간값 및/또는 중복된 행이 있는지 확인합니다. 명확한 중복 항목은 계측 오차로 간주될 수도 있으므로 제외하는 것이 좋습니다. 정렬된 시간값들 사이의 차이가 정확하게 0인 경우를 찾아 중복된 시간값을 식별해 보겠습니다.

idx = diff(bikeData.Time) == 0;
dup = bikeData.Time(idx)
dup = 3x1 datetime array
   2015-08-21 00:00:00
   2015-11-19 23:00:00
   2015-11-19 23:00:00

반복되는 시간값은 3개이고, 2015년 11월 19일은 두 번 반복됩니다. 반복된 시간값과 관련된 데이터를 검토해 보겠습니다.

bikeData(dup(1),:)
ans=2×5 timetable
           Time             Day      Total    Westbound    Eastbound
    ___________________    ______    _____    _________    _________

    2015-08-21 00:00:00    Friday     14          9            5    
    2015-08-21 00:00:00    Friday     11          7            4    

bikeData(dup(2),:)
ans=3×5 timetable
           Time              Day       Total    Westbound    Eastbound
    ___________________    ________    _____    _________    _________

    2015-11-19 23:00:00    Thursday     17         15            2    
    2015-11-19 23:00:00    Thursday     17         15            2    
    2015-11-19 23:00:00    Thursday     17         15            2    

첫 번째의 경우 시간값이 중복되지만 데이터는 중복되지 않는 반면, 나머지의 경우는 시간값과 데이터가 완전히 중복됩니다. 타임테이블의 행에 다른 행과 동일한 행 시간값이 포함되어 있고, 데이터 값 또한 동일하게 포함되어 있으면 해당 행은 중복 항목으로 간주됩니다. unique를 사용하여 타임테이블에서 중복된 행을 제거할 수 있습니다. 또한 unique 함수는 행 시간값을 기준으로 행을 정렬합니다.

bikeData = unique(bikeData); 

시간값이 중복되지만 데이터는 중복되지 않는 행은 확인이 필요합니다. 이러한 시간값에 대한 데이터를 검토해 보겠습니다.

d = dup(1) + hours(-2:2);
bikeData(d,:)
ans=5×5 timetable
           Time              Day       Total    Westbound    Eastbound
    ___________________    ________    _____    _________    _________

    2015-08-20 22:00:00    Thursday     40         30           10    
    2015-08-20 23:00:00    Thursday     25         18            7    
    2015-08-21 00:00:00    Friday       11          7            4    
    2015-08-21 00:00:00    Friday       14          9            5    
    2015-08-21 02:00:00    Friday        6          5            1    

이 경우, 데이터와 그 관련 시간값들이 일관되기 때문에 중복된 시간값은 실수일 수 있습니다. 중복 항목이 01:00:00을 나타내는 것으로 보이지만 원래 몇 시여야 하는지 확실하지는 않습니다. 두 시간 지점의 데이터를 설명하기 위해 데이터를 누적할 수 있습니다.

sum(bikeData{dup(1),2:end})
ans = 1×3

    25    16     9

유일하게 수동으로 수행할 수 있는 작업입니다. 하지만 대부분의 행에서는 retime 함수로 이 계산을 수행할 수 있습니다. sum 함수를 사용하여 집계함으로써 데이터를 누적하고 고유 시간값으로 만듭니다. sum은 숫자형 데이터에는 적합하지만 타임테이블의 categorical형 데이터에는 적합하지 않습니다. vartype을 사용하여 숫자형 변수를 식별해 보겠습니다.

vt = vartype('numeric');
t = unique(bikeData.Time);
numData = retime(bikeData(:,vt),t,'sum');
head(numData)
ans=8×4 timetable
           Time            Total    Westbound    Eastbound
    ___________________    _____    _________    _________

    2015-06-24 00:00:00      13         9             4   
    2015-06-24 01:00:00       3         3             0   
    2015-06-24 02:00:00       1         1             0   
    2015-06-24 03:00:00       1         1             0   
    2015-06-24 04:00:00       1         1             0   
    2015-06-24 05:00:00       7         3             4   
    2015-06-24 06:00:00      36         6            30   
    2015-06-24 07:00:00     141        13           128   

categorical형 데이터의 합을 구할 수는 없지만 하나의 레이블이 하루를 나타내기 때문에 각 시간값의 첫 번째 값을 취하면 됩니다. 동일한 시간 벡터로 다시 retime 연산을 수행하여 타임테이블을 결합할 수 있습니다.

vc = vartype('categorical');
catData = retime(bikeData(:,vc),t,'firstvalue');
bikeData = [catData,numData];
bikeData(d,:)
ans=4×5 timetable
           Time              Day       Total    Westbound    Eastbound
    ___________________    ________    _____    _________    _________

    2015-08-20 22:00:00    Thursday     40         30           10    
    2015-08-20 23:00:00    Thursday     25         18            7    
    2015-08-21 00:00:00    Friday       25         16            9    
    2015-08-21 02:00:00    Friday        6          5            1    

시간 간격의 균등성 검사하기

이 데이터는 균등하게 1시간 간격의 시간 스텝을 가지는 것으로 보입니다. 타임테이블의 모든 행 시간값에 균등한 간격이 적용되었는지 확인하려면 isregular 함수를 사용하십시오. isregular는 중복되거나 누락된 시간값(NaT 또는 NaN) 없이 균일한 간격으로 정렬된 시간값(단조 증가)에 대해서는 true를 반환합니다.

isregular(bikeData)
ans = logical
   0

출력값 0 또는 false는 타임테이블의 시간값에 균일한 간격이 적용되지 않았다는 것을 나타냅니다. 시간 간격을 더 자세히 탐색해 보겠습니다.

dt = diff(bikeData.Time);
[min(dt); max(dt)]
ans = 2x1 duration array
   00:30:00
   03:00:00

타임테이블에 규칙적인 시간 간격을 적용하려면 retime 또는 synchronize를 사용하여 원하는 시간 간격을 지정하십시오.

일일 자전거 수량 확인하기

retime 함수를 사용하여 일일 자전거 수를 확인해 보겠습니다. sum 메서드를 사용하여 각 날짜의 개수 데이터를 누적할 수 있습니다. sum은 숫자형 데이터에는 적합하지만 타임테이블의 categorical형 데이터에는 적합하지 않습니다. 데이터형으로 변수를 식별하려면 vartype을 사용하십시오.

dayCountNum = retime(bikeData(:,vt),'daily','sum');
head(dayCountNum)
ans=8×4 timetable
           Time            Total    Westbound    Eastbound
    ___________________    _____    _________    _________

    2015-06-24 00:00:00    2141       1141         1000   
    2015-06-25 00:00:00    2106       1123          983   
    2015-06-26 00:00:00    1748        970          778   
    2015-06-27 00:00:00     695        346          349   
    2015-06-28 00:00:00     153         83           70   
    2015-06-29 00:00:00    1841        978          863   
    2015-06-30 00:00:00    2170       1145         1025   
    2015-07-01 00:00:00     997        544          453   

또다시, categorical형 데이터를 표시하기 위해 retime 연산을 적합한 메서드와 함께 다시 수행하고 타임테이블을 결합할 수 있습니다.

dayCountCat = retime(bikeData(:,vc),'daily','firstvalue');
dayCount = [dayCountCat,dayCountNum];
head(dayCount)
ans=8×5 timetable
           Time               Day       Total    Westbound    Eastbound
    ___________________    _________    _____    _________    _________

    2015-06-24 00:00:00    Wednesday    2141       1141         1000   
    2015-06-25 00:00:00    Thursday     2106       1123          983   
    2015-06-26 00:00:00    Friday       1748        970          778   
    2015-06-27 00:00:00    Saturday      695        346          349   
    2015-06-28 00:00:00    Sunday        153         83           70   
    2015-06-29 00:00:00    Monday       1841        978          863   
    2015-06-30 00:00:00    Tuesday      2170       1145         1025   
    2015-07-01 00:00:00    Wednesday     997        544          453   

자전거 수와 기상 데이터 동기화하기

자전거 수와 기상 데이터를 비교하여 날씨가 자전거 이용에 미치는 영향을 검토해 보겠습니다. 폭풍을 비롯해 매사추세츠주 보스턴의 과거 기상 데이터가 포함된 기상 타임테이블을 불러와 보겠습니다.

load BostonWeatherData
head(weatherData)
ans=8×4 timetable
       Time        TemperatureF    Humidity       Events   
    ___________    ____________    ________    ____________

    01-Jul-2015         72            78       Thunderstorm
    02-Jul-2015         72            60       None        
    03-Jul-2015         70            56       None        
    04-Jul-2015         67            75       None        
    05-Jul-2015         72            67       None        
    06-Jul-2015         74            69       None        
    07-Jul-2015         75            77       Rain        
    08-Jul-2015         79            68       Rain        

타임테이블의 시간값과 변수를 요약하려면 summary 함수를 사용하십시오.

summary(weatherData)
RowTimes:

    Time: 383x1 datetime
        Values:
            Min           01-Jul-2015 
            Median        08-Jan-2016 
            Max           17-Jul-2016 
            TimeStep      24:00:00    

Variables:

    TemperatureF: 383x1 double

        Values:

            Min              2      
            Median          55      
            Max             85      

    Humidity: 383x1 double

        Values:

            Min           29    
            Median        64    
            Max           97    

    Events: 383x1 categorical

        Values:

            Fog                 7   
            Hail                1   
            Rain              108   
            Rain-Snow           4   
            Snow               18   
            Thunderstorm       12   
            None              233   

synchronize를 사용하여 자전거 데이터와 기상 데이터를 공통된 시간 벡터로 결합합니다. synchronize 함수 도움말 페이지에 설명된 메서드를 사용하여 타임테이블 데이터를 리샘플링하거나 집계할 수 있습니다.

두 타임테이블의 데이터를 각 일별 시간 벡터의 교집합에서 생성된, 공통된 시간 벡터로 동기화해 보겠습니다.

data = synchronize(dayCount,weatherData,'intersection');
head(data)
ans=8×8 timetable
           Time               Day       Total    Westbound    Eastbound    TemperatureF    Humidity       Events   
    ___________________    _________    _____    _________    _________    ____________    ________    ____________

    2015-07-01 00:00:00    Wednesday     997        544          453            72            78       Thunderstorm
    2015-07-02 00:00:00    Thursday     1943       1033          910            72            60       None        
    2015-07-03 00:00:00    Friday        870        454          416            70            56       None        
    2015-07-04 00:00:00    Saturday      669        328          341            67            75       None        
    2015-07-05 00:00:00    Sunday        702        407          295            72            67       None        
    2015-07-06 00:00:00    Monday       1900       1029          871            74            69       None        
    2015-07-07 00:00:00    Tuesday      2106       1140          966            75            77       Rain        
    2015-07-08 00:00:00    Wednesday    1855        984          871            79            68       Rain        

별도의 y축에서 자전거 통행량과 실외 온도를 비교하여 추세를 검토합니다. 시각화를 위해 데이터에서 주말 부분은 제거해 보겠습니다.

idx = ~isweekend(data.Time);  
weekdayData = data(idx,{'TemperatureF','Total'});
figure
yyaxis left
plot(weekdayData.Time, weekdayData.Total) 
ylabel('Bicycle Count')
yyaxis right
plot(weekdayData.Time,weekdayData.TemperatureF) 
ylabel('Temperature (\circ F)')
title('Bicycle Counts and Temperature Over Time')
xlim([min(data.Time) max(data.Time)])

플롯에서 통행량 데이터와 기상 데이터가 유사한 추세를 보이는 것을 알 수 있습니다. 플롯을 확대해 보겠습니다.

xlim([datetime('2015-11-01'),datetime('2016-05-01')])

추세가 유사한 것으로 보아 날씨가 추울수록 자전거를 이용하는 사람들이 줄어든다는 것을 알 수 있습니다.

요일과 시간 모두를 기준으로 분석하기

요일이나 시간 등 다양한 간격을 기준으로 데이터를 검토합니다. varfun을 사용하여 변수에 대해 그룹형 계산을 수행하면 일별 총 자전거 수를 확인할 수 있습니다. sum 함수를 함수 핸들로 지정하고 이름-값 쌍을 사용하여 그룹화 변수와 원하는 출력 유형을 지정해 보겠습니다.

byDay = varfun(@sum,bikeData,'GroupingVariables','Day',...
             'OutputFormat','table')
byDay=7×5 table
       Day       GroupCount    sum_Total    sum_Westbound    sum_Eastbound
    _________    __________    _________    _____________    _____________

    Sunday          1344         25315          12471            12844    
    Monday          1343         79991          39219            40772    
    Tuesday         1320         81480          39695            41785    
    Wednesday       1344         86853          41726            45127    
    Thursday        1344         87516          42682            44834    
    Friday          1342         76643          36926            39717    
    Saturday        1343         30292          14343            15949    

figure
bar(byDay{:,{'sum_Westbound','sum_Eastbound'}})
legend({'Westbound','Eastbound'},'Location','eastoutside')
xticklabels({'Sun','Mon','Tue','Wed','Thu','Fri','Sat'})
title('Bicycle Count by Day of Week')

막대 플롯에서 주중에 통행량이 더 많은 것을 알 수 있습니다. 동쪽 방향 통행량과 서쪽 방향 통행량에 차이가 있는 것도 알 수 있습니다. 이는 사람들이 도시로 올 때와 도시에서 나갈 때 다른 경로를 이용한다는 의미인 것 같습니다. 또는 일부 사람들이 특정 날짜에 도시로 온 후 다른 날 돌아간 것일 수도 있습니다.

시간을 확인하고 varfun을 사용하여 그룹형 계산을 수행해 보겠습니다.

bikeData.HrOfDay = hour(bikeData.Time);
byHr = varfun(@mean,bikeData(:,{'Westbound','Eastbound','HrOfDay'}),...
    'GroupingVariables','HrOfDay','OutputFormat','table');
head(byHr)
ans=8×4 table
    HrOfDay    GroupCount    mean_Westbound    mean_Eastbound
    _______    __________    ______________    ______________

       0          389            5.4396            1.7686    
       1          389            2.7712           0.87147    
       2          391            1.8696           0.58312    
       3          391            0.7468             0.289    
       4          391           0.52685            1.0026    
       5          391           0.70588            4.7494    
       6          391            3.1228            22.097    
       7          391            9.1176             63.54    

bar(byHr{:,{'mean_Westbound','mean_Eastbound'}})
legend('Westbound','Eastbound','Location','eastoutside')
xlabel('Hour of Day')
ylabel('Bicycle Count')
title('Mean Bicycle Count by Hour of Day')

일반적인 출퇴근 시간인 오전 9시와 오후 5시 무렵에 통행량이 최고치에 달합니다. 그리고 동쪽 방향 추세와 서쪽 방향 추세가 다릅니다. 일반적으로 서쪽 방향은 케임브리지 근교의 주거 지역과 대학교로 향하는 경로입니다. 동쪽 방향은 보스턴으로 향하는 경로입니다.

늦은 오후에는 동쪽 방향보다 서쪽 방향으로 향하는 통행량이 더 많습니다. 아마 대학교 일정과 해당 지역의 식당가로 향하는 통행량 때문인 것 같습니다. 시간과 요일 모두를 기준으로 하여 추세를 검토해 보겠습니다.

byHrDay = varfun(@sum,bikeData,'GroupingVariables',{'HrOfDay','Day'},...
    'OutputFormat','table');
head(byHrDay)
ans=8×6 table
    HrOfDay       Day       GroupCount    sum_Total    sum_Westbound    sum_Eastbound
    _______    _________    __________    _________    _____________    _____________

       0       Sunday           56           473            345              128     
       0       Monday           55           202            145               57     
       0       Tuesday          55           297            213               84     
       0       Wednesday        56           374            286               88     
       0       Thursday         56           436            324              112     
       0       Friday           55           442            348               94     
       0       Saturday         56           580            455              125     
       1       Sunday           56           333            259               74     

요일을 변수로 취하도록 타임테이블을 정렬하려면 unstack 함수를 사용하십시오.

hrAndDayWeek = unstack(byHrDay(:,{'HrOfDay','Day','sum_Total'}),'sum_Total','Day'); 
head(hrAndDayWeek)
ans=8×8 table
    HrOfDay    Sunday    Monday    Tuesday    Wednesday    Thursday    Friday    Saturday
    _______    ______    ______    _______    _________    ________    ______    ________

       0        473        202       297         374          436        442       580   
       1        333         81       147         168          173        183       332   
       2        198         77        68          93          128        141       254   
       3         86         41        43          44           50         61        80   
       4         51         81       117         101          108         80        60   
       5        105        353       407         419          381        340       128   
       6        275       1750      1867        2066         1927       1625       351   
       7        553       5355      5515        5818         5731       4733       704   

ribbon(hrAndDayWeek.HrOfDay,hrAndDayWeek{:,2:end})
ylim([0 24])
xlim([0 8])
xticks(1:7)
xticklabels({'Sun','Mon','Tue','Wed','Thu','Fri','Sat'})
ylabel('Hour')
title('Bicycle Count by Hour and Day of Week')

월요일부터 금요일까지 평일에는 통행량이 러시아워에 최대치를 기록하고 저녁에는 점점 줄어드는 유사한 추세를 보입니다. 금요일의 경우 통행량이 줄어들지만 전반적인 추세는 다른 평일과 유사합니다. 토요일과 일요일은 러시아워에 통행량이 최대치가 아니며 오후로 갈수록 증가하는 서로 유사한 추세를 보입니다. 늦은 저녁의 추세도 월요일부터 금요일까지 유사하지만 금요일에는 통행량이 줄어듭니다.

러시아워의 통행량 분석하기

하루 전체 시간의 추세를 검토하기 위해 러시아워 시간값을 기준으로 데이터를 분할합니다. discretize 함수에 여러 시간값 또는 시간값 단위를 사용할 수 있습니다. 예를 들어, 데이터를 AM, AMRush, Day, PMRush, PM에 대한 그룹으로 구분합니다. 그런 다음, varfun을 사용하여 그룹별로 평균을 계산합니다.

bikeData.HrLabel = discretize(bikeData.HrOfDay,[0,6,10,15,19,24],'categorical',...
    {'AM','RushAM','Day','RushPM','PM'});
byHrBin = varfun(@mean,bikeData(:,{'Total','HrLabel'}),'GroupingVariables','HrLabel',...
    'OutputFormat','table')
byHrBin=5×3 table
    HrLabel    GroupCount    mean_Total
    _______    __________    __________

    AM            2342         3.5508  
    RushAM        1564         94.893  
    Day           1955         45.612  
    RushPM        1564         98.066  
    PM            1955         35.198  

bar(byHrBin.mean_Total)
cats = categories(byHrBin.HrLabel);
xticklabels(cats)
title('Mean Bicycle Count During Rush Hours')

일반적으로 이 지역의 저녁과 아침 러시아워 시간대의 자전거 통행량은 다른 시간대에 비해 2배 많습니다. 이른 아침에는 통행량이 매우 적지만, 늦은 저녁에는 아침과 저녁 러시아워를 제외한 낮 시간과 견줄 만큼 상당한 통행량이 있습니다.

참고 항목

| | | | | | | | | |

관련 항목