【问题标题】:Python generate rolling window to calculate correlationPython生成滚动窗口来计算相关性
【发布时间】:2018-03-27 04:58:50
【问题描述】:

我有一个大熊猫数据框(97165 行和 2 列),我想为每 100 行计算并保存这些列之间的相关性我想要这样的东西:

第一个相关 --> 从 0 到 100 的行 --> corr = 0.265

第二个相关 --> 从 1 到 101 的行 --> corr = 0.279

第三次相关 --> 2 到 102 的行 --> corr = 0.287

每个值都必须存储并显示在绘图中,因此我必须将所有这些值保存在列表或类似的东西中。

我一直在阅读与滚动窗口相关的 pandas 文档 pandas rolling window 但我什么也没做。 我试图生成一个简单的循环来获得一些结果,但我遇到了内存问题,我尝试过的代码是:

lcl = 100
a = []
for i in range(len(tabla)):

    x = tabla.iloc[i:lcl, [0]] 
    y = tabla.iloc[i:lcl, [1]]
    z = x['2015_Avion'].corr(y['2015_Hotel'])
    a.append(z) 
    lcl += 1

有什么建议吗?

【问题讨论】:

  • 输入数据框中有什么?生成具有最少代表性数据的样本?另外,您在哪一步遇到内存错误?
  • 排序的整数值

标签: python pandas numpy


【解决方案1】:

我们可以通过处理数组数据来优化内存和性能。

方法#1

首先,让我们有一个数组解决方案来获取两个1D 数组之间对应元素的相关系数。这基本上是受到this post 的启发,看起来像这样 -

def corrcoeff_1d(A,B):
    # Rowwise mean of input arrays & subtract from input arrays themeselves
    A_mA = A - A.mean(-1,keepdims=1)
    B_mB = B - B.mean(-1,keepdims=1)

    # Sum of squares
    ssA = np.einsum('i,i->',A_mA, A_mA)
    ssB = np.einsum('i,i->',B_mB, B_mB)

    # Finally get corr coeff
    return np.einsum('i,i->',A_mA,B_mB)/np.sqrt(ssA*ssB)

现在,要使用它,在数组数据上使用相同的循环 -

lcl = 100
ar = tabla.values
N = len(ar)
out = np.zeros(N)
for i in range(N):
    out[i] = corrcoeff_1d(ar[i:i+lcl,0], ar[i:i+lcl,1])

我们可以通过预先计算滚动平均值来进一步优化性能,这些平均值用于计算 corrcoeff_1dconvolution 中的 A_mA,但首先让我们消除内存错误。

方法 #2

这是一种几乎矢量化的方法,因为我们将对大多数迭代进行矢量化,除了最后没有适当窗口长度的剩余切片。循环计数将从97165 减少到lcl-1,即仅99

lcl = 100
ar = tabla.values
N = len(ar)
out = np.zeros(N)

col0_win = strided_app(ar[:,0],lcl,S=1)
col1_win = strided_app(ar[:,1],lcl,S=1)
vectorized_out = corr2_coeff_rowwise(col0_win, col1_win)
M = len(vectorized_out)
out[:M] = vectorized_out

for i in range(M,N):
    out[i] = corrcoeff_1d(ar[i:i+lcl,0], ar[i:i+lcl,1])

辅助函数 -

# https://stackoverflow.com/a/40085052/ @ Divakar
def strided_app(a, L, S ):  # Window len = L, Stride len/stepsize = S
    nrows = ((a.size-L)//S)+1
    n = a.strides[0]
    return np.lib.stride_tricks.as_strided(a, shape=(nrows,L), strides=(S*n,n))

# https://stackoverflow.com/a/41703623/ @Divakar
def corr2_coeff_rowwise(A,B):
    # Rowwise mean of input arrays & subtract from input arrays themeselves
    A_mA = A - A.mean(-1,keepdims=1)
    B_mB = B - B.mean(-1,keepdims=1)

    # Sum of squares across rows
    ssA = np.einsum('ij,ij->i',A_mA, A_mA)
    ssB = np.einsum('ij,ij->i',B_mB, B_mB)

    # Finally get corr coeff
    return np.einsum('ij,ij->i',A_mA,B_mB)/np.sqrt(ssA*ssB)

NaN 填充数据的相关性

接下来列出了基于 Pandas 的相关计算的 NumPy 解决方案,用于计算一维数组和逐行相关值之间的相关性。

1) 两个一维数组之间的标量相关值 -

