【问题标题】:Cross-correlation (time-lag-correlation) with pandas?与熊猫的互相关(时滞相关)?
【发布时间】:2016-01-15 06:16:54
【问题描述】:

我有各种时间序列,我想将它们相互关联 - 或者更确切地说,交叉关联 - 以找出相关因子在哪个时间滞后时最大。

我发现 various questions 和答案/链接讨论如何使用 numpy 进行操作,但这意味着我必须将我的数据帧转换为 numpy 数组。而且由于我的时间序列经常涵盖不同的时期,我怕我会陷入混乱。

编辑

我在使用所有 numpy/scipy 方法时遇到的问题是,它们似乎缺乏对我数据的时间序列性质的认识。当我将一个从 1940 年开始的时间序列与从 1970 年开始的时间序列关联起来时,pandas corr 知道这一点,而 np.correlate 只生成一个 1020 个条目(较长系列的长度)数组,其中包含 nan。

关于这个主题的各种 Q 表明应该有一种方法来解决不同长度的问题,但到目前为止,我还没有看到关于如何在特定时间段内使用它的迹象。我只需要以 1 为增量移动 12 个月,以查看一年内最大相关性的时间。

编辑2

一些最小的样本数据:

import pandas as pd
import numpy as np
dfdates1 = pd.date_range('01/01/1980', '01/01/2000', freq = 'MS')
dfdata1 = (np.random.random_integers(-30,30,(len(dfdates1)))/10.0) #My real data is from measurements, but random between -3 and 3 is fitting
df1 = pd.DataFrame(dfdata1, index = dfdates1)
dfdates2 = pd.date_range('03/01/1990', '02/01/2013', freq = 'MS')
dfdata2 = (np.random.random_integers(-30,30,(len(dfdates2)))/10.0)
df2 = pd.DataFrame(dfdata2, index = dfdates2)

由于各种处理步骤,这些 dfs 最终更改为 df,索引从 1940 年到 2015 年。这应该重现:

bigdates = pd.date_range('01/01/1940', '01/01/2015', freq = 'MS')
big1 = pd.DataFrame(index = bigdates)
big2 = pd.DataFrame(index = bigdates)
big1 = pd.concat([big1, df1],axis = 1)
big2 = pd.concat([big2, df2],axis = 1)

这是我与 pandas 关联并移动一个数据集时得到的结果:

In [451]: corr_coeff_0 = big1[0].corr(big2[0])
In [452]: corr_coeff_0
Out[452]: 0.030543266378853299
In [453]: big2_shift = big2.shift(1)
In [454]: corr_coeff_1 = big1[0].corr(big2_shift[0])
In [455]: corr_coeff_1
Out[455]: 0.020788314779320523

并尝试 scipy:

In [456]: scicorr = scipy.signal.correlate(big1,big2,mode="full")
In [457]: scicorr
Out[457]: 
array([[ nan],
       [ nan],
       [ nan],
       ..., 
       [ nan],
       [ nan],
       [ nan]])

根据whos

scicorr               ndarray                       1801x1: 1801 elems, type `float64`, 14408 bytes

但我只想有 12 个条目。 /Edit2

我想出的想法是自己实现一个时滞相关性,如下所示:

corr_coeff_0 = df1['Data'].corr(df2['Data'])
df1_1month = df1.shift(1)
corr_coeff_1 = df1_1month['Data'].corr(df2['Data'])
df1_6month = df1.shift(6)
corr_coeff_6 = df1_6month['Data'].corr(df2['Data'])
...and so on

但这可能很慢,我可能正在尝试在这里重新发明轮子。 编辑 上面的方法似乎有效,我把它放到一个循环中,通过一年中的所有 12 个月,但我仍然更喜欢内置方法。

