【问题标题】:Calculate weekly (or monthly) average of time series data in MATLAB在 MATLAB 中计算时间序列数据的每周(或每月)平均值
【发布时间】:2016-06-29 07:52:20
【问题描述】:

假设我们在 MATLAB R2015b 中有DT_vec

DT_vec = 
2008    7   21  0   0   0
2008    7   22  0   0   0
2008    7   23  0   0   0
2008    7   29  0   0   0
2008    8   4   0   0   0
2008    8   12  0   0   0
2008    9   14  0   0   0
2008    9   15  0   0   0
2008    9   16  0   0   0
2008    9   17  0   0   0
2008    9   20  0   0   0
2008    9   21  0   0   0

数据存储在My_data:

32
43
12
43
2
12
54
32
34
5
32
12

我想计算这个时间序列的每周(或每月)平均值 (My_data)。我该怎么做?

【问题讨论】:

  • 哪些数据的平均值?根据我的理解,左前 3 列代表日期,但右前 3 列代表什么 - 你想计算这些值的平均值吗?
  • @drorco 感谢您的评论,我修改了问题。右前 3 列代表时间(小时等),在上述情况下我们没有此数据。我想计算My_data 值的平均值。
  • 有关如何有效执行此操作的问题,请参阅this question。

标签: matlab time-series


【解决方案1】:

每月更简单,您可以使用DT_vec 中的第一列和第二列来创建accumarray 所需的subs 数组

[~,~,subs] = unique(DT_vec(:,1:2), 'rows')
MonthlyMeans = accumarray(subs, My_data, [], @mean)

你可以每周做同样的事情,但你必须弄清楚如何获得subs。它应该不会更复杂,但使用日期序列号(即datenum(DT_vec))可能更容易,然后执行subs = floor((datenum(DT_vec) + offset)/7) 之类的操作,其中offset 是您使用的06 之间的整数让数字从周日(或周一)开始。然后您可能想要减去以使第一周从1 开始,所以subs = subs - min(subs) + 1

编辑:这是如何工作的?offset 是什么?

这里的想法是将您的日期表示为serial numbers (by using the datenum function)。来自datenum 的文档:

datenum 函数创建一个数值数组,将每个时间点表示为从 0000 年 1 月 0 日开始的天数。

所以datenum 结果中的每个整数代表一整天。在您的示例DT_vec(即datenum(DT_vec))上运行它,我们得到:

DT_num =

     733610
     733611
     733612
     733618
     733624
     733632
     733665
     733666
     733667
     733668
     733671
     733672

您的前两个日期是连续的,因此是DT_num(2) - DT_num(1) == 1。那么我们如何找到星期呢?我们需要将这些序列日期数字分组为 7 个一组。为此,我将每个数字除以 7,然后使用 floor 删除小数点。为了用较小的数字来证明这一点,当我们将0:14 除以7 时会发生什么?我们得到

     0
0.1429
0.2857
0.4286
0.5714
0.7143
0.8571
1.0000
1.1429
1.2857
1.4286
1.5714
1.7143
1.8571
2.0000

如果我们使用 floor 去掉小数,我们会得到:

 0
 0
 0
 0
 0
 0
 0
 1
 1
 1
 1
 1
 1
 1
 2

您的实际数字也会发生同样的情况,它们只是不会从0 开始。那么偏移量有什么用呢?好吧,因为除以7 后整数的每一次变化都代表新的一周,我们需要确保我们从周日开始划分周,而不是像周四这样的任意一天。由于 MATLAB 从 0000 年 1 月的第一天开始计数,我们需要知道那是一周中的哪一天,然后使用 offset 使它好像从下一个星期日开始计数。 0000 年 1 月 1 日是哪一天?我们可以使用 MATLAB 的weekday 函数来查找。例如今天是星期几?

weekday(datenum([2016 03 14]))

返回 2 表示星期一。那么0 是哪一天? weekday(0) 返回 6 表示星期五。所以我们需要抵消这个计数器,使它从0开始,因此offset应该等于weekday(1) - 1

为了进一步说明这一点,请考虑过去 14 天:

d = (today-7:today)'

现在

[floor(d/7) weekday(d)]

返回

ans =

  105198           2
  105198           3
  105198           4
  105198           5
  105199           6
  105199           7
  105199           1
  105199           2
  105199           3
  105199           4
  105199           5
  105200           6
  105200           7
  105200           1
  105200           2

当第二列从7 变为1 时,新的一周开始,但您可以看到由floor(d/7) 在第一列中创建的分组与此不对应。事实上它被5(或-2)关闭。这就是我们想要使用offset 的目的。所以如果我们设置offset = weekday(0) - 1 那么

[floor((d+offset)/7) weekday(d)]

给予

  105199           2
  105199           3
  105199           4
  105199           5
  105199           6
  105199           7
  105200           1
  105200           2
  105200           3
  105200           4
  105200           5
  105200           6
  105200           7
  105201           1
  105201           2

正确划分周。

【讨论】:

  • 每周更难...我必须使用weeknum 创建一个新的周数列。
  • @GameOfThrows 我刚刚添加了关于如何使用datenum 的描述。我不知道weeknum,但对我来说,这基本上就像每月一样简单,因为[~,~,subs] = unique([DT_vec(:,1),weeknum(DT_vec(:,2))], 'rows') 虽然每年的第一周和最后一周都会很混乱,所以我会坚持我的datenum 方法
  • 是的,weeknum 只是一个日期解析器,它获取日期向量并为其分配一年中的周数(我认为这就像您对 datenum 所做的一样)
  • @GameOfThrows 不同之处在于我的datenum 代码将为 12 月 31 日和 1 月 1 日分配相同的数字(除非 1 月 1 日是星期日),而 weeknum 应该分配 @ 987654383@ 到 12 月底,1 到 1 月初,因此划分了不应划分的一周
  • 没错,年底重置。你的方法更准确。
猜你喜欢
  • 2016-12-25
  • 2017-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 2021-12-18
  • 2015-08-15
相关资源
最近更新 更多