def nancorrcoeff_1d(A,B):
    # Get combined mask
    comb_mask = ~(np.isnan(A) & ~np.isnan(B))
    count = comb_mask.sum()

    # Rowwise mean of input arrays & subtract from input arrays themeselves
    A_mA = A - np.nansum(A * comb_mask,-1,keepdims=1)/count
    B_mB = B - np.nansum(B * comb_mask,-1,keepdims=1)/count

    # Replace NaNs with zeros, so that later summations could be computed    
    A_mA[~comb_mask] = 0
    B_mB[~comb_mask] = 0

    ssA = np.inner(A_mA,A_mA)
    ssB = np.inner(B_mB,B_mB)

    # Finally get corr coeff
    return np.inner(A_mA,B_mB)/np.sqrt(ssA*ssB)

2) 两个2D 数组(m,n) 之间的逐行相关性给我们一个1D 形状(m,) 的数组-

def nancorrcoeff_rowwise(A,B):
    # Input : Two 2D arrays of same shapes (mxn). Output : One 1D array  (m,)
    # Get combined mask
    comb_mask = ~(np.isnan(A) & ~np.isnan(B))
    count = comb_mask.sum(axis=-1,keepdims=1)

    # Rowwise mean of input arrays & subtract from input arrays themeselves
    A_mA = A - np.nansum(A * comb_mask,-1,keepdims=1)/count
    B_mB = B - np.nansum(B * comb_mask,-1,keepdims=1)/count

    # Replace NaNs with zeros, so that later summations could be computed    
    A_mA[~comb_mask] = 0
    B_mB[~comb_mask] = 0

    # Sum of squares across rows
    ssA = np.einsum('ij,ij->i',A_mA, A_mA)
    ssB = np.einsum('ij,ij->i',B_mB, B_mB)

    # Finally get corr coeff
    return np.einsum('ij,ij->i',A_mA,B_mB)/np.sqrt(ssA*ssB)

【讨论】:

  • 感谢您的帮助,这很好,但我遇到了与其他方法相同的问题,前 77 个值很好,但之后所有值都是 0 或 nan。我知道为什么,但所有解决方案都会发生这种情况
  • @WinterZ 正如我之前在评论中所说的那样 - Produce a sample with minimal representative data?
  • 在我的所有方法中都有一个 bz2 格式的样本,其中包含 10k 行 ufile.io/xpneh,就像你的方法一样,因为我得到了 nan 值...
  • @WinterZ 那么,it seems you were able to fix it?这两种解决方案现在都有效吗?
  • 问题是我对数据进行了排序,所以我有很多经常出现的值。您的解决方案非常好,但在我的情况下,我得到了 nan 值,因为这行代码: A_mA = A - A.mean(-1,keepdims=1) 例如所有填充为 3 的向量使 A_mA 等于 0 并且当此值为 0 时,相关公式不起作用。非常感谢!
【解决方案2】:

你提到尝试rolling。那到底出了什么问题?这对我有用:

my_res = tabla['2015_Avion'].rolling(100).corr(tabla['2015_Hotel'])

my_res 将具有 NaN 值,直到其 100th 值,因此 my_res[99] 应该是行 0 和行 99 两列元素之间的相关性,这将由 @ 返回987654329@ corr 函数仅应用于子集。 my_res[100] 是行 1 和行 100 元素之间的相关性。

【讨论】:

  • 大多数输出​​值是 nan 或 0,在我的表中只有 0 到 10 的整数值..所以我不知道为什么我得到 nan/0 值。
  • 您是从某种 csv 文件中读取的吗?是否有可能某些值具有转义字符或导致问题的非 ascii 字符?我希望它会引发错误,但这取决于 corr() 的工作方式。到目前为止,我无法使用一些随机整数重新创建问题。
  • 我使用read_pickle读取文件,格式为bz2。我正在查看数据集,但没有看到任何奇怪的东西。
  • 我没有在 python 中使用 read_pickle 或 bz2 的经验。在某些值上尝试 print(repr()) 以检查是否出现任何奇怪的东西(print() 可能无法捕获转义字符等) - 比如说在给出 NaN 相关性的窗口中的所有值上。
  • 如果我和 Divakar 的解决方案都给出 0/NaN,我强烈建议您查看数据本身 - 几乎可以肯定问题就在那里。要么自己检查,要么按照 Divakar 的建议发布样本。
猜你喜欢
  • 2019-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-20
  • 2014-01-08
  • 1970-01-01
  • 2014-05-22
  • 1970-01-01
相关资源
最近更新 更多