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
の値で表されます。datetime
と duration
は、それぞれ時間または経過時間における時点を表す推奨データ型です。
関数 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 1562713 timetable bikeTbl 9387x5 1638055 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'} VariableTypes: ["categorical" "double" "double" "double"] 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
を使って変更できます。
次元の名前を Time
と Data
に変更します。
bikeData.Properties.DimensionNames = {'Time' 'Data'}; bikeData.Properties
ans = TimetableProperties with properties: Description: '' UserData: [] DimensionNames: {'Time' 'Data'} VariableNames: {'Day' 'Total' 'Westbound' 'Eastbound'} VariableTypes: ["categorical" "double" "double" "double"] 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 を作成するには、
unique
とretime
を使用します。規則的な timetable を作成するには、等間隔の時間ベクトルを指定し、
retime
を使用します。
時間順での並べ替え
timetable が並べ替えられているかどうかを判定します。行時間が昇順にリストされる場合、timetable は並べ替えられています。
issorted(bikeData)
ans = logical
0
timetable を並べ替えます。関数 sortrows
は行を行時間で最も古い時間から最も新しい時間に並べ替えます。重複している行時間をもつ行がある場合、sortrows
はすべての重複を出力にコピーします。
bikeData = sortrows(bikeData); issorted(bikeData)
ans = logical
1
欠損している時間とデータの特定および削除
timetable では、その変数またはその行時間に欠損データ インジケーターを含めることができます。たとえば、欠損している数値を NaN
、欠損している datetime 値を NaT
として示すことができます。欠損値を代入、検索、削除および埋めるには、それぞれ関数 standardizeMissing
、ismissing
、rmmissing
および 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)
weatherData: 383x3 timetable Row Times: Time: datetime Variables: TemperatureF: double Humidity: double Events: categorical (7 categories) Statistics for applicable variables and row times: NumMissing Min Median Max Mean Std Time 0 01-Jul-2015 08-Jan-2016 17-Jul-2016 08-Jan-2016 2656:57:49 TemperatureF 0 2 55 85 55.2950 16.3505 Humidity 0 29 64 97 65.2193 14.0507 Events 0
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
を使用して異なる時間帯または時間単位を使用できます。たとえば、データを 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 倍になっています。このエリアの早朝の交通量は非常に少ないのですが、夕方と夜の交通量はまだ多く、朝と夕方のラッシュ アワーを除く日中の交通量に匹敵します。
参考
timetable
| table2timetable
| head
| summary
| varfun
| timerange
| sortrows
| rmmissing
| retime
| datetime
| unstack