【问题讨论】:

  • 如果您还没有看到这些,请考虑使用scipy.signal.correlatescipy.signal.correlate2d。我会说转换为 numpy 数组可能是你最好的选择。
  • 我见过这些,但我想避免使用 numpy,因为在这一步之后,我必须转换回数据框,以便进一步计算。我想我会尝试重新发明轮子,然后……
  • 据我所知,这是一个非常常见的工作流程,转换为 numpy 并返回。我认为这样做没有必要犹豫。我建议将您的数组写入磁盘,这样您就不会在代码中重复转换。结帐pd.HDFStoreh5py。如果您想重新发明轮子,那就去做吧。
  • 顺便检查一下pandas apply/ufunc object。不过,您可能已经发现了这一点。您实际上可以将一个 numpy 函数放入 pandas 应用对象中。所以这可以解决问题
  • 不知道series.apply,谢谢,以后可能会派上用场。我在使用所有 numpy/scipy 方法时遇到的问题是它们似乎缺乏对我数据的时间序列性质的认识。当我将一个从 1940 年开始的时间序列与一个从 1970 年开始的时间序列关联起来时,pandas corr 知道这一点,而 np.correlate 只生成一个包含 nan 的 1020 个条目数组。我只需要在一年内看到最大相关性。

标签: python numpy pandas correlation cross-correlation


【解决方案1】:

据我所知,没有一种内置方法可以完全满足您的要求。但是如果您查看 pandas Series 方法 autocorr 的源代码,您会发现您的想法是正确的:

def autocorr(self, lag=1):
    """
    Lag-N autocorrelation

    Parameters
    ----------
    lag : int, default 1
        Number of lags to apply before performing autocorrelation.

    Returns
    -------
    autocorr : float
    """
    return self.corr(self.shift(lag))

所以一个简单的时滞交叉协方差函数将是

def crosscorr(datax, datay, lag=0):
    """ Lag-N cross correlation. 
    Parameters
    ----------
    lag : int, default 0
    datax, datay : pandas.Series objects of equal length

    Returns
    ----------
    crosscorr : float
    """
    return datax.corr(datay.shift(lag))

如果你想查看每个月的互相关,你可以这样做

 xcov_monthly = [crosscorr(datax, datay, lag=i) for i in range(12)]

【讨论】:

  • 谢谢,这很有帮助!完全忘记了内置的自相关本质上是一种时滞相关。我会看看我是否可以使用它来产生一些比列表更有用的输出。
  • 刚刚找到这个——很好的答案!
  • 当我将此解决方案应用于我的熊猫系列时,尽管这两个系列不同,但它给出了 nan
【解决方案2】:

有一个更好的方法:您可以创建一个函数,在调用 corr() 之前先移动您的数据框。

像一个例子一样获取这个数据框:

d = {'prcp': [0.1,0.2,0.3,0.0], 'stp': [0.0,0.1,0.2,0.3]}
df = pd.DataFrame(data=d)

>>> df
   prcp  stp
0   0.1  0.0
1   0.2  0.1
2   0.3  0.2
3   0.0  0.3

您移动其他列的功能(目标除外):

def df_shifted(df, target=None, lag=0):
    if not lag and not target:
        return df       
    new = {}
    for c in df.columns:
        if c == target:
            new[c] = df[target]
        else:
            new[c] = df[c].shift(periods=lag)
    return  pd.DataFrame(data=new)

假设您的目标正在比较 prcp(降水变量)和 stp(大气压力)

如果你现在这样做会是:

>>> df.corr()
      prcp  stp
prcp   1.0 -0.2
stp   -0.2  1.0

但是,如果您将所有其他列移动 1(一个)句点并保持 目标(prcp):

df_new = df_shifted(df, 'prcp', lag=-1)

>>> print df_new
   prcp  stp
0   0.1  0.1
1   0.2  0.2
2   0.3  0.3
3   0.0  NaN

请注意,现在 stp 列在句点上移动了一个位置,所以如果你调用 corr(),将是:

>>> df_new.corr()
      prcp  stp
prcp   1.0  1.0
stp    1.0  1.0

所以,你可以用 lag -1, -2, -n!!

【讨论】:

    【解决方案3】:

    要建立在 Andre 的答案之上 - 如果您只关心与目标的(滞后)相关性,但想要测试各种滞后(例如,查看哪个滞后给出最高相关性),您可以执行以下操作:

    lagged_correlation = pd.DataFrame.from_dict(
        {x: [df[target].corr(df[x].shift(-t)) for t in range(max_lag)] for x in df.columns})
    

    这样,每一行对应一个不同的滞后值,每一列对应一个不同的变量(其中一个是目标本身,给出自相关)。

    【讨论】:

      猜你喜欢
      • 2017-01-13
      • 2016-12-03
      • 1970-01-01
      • 1970-01-01
      • 2015-01-19
      • 2016-10-29
      • 1970-01-01
      • 2012-05-09
      • 2011-09-11
      相关资源
      最近更新 更多