Main Content

使用 timetable 预处理和探索时间戳数据

此示例说明如何使用 timetable 数据容器组织和预处理时间戳数据,从而基于传感器数据分析自行车交通模式。这些数据来自马萨诸塞州剑桥市百老汇大街上的传感器。剑桥市允许公众访问位于 Cambridge Open Data 站点上的完整数据。

以下示例演示如何执行各种数据清洗、整理和预处理任务,例如删除缺失值以及将时间戳数据与不同的时间步同步。此外,还将突出显示数据探索,包括使用 timetable 数据容器进行可视化和分组计算,以便:

  • 探查每日自行车流量

  • 将自行车流量与当地天气状况进行比较

  • 分析一周中的不同天和一天中的不同时间的自行车流量

将自行车流量数据导入时间表

从逗号分隔的文本文件中导入自行车流量数据样本。readtable 函数在表中返回这些数据。使用 head 函数来显示前八行。

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   

这些数据具有时间戳,因此可以使用时间表方便地存储和分析这些数据。时间表与表类似,但包含与数据行关联的时间戳。时间戳(即行时间)由 datetimeduration 值表示。datetimeduration 是建议的数据类型,分别用于表示时间点或已用时间。

使用 table2timetable 函数将 bikeTbl 转换为时间表。由于 readtable 返回的是表,因此必须使用转换函数。table2timetable 可将表中的第一个 datetimeduration 变量转换为时间表的行时间。行时间是用来标记行的元数据。但是,当您显示时间表时,行时间和时间表变量以相似方式显示。请注意,该表有五个变量,而时间表只有四个变量。

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 变量转换为分类类型。分类数据类型设计用于由有限的离散值集组成的数据,例如一周中的星期几的名称。列出类别,以便它们按星期几的顺序显示。使用圆点下标按名称访问变量。

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'}
           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.

默认情况下,在将表转换为时间表时,table2timetableTimestamp 分配为第一个维度名称,因为这是原始表中的变量名称。可以通过 Properties 更改维度的名称和其他时间表元数据。

将维度的名称更改为 TimeData

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.

显示时间表的前八行。

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   

确定最晚行时间与最早行时间之间经过的天数。在一次引用一个变量时,可以通过圆点表示法访问变量。

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

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

要确定某给定天的典型自行车计数,请计算总自行车数的均值、向西行进和向东行进的自行车数。

通过使用花括号对 bikeData 的内容进行索引,将数值数据以矩阵的形式返回。显示前八行。要访问多个变量,须使用标准表下标。

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 日的时间表建立索引。当对行时间建立索引时,必须与时间完全匹配。可以将时间索引指定为 datetimeduration 值,或者指定为可以转换为日期时间的字符向量。可以将多个时间指定为数组。

使用特定的日期时间对 bikeData 进行索引以提取 2015 年 7 月 4 日的数据。如果仅指定日期,则时间假定为午夜,即 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    

如果使用此策略提取一整天的数据,则是非常繁琐的工作。您也可以指定时间范围,而不对特定的时间建立索引。要创建时间范围下标来作为帮助,请使用 timerange 函数。

使用 2015 年 7 月 4 日一整天作为时间范围来对时间表建立下标。指定起始时间为 7 月 4 日午夜,结束时间为 7 月 5 日午夜。默认情况下,timerange 涵盖了从起始时间直至结束时间(但不包含结束时间)的所有时间。绘制这一天内各时间段的自行车计数。

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')

Figure contains an axes object. The axes object with title Bicycle Counts on July 4, 2015, ylabel Bicycle Counts contains an object of type bar.

从绘图中可看出,整天的自行车流量较高,下午的流量比较平稳。由于当天非工作日,许多公司未上班,因此该绘图并未反映典型的上下班时间内的交通情况。峰值出现在夜晚较晚时间可能归因于在天黑后进行的烟花燃放庆祝活动。要更准确地确定这些趋势,应将当天的数据与典型一天中的数据进行比较。

将 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')

Figure contains an axes object. The axes object with title Bicycle Counts in July, ylabel Total Count contains 2 objects of type line. These objects represent Bicycle Count, July 4 Bicycle Count.

该绘图显示的差异可以归因于工作日与周末之间的流量变化。7 月 4 日和 5 日的流量模式与周末的流量模式一致。7 月 5 日是周一,但通常作为假日进行观察。通过进一步的预处理和分析,可更准确地确定这些趋势。

使用 timetable 预处理时间和数据

时间戳数据集通常是杂乱的,可能包含异常情况或错误。时间表非常适合解决异常情况和错误。

时间表的行时间无需采用任何特定顺序。它可以包含未按行时间排序的行。时间表也可以包含多个具有相同行时间的行,即使这些行具有不同的数据值也是如此。即使行时间已排序并且是唯一的,也会因不同大小的时间步而异。时间表甚至可以包含 NaTNaN 值以指示缺失的行时间。

timetable 数据类型提供了很多种不同的方式来解决时间缺失、重复或不均匀时间问题。您也可以对数据重采样或聚合数据以创建一个规则时间表。当时间表为规则时间表时,其行时间已排序并且是唯一的,并且行时间之间具有均匀或等间距的时间步。

  • 要查找缺失的行时间,请使用 ismissing

  • 要删除缺失的时间和数据,请使用 rmmissing

  • 要按行时间对时间表进行排序,请使用 sortrows

  • 要使时间表具有唯一和已排序的行时间,请使用 uniqueretime

  • 要创建规则时间表,请指定一个均匀间隔时间向量并使用 retime

按时间顺序排序

确定该时间表是否已排序。如果时间表的行时间按升序列出,则说明它已进行了排序。

issorted(bikeData)
ans = logical
   0

