Main Content

timetable を使用したタイムスタンプ付きデータの前処理と探索

この例では、timetable データ コンテナーを使用してタイムスタンプ付きデータを編成および前処理し、センサー データから自転車の交通量パターンを解析する方法を示します。マサチューセッツ州ケンブリッジのブロードウェイ ストリートにあるセンサーのデータを使用します。ケンブリッジ市は、Cambridge Open Data サイトのすべてのデータ セットへのパブリック アクセスを提供しています。

この例では、データ クリーニング、マンジング、および欠損値の削除や異なるタイムステップのタイムスタンプ付きデータの同期などの前処理といったさまざまなタスクを実行する方法を示します。また、timetable データ コンテナーを使用して次を行い、可視化やグループ化された計算を含むデータ探索の詳細を示します。

  • 毎日の自転車交通量の調査

  • 自転車交通量と現地の天候条件の比較

  • さまざまな曜日や時間における自転車交通量の解析

timetable への自転車交通量データのインポート

コンマ区切りのテキスト ファイルから自転車交通量データのサンプルをインポートします。関数 readtable は、table でデータを返します。関数 head を使用して最初の 8 行を表示します。

bikeTbl = readtable('BicycleCounts.csv');
head(bikeTbl)
         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   

データにタイムスタンプがあるため、timetable を使用してデータを保存および解析すると便利です。timetable は table と似ていますが、データ行に関連付けられているタイムスタンプが含まれています。タイムスタンプ、つまり行時間は datetime または duration の値で表されます。datetimeduration は、それぞれ時間または経過時間における時点を表す推奨データ型です。

関数 table2timetable を使用して bikeTbl を timetable に変換します。readtable は table を返すため、変換関数を使用しなければなりません。table2timetable は table 内の最初の datetime 変数または duration 変数を timetable の行時間に変換します。行時間は行をラベル付けするメタデータです。ただし、timetable を表示すると、行時間と timetable の変数は同じように表示されます。table の変数は 5 つありますが、timetable の変数は 4 つである点に注意してください。

bikeData = table2timetable(bikeTbl);
head(bikeData)
         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             1412425  timetable              
  bikeTbl       9387x5             1487735  table                  

時間とデータへのアクセス

変数 Day を categorical に変換します。categorical データ型は、曜日名など、離散値の有限集合で構成されるデータ向けに設計されています。曜日順に表示されるようカテゴリをリストします。ドット添字を使用して、名前で変数にアクセスします。

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

timetable では、時間はデータ変数とは別に処理されます。timetable の Properties にアクセスして、行時間が timetable の最初の次元であり、変数は 2 番目の次元であることを確認します。DimensionNames プロパティは 2 つの次元の名前を示し、VariableNames プロパティは 2 番目の次元の変数の名前を示します。

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
                  Events: []
        CustomProperties: No custom properties are set.
      Use addprop and rmprop to modify CustomProperties.

既定で、table2timetable は table を timetable に変換したときに最初の次元名として Timestamp を代入しています。これが元の table の変数名だったためです。次元の名前、およびその他の timetable メタデータは 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
                  Events: []
        CustomProperties: No custom properties are set.
      Use addprop and rmprop to modify CustomProperties.

timetable の最初の 8 行を表示します。

head(bikeData)
           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   

最も新しい行時間から最も古い行時間までの経過日数を確認します。変数を一度に 1 つずつ参照する場合、変数にはドット表記でアクセスできます。

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

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

特定の日付の一般的な自転車数を調べるには、自転車の合計数の平均と、西および東へ走行する台数を計算します。

中かっこを使用して bikeData の内容にインデックスを付け、数値データを行列として返します。最初の 8 行を表示します。標準の table の添字を使用して複数の変数にアクセスします。

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 は、table または timetable に手動でインデックスを付けて変数を選択するよりも便利です。平均を計算し、NaN 値を省きます。

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

   49.8860   24.2002   25.6857

日付および時間によるデータの選択

休日に自転車に乗る人の数を確認するために、7 月 4 日の休日のデータを調べます。2015 年 7 月 4 日の行時間で timetable にインデックスを付けます。行時間でインデックスを付ける場合、時間が正確に一致しなければなりません。時間インデックスを datetime または duration の値、あるいは日付と時刻に変換できる文字ベクトルとして指定できます。複数の時間を 1 つの配列として指定できます。

