用pandas进行时间序列相关性分析

9
我有一些颗粒物传感器和带有时间序列的CSV文件,例如:
传感器A:
                     date           value
date                                     
2017-11-30 00:00:00  30/11/17 0.00     49
2017-11-30 00:02:00  30/11/17 0.02     51
2017-11-30 00:03:00  30/11/17 0.03     54
2017-11-30 00:05:00  30/11/17 0.05     57
2017-11-30 00:07:00  30/11/17 0.07     53
2017-11-30 00:08:00  30/11/17 0.08     55
2017-11-30 00:10:00  30/11/17 0.10     55
2017-11-30 00:12:00  30/11/17 0.12     58
2017-11-30 00:13:00  30/11/17 0.13     57
2017-11-30 00:15:00  30/11/17 0.15     58
....
2018-02-06 09:30:00    6/2/18 9.30     33
2018-02-06 09:32:00    6/2/18 9.32     31
2018-02-06 09:33:00    6/2/18 9.33     34
2018-02-06 09:35:00    6/2/18 9.35     32
2018-02-06 09:37:00    6/2/18 9.37     33
2018-02-06 09:38:00    6/2/18 9.38     30

我使用以下代码将日期设置为索引:
df.index = pd.to_datetime(df['date'], format='%d/%m/%y %H.%M')

我想将来自同一传感器和不同传感器的数据在相似时间窗口内进行相关性分析。我希望能知道某些时段/日子内是否存在相同的增长/减少行为。在设置“日期索引”后,我可以获取“从传感器A每天上午9点到10点的所有PM值”。
df.between_time('9:00','10:00')

问题1:如何检查来自同一传感器但不同日期的相关性:我从两天中的9/10am过滤了数据,并将其存储在两个DataFrame中,但它们并不总是在完全相同的时间被记录。我可能会遇到这样的情况:
01-01-2018 (df01 - I removed data column)
2018-01-01 09:05:00     11
2018-01-01 09:07:00     11
2018-01-01 09:09:00     10
....


02-01-2018 (df02)
2018-02-01 09:05:00     67
2018-02-01 09:07:00     68
2018-02-01 09:08:00     67
....

我应该重命名数据列吗?我实际上关心的是,从2018年1月1日开始的第三个值将与第二个窗口中的第三个值相关联。
df01.corr(df02)

返回
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all()

问题2:不同传感器之间的相关性。在这种情况下,我有两个带有来自两个传感器的PM值的CVS文件。与问题1一样,我想要将它们的相同时间窗口进行相关性分析。 即使在这种情况下,我也预计数据之间会存在一些“偶然滞后”,但是每分钟之间的误差都可以接受,我只想检查“正确位置”的值。例如:
Sensor A:
                         date           value
    date                                     
    2017-11-30 00:00:00  30/11/17 0.00     49
    2017-11-30 00:02:00  30/11/17 0.02     51
    2017-11-30 00:03:00  30/11/17 0.03     54
    2017-11-30 00:05:00  30/11/17 0.05     57

Sensor B:
                         date           value
    date                                     
    2017-11-30 00:00:00  30/11/17 0.00     1
    2017-11-30 00:02:00  30/11/17 0.02     40
    2017-11-30 00:04:00  30/11/17 0.03     11
    2017-11-30 00:05:00  30/11/17 0.05     57

AxB
                         date           valueA    valueB
    date                                     
    2017-11-30 00:00:00  30/11/17 0.00     49       1
    2017-11-30 00:02:00  30/11/17 0.02     51       40
    2017-11-30 00:03:00  30/11/17 0.03     54       11
    2017-11-30 00:05:00  30/11/17 0.05     57       57

预先感谢你。
1个回答

13

我会试着一起回答你的问题。这似乎是使用pd.merge_asof()进行合并的工作,它可以在最接近匹配的键上进行合并,而不仅仅是在完全匹配的键上进行合并。

示例数据

df1
date            value
30/11/17 0.00   51
30/11/17 0.02   53
30/11/17 0.05   65
30/11/17 0.08   58

df2
date            value
30/11/17 0.01   61
30/11/17 0.02   63
30/11/17 0.04   65
30/11/17 0.07   68

预处理

df1.date = pd.to_datetime(df1.date, format='%d/%m/%y %H.%M')
df2.date = pd.to_datetime(df2.date, format='%d/%m/%y %H.%M')
df1.set_index('date', inplace=True)
df2.set_index('date', inplace=True)

df1
                     value
date
2017-11-30 00:00:00     51
2017-11-30 00:02:00     53
2017-11-30 00:05:00     65
2017-11-30 00:08:00     58

df2
                     value
date
2017-11-30 00:01:00     61
2017-11-30 00:02:00     63
2017-11-30 00:04:00     65
2017-11-30 00:07:00     68

在最接近的索引匹配上合并数据框

merged = pd.merge_asof(df1, df2, left_index=True, right_index=True, direction='nearest')
merged
                         value_x  value_y
date
2017-11-30 00:00:00       51       61
2017-11-30 00:02:00       53       63
2017-11-30 00:05:00       65       65
2017-11-30 00:08:00       58       68

相关性

请注意,df.corr()不接受数据作为参数,因此df1.corr(df2)无法使用。 corr方法计算您在其上调用的DataFrame中列之间的成对相关性(文档)。

merged.corr()
          value_x   value_y
value_x  1.000000  0.612873
value_y  0.612873  1.000000

注意事项

pd.merge_asof 的上述用法会保留 df1 的索引;df1 中的每一行都会获得在 df2 中最接近它的匹配行,且是带有替换的。因此,如果 df2 的行数少于 df1,则 merge_asof 的结果将包含来自 df2 的重复值。而结果将与 df1 具有相同的行数。

你提到你只关心按相对位置比较行,例如,比较 df1 的第三个值与 df2 的第三个值。你可以简单地忽略时间索引,一旦使用它获得感兴趣的时间段,并使用df.values访问底层的numpy数组,而不是使用merge_asof

# Get a 2D array of shape (4, 1)
df1.values
array([[51],
       [53],
       [65],
       [58]])

# Get a 1D array of shape (4,)
df1.values.flatten()
array([51, 53, 65, 58])

# numpy correlation matrix
pd.np.corrcoef(df1.values.flatten(), df2.values.flatten())
array([[1.        , 0.61287265],
       [0.61287265, 1.        ]])

你好Peter!使用merge_asof()后,我发现value_x和value_y的值相同,这可能是因为value_x是从day1获取的,而value_y是从day2获取的,所以最近的值总是来自day2中的第一个值。我应该从datetime索引中删除日期吗?如何操作?你在Notes中提到的第二种方法看起来很有前途。如果两个数组的长度不同(+-1),我能否将它们相关联?我得到了'ValueError: all the input array dimensions except for the concatenation axis must match exactly'的错误提示。我想比较相等的数组,避免多余的值。我将对数千个数组进行相关性分析,如何自动管理它们?谢谢 ;) - Gorgo
1
嘿 @Davide,不幸的是 Pearson 和 Spearman 相关性要求输入具有相同的长度。merge_asof(df1, df2) 应该是最简洁的方法,可以将 df1 中的所有行与来自 df2 的最接近的匹配合并。如果您选择 numpy 数组路线,您可能需要手动修剪较长的数组以匹配较短数组的长度,类似于:a2 = a[:b.shape[0]]; b2 = b[:a.shape[0]](这将截断 a2b2 以匹配两者中较短的长度)。 - Peter Leimbigler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接