对时间表排序。sortrows 函数按照行的行时间(从最早时间到最晚时间)对行进行排序。如果存在具有重复行时间的行,则 sortrows 会将所有重复项复制到输出。

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

确定并删除缺失的时间和数据

时间表可以在其变量或行时间中包含数据缺失指示符。例如,可以将缺失的数值指示为 NaN,将缺失的日期时间值指示为 NaT。可以分别使用 standardizeMissingismissingrmmissingfillmissing 函数来分配、查找、删除和填充缺失值。

查找和统计时间表变量中的缺失值。在下面的示例中,缺失值指示未收集任何数据的情况。

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

     1     3     3     3

来自 ismissing 的输出是一个大小与表相同的 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) 仅在时间表变量中查找缺失的数据,而并不查找缺失的时间。要查找缺失的行时间,请对行时间调用 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 删除包含缺失数据值和缺失行时间的表行。

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

     0     0     0     0

sum(ismissing(bikeData.Time))
ans = 
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

三个时间是重复的,并且 2015 年 11 月 19 日重复两次。检查与重复时间关联的数据。

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    

第一项有重复时间,但是没有重复数据,其他项则完全重复。时间表的不同行如果包含相同的行时间与数据值,则被视为重复。可以使用 unique 删除时间表中的重复行。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 函数累加唯一时间对应的数据以计算总和。总和适合于数值数据,但不适合于时间表中的分类数据。使用 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   

不能对分类数据计算总和,但由于一个标签代表一整天,因此取每一天的第一个值。可以使用相同的时间向量再次执行 retime 操作,并将时间表串联到一起。

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    

检查时间间隔的均匀性

数据似乎具有相同的时间步长,即一小时。要确定是否时间表中的所有行时间都是这种情况,请使用 isregular 函数。对于已排序、间隔等间距的时间(单调递增),并且没有重复或缺失的时间(NaTNaN),isregular 函数返回 true

isregular(bikeData)
ans = logical
   0

输出 0false 表示时间表中的时间不是间隔均匀的。更详细地探索时间间隔。

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

要将时间表放到均匀时间间隔中,请使用 retimesynchronize 并指定相关的时间间隔。

确定每天自行车数量

使用 retime 函数确定每天的自行车计数。使用 sum 方法累加每天的计数数据。此操作适合于数值数据,但不适合于时间表中的分类数据。使用 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 操作,以使用合适方法表示分类数据并将时间表串联到一起。

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   

同步自行车计数和天气数据

通过使用天气数据比较自行车计数,来确定天气对骑自行车行为的影响。加载天气数据时间表,其中包括马萨诸塞州波士顿市的历史天气数据,包括风暴活动。

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        

要汇总时间表中的时间和变量,请使用 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 函数参考页上记录的任一方法来重采样或聚合时间表数据。

将两个时间表中的数据同步到一个公共时间向量,即基于两个时间表各自的日时间向量的交集来构造。

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)])

Figure contains an axes object. The axes object with title Bicycle Counts and Temperature Over Time, ylabel Temperature ( degree blank F) contains 2 objects of type line.

绘图显示,交通和天气数据可能遵循相似的趋势。放大绘图。

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

Figure contains an axes object. The axes object with title Bicycle Counts and Temperature Over Time, ylabel Temperature ( degree blank F) contains 2 objects of type line.

趋势是类似的,指示天气越冷,骑自行车的人越少。

按星期几和一天中的时间进行分析

基于不同的时间间隔检查数据,例如星期几和一天中的时间。使用 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')

Figure contains an axes object. The axes object with title Bicycle Count by Day of Week contains 2 objects of type bar. These objects represent Westbound, Eastbound.

条形图指示,交通在工作日更为拥堵。此外,向东行进和向西行进的流量数据存在差异。这可能指示,人们进入和离开城市时,倾向于采用不同的路线。另外一种可能性是一些人在某一天进入城市,在另一天离开城市。

确定一天中的小时并使用 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')

Figure contains an axes object. The axes object with title Mean Bicycle Count by Hour of Day, xlabel Hour of Day, ylabel Bicycle Count contains 2 objects of type bar. These objects represent Westbound, Eastbound.

在上午约 9:00 和下午约 5:00 是流量高峰期。此外,向东行进和向西行进的趋势是明显不同的。通常情况下,向西行进的目标是围绕剑桥区的居住区和大学。向东行进的目标是波士顿。

在一天中的晚些时候,相对于向东方向,向西方向的交通更为拥堵。这可能指示,由于餐馆位于该区域中,这可能是大学学生活动和交通导致。按星期几和一天中小时确定趋势。

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     

若要安排时间表以便将星期几作为变量,可使用 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')

Figure contains an axes object. The axes object with title Bicycle Count by Hour and Day of Week, ylabel Hour contains 7 objects of type surface.

从周一到周五的正常工作日也有类似的趋势,在上下班高峰时段达到峰值,夜间交通逐渐减少。周五的交通拥堵情况较少,尽管这一天的总体趋势与其他工作日类似。周六与周日的情况大同小异,无高峰时段峰值,日间晚些时候交通流量有所增加。从周一到周五深夜时段的趋势类似,周五深夜交通流量较少。

分析高峰时段中的交通

要确定一天中的时间的总体趋势,请按高峰时段时间划分数据。使用 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')

Figure contains an axes object. The axes object with title Mean Bicycle Count During Rush Hours contains an object of type bar.

通常情况下,在此区域中早晚高峰时段的交通量是一天中其他时间的交通量的两倍。在此区域中的清早的交通量很少,但在傍晚和晚间的交通量仍较大,相当于一天中除早晚高峰时段外的交通量。

另请参阅

| | | | | | | | | |

相关主题