特定の日付と時刻を使用して bikeData にインデックスを付けて、2015 年 7 月 4 日のデータを抽出します。日付のみを指定すると、時刻は午前 0 時 (00:00:00) とみなされます。

bikeData('2015-07-04',:)
ans=1×4 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×4 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    

この手法を使用して 1 日全体を抽出するのは手間のかかる作業です。特定の時刻にインデックスを付けず、時間の範囲を指定することもできます。時間範囲の添字をヘルパーとして作成するには、関数 timerange を使用します。

2015 年 7 月 4 日全日を時間範囲として使用して timetable に対する添字を作成します。開始時間を 7 月 4 日の午前 0 時、終了時間を 7 月 5 日の午前 0 時に指定します。既定では、timerange は開始時間から終了時間まで (終了時間は含まない) のすべての時間をカバーします。1 日全体の自転車数をプロットします。

tr = timerange('2015-07-04','2015-07-05');
jul4 = bikeData(tr,'Total');
head(jul4)
           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')

プロットから、交通量は 1 日を通して通常より多く、午後にかけて横ばい状態になることがわかります。多くの企業が休みであるため、プロットは通常の通勤時間の交通量は示していません。夕方に急増しているのは、暗くなってから行われる花火大会に起因すると思われます。これらのトレンドをさらに細かく調べるには、データを通常の日と比較しなければなりません。

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 を使用した時間とデータの前処理

タイムスタンプ付きデータ セットは煩雑になることがよくあり、異常やエラーが含まれる可能性もあります。timetable は異常やエラーを解決するのに適しています。

timetable では、行時間を特定の順序にする必要はありません。行時間で並べ替えられてない行を含めることができます。timetable には同じ行時間をもつ複数の行を含めることもできますが、行に異なるデータ値が含まれていてもかまいません。行時間は、並べ替えられて一意であっても、サイズの異なるタイム ステップにより変化することがあります。timetable には欠損行時間を示す NaT または NaN の値を含めることもできます。

timetable データ型には、欠損している時間、重複している時間、等間隔ではない時間を解決するさまざまな方法があります。また、データをリサンプリングまたは集計して "規則的な" timetable を作成することもできます。規則的な timetable には並べ替えられた一意の行時間が含まれ、それらの行時間の間には、均一、つまり等間隔のタイム ステップがあります。

  • 欠損している行時間を見つけるには、ismissing を使用します。

  • 欠損している時間およびデータを削除するには、rmmissing を使用します。

  • timetable をその行時間で並べ替えるには、sortrows を使用します。

  • 一意の並べ替えられた行時間をもつ timetable を作成するには、uniqueretime を使用します。

  • 規則的な timetable を作成するには、等間隔の時間ベクトルを指定し、retime を使用します。

時間順での並べ替え

timetable が並べ替えられているかどうかを判定します。行時間が昇順にリストされる場合、timetable は並べ替えられています。

issorted(bikeData)
ans = logical
   0

timetable を並べ替えます。関数 sortrows は行を行時間で最も古い時間から最も新しい時間に並べ替えます。重複している行時間をもつ行がある場合、sortrows はすべての重複を出力にコピーします。

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

欠損している時間とデータの特定および削除

timetable では、その変数またはその行時間に欠損データ インジケーターを含めることができます。たとえば、欠損している数値を NaN、欠損している datetime 値を NaT として示すことができます。欠損値を代入、検索、削除および埋めるには、それぞれ関数 standardizeMissingismissingrmmissing および fillmissing を使用できます。

timetable 変数で欠損値を検索およびカウントします。この例では、欠損値はデータが収集されなかった状況を示します。

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

     1     3     3     3

ismissing からの出力は、table と同じサイズの logical 行列で、欠損データ値を true と識別しています。欠損データ インジケーターを示す行を表示します。

idx = any(missData,2);
bikeData(idx,:)
ans=3×4 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) は時間ではなく timetable 変数内の欠損データのみを検出します。欠損している行時間を検出するには、行時間で ismissing を呼び出します。

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

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

この例では、欠損時間または欠損データ値は測定エラーを示しており、除外することができます。rmmissing を使用して、欠損データ値と欠損行時間を含む table の行を削除します。

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
   2015-08-21 00:00:00
   2015-11-19 23:00:00
   2015-11-19 23:00:00

3 つの時間が繰り返され、2015 年 11 月 19 日は 2 回繰り返されています。繰り返されている時間に関連するデータを確認します。

bikeData(dup(1),:)
ans=2×4 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×4 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    

1 つ目は時間が重複していますがデータは重複していません。その他は完全に重複しています。timetable 行では、複数行において同一の行時間と同一のデータ値が含まれている場合、重複とみなされます。unique を使用して timetable 内の重複行を削除できます。関数 unique は、行時間による行の並べ替えも行います。

bikeData = unique(bikeData); 

時間は重複しているもののデータが重複していない行については、何らかの解釈が必要です。これらの時間の周辺のデータを調べます。

d = dup(1) + hours(-2:2);
bikeData(d,:)
ans=5×4 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 は数値データには適していますが、timetable の categorical データには適していません。vartype を使用して、数値変数を特定します。

vt = vartype('numeric');
t = unique(bikeData.Time);
numData = retime(bikeData(:,vt),t,'sum');
head(numData)
           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 データは集計できませんが、1 つのラベルが 1 日全体を表すため、各日付で最初の値をとります。同じ時間ベクトルで retime 演算を実行し、timetable を連結することができます。

vc = vartype('categorical');
catData = retime(bikeData(:,vc),t,'firstvalue');
bikeData = [catData,numData];
bikeData(d,:)
ans=4×4 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 時間の等間隔タイム ステップがあるようです。これが timetable のすべての行時間にあてはまるかどうかを確認するには、関数 isregular を使用します。isregular は、重複または欠損している時間 (NaT または NaN) のない、並べ替えられた等間隔の時間 (単調増加) の場合、true を返します。

isregular(bikeData)
ans = logical
   0

0 (false) の出力は、timetable の時間が等間隔でないことを示します。時間間隔をさらに詳しく調べます。

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

timetable を一定の時間間隔にするには、retime または synchronize を使用して、目的の時間間隔を指定します。

1 日の自転車交通量の確認

関数 retime を使用して 1 日あたりの台数を確認します。sum メソッドを使用して各日付のカウント データを累積します。これは数値データには適していますが、timetable の categorical データには適していません。vartype を使用して変数をデータ型で識別します。

dayCountNum = retime(bikeData(:,vt),'daily','sum');
head(dayCountNum)
           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   

上記のとおり、retime 演算を再度実行し、適切なメソッドを使用して categorical データを表し、timetable を連結できます。

dayCountCat = retime(bikeData(:,vc),'daily','firstvalue');
dayCount = [dayCountCat,dayCountNum];
head(dayCount)
           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   

自転車数と気象データの同期

自転車数と気象データを比較して、サイクリング行動に対する気象の影響を調べます。暴風雨など、マサチューセッツ州ボストンの過去の気象データが含まれる気象の timetable を読み込みます。

load BostonWeatherData
head(weatherData)
       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        

timetable の時間と変数を集計するには、関数 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 のリファレンス ページに記載されているいずれかの方法を使って timetable データをリサンプリングまたは集計できます。

両方の timetable のデータを同期して、共通時間ベクトル (個々の日次時間ベクトルの共通部分から作成) にします。

data = synchronize(dayCount,weatherData,'intersection');
head(data)
           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 を使用して 1 日あたりの合計数を確認します。関数 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)
    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)
    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     

曜日が変数になるように timetable を調整するには、関数 unstack を使用します。

hrAndDayWeek = unstack(byHrDay(:,{'HrOfDay','Day','sum_Total'}),'sum_Total','Day'); 
head(hrAndDayWeek)
    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')

月曜日から金曜日の平日には、交通量はラッシュ アワーにピークとなり、夕方に減少するという同様のトレンドがみられます。金曜日は交通量が少なくなっていますが、全体的なトレンドは他の平日と似ています。土曜日と日曜日のトレンドは似ており、ラッシュ アワーのピークがなく、午後の交通量が増しています。月曜日から金曜日は夜のトレンドも同様ですが、金曜日は交通量が減少します。

ラッシュ アワー時の交通量の解析

1 日全体のトレンドを調べるためには、ラッシュ アワーの時間でデータを分割します。関数 discretize を使用して異なる時間帯または時間単位を使用できます。たとえば、データを AMAMRushDayPMRushPM のグループに分けます。次に、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 倍になっています。このエリアの早朝の交通量は非常に少ないのですが、夕方と夜の交通量はまだ多く、朝と夕方のラッシュ アワーを除く日中の交通量に匹敵します。

参考

| | | | | | | | | |

関連するトピック