计算相关矩阵子集的最快方法

时间:2016-07-04 05:26:27

标签: python numpy pandas

我偏向于使用pandas内置corr方法来处理数据帧。但是,我试图计算具有45,000列的数据帧的相关矩阵。然后重复这250次。计算正在粉碎我的公羊(16 GB,mac book pro)。我抓住了所得相关矩阵的列的统计数据。所以我需要一列与其他列的相关性来计算这些统计数据。我的解决方案是计算列子集与每个其他列的相关性,但我需要一种有效的方法来实现这一点。

考虑:

import pandas as pd
import numpy as np

np.random.seed([3,1415])

df = pd.DataFrame(np.random.rand(6, 4), columns=list('ABCD'))
df

enter image description here

我想计算仅['A', 'B']

的相关性
corrs = df.corr()[['A', 'B']]
corrs

enter image description here

我会通过计算平均值或其他一些数据来完成它。

我无法使用我用来创建示例的代码,因为当我扩展时,我没有内存。执行计算时,它必须使用与所选列数成比例的内存量来计算相对于其他所有内容的相关性。

我正在寻找规模最大的高性能解决方案。我有一个解决方案,但我正在寻找其他想法,以确保我获得最佳。提供的任何答案都会返回正确的答案,如演示中所示,并且满足记忆约束将被我支持(并且我鼓励彼此之间相互竞争)。

以下是我的代码:

def corr(df, k=0, l=10):
    d = df.values - df.values.mean(0)
    d_ = d[:, k:l]
    s = d.std(0, keepdims=True)
    return pd.DataFrame(d.T.dot(d[:, k:l]) / s.T.dot(s[:, k:l]) / d.shape[0],
                        df.columns, df.columns[k:l])   

2 个答案:

答案 0 :(得分:3)

使用点积来计算相关性(如您的示例中所示)似乎是一种很好的方法。我将描述两个改进,然后代码实现它们。

改进1:拉出意味着点积

我们可以将这些方法从点积中拉出来,以避免从每个值中减去它们(类似于你从点积中拉出标准偏差的方式,我们也会这样做。)

x, y成为具有n元素的向量。让a, b成为标量。设<x,y>表示x和y之间的点积。

xy之间的相关性可以使用点积

表示
<(x-mean(x))/std(x), (y-mean(y))/std(y)> / n

要从点积中拉出标准偏差,我们可以使用以下标识(如上所述):

<ax, by> = a*b*<x, y>

为了从平面产品中取出手段,我们可以获得另一个身份:

<x+a, y+b> = <x,y> + a*sum(y) + b*sum(x) + a*b*n

a = -mean(x), b = -mean(y)的情况下,这简化为:

<x-mean(x), y-mean(y)> = <x, y> - sum(x)*sum(y)/n

使用这些身份,xy之间的相关性相当于:

(<x, y> - sum(x)*sum(y)/n) / (std(x)*std(y)*n)

在下面的函数中,这将使用矩阵乘法和外部乘积来表示,以同时处理多个变量(如您的示例所示)。

改进2:预计算总和和标准差

我们可以预先计算总和和标准差,以避免每次调用函数时为所有列重新计算它们。

代码

将这两项改进放在一起,我们有以下内容(我不会说熊猫,所以它是numpy):

def corr_cols(x, xsum, xstd, lo, hi):
    n = x.shape[0]

    return (
        (np.dot(x.T, x[:, lo:hi]) - np.outer(xsum, xsum[lo:hi])/n)
        / (np.outer(xstd, xstd[lo:hi])*n)
    )

# fake data w/ 10 points, 5 dimensions
x = np.random.rand(10, 5)

# precompute sums and standard deviations along each dimension
xsum = np.sum(x, 0)
xstd = np.std(x, 0)

# calculate columns of correlation matrix for dimensions 1 thru 3
r = corr_cols(x, xsum, xstd, 1, 4)

更好的代码

预先计算和存储总和和标准差可以隐藏在闭包内,以提供更好的界面并使主代码更清晰。从功能上讲,这些操作与前面的代码相同。

def col_correlator(x):
    n = x.shape[0]
    xsum = np.sum(x, 0)
    xstd = np.std(x, 0)

    return lambda lo, hi: (
        (np.dot(x.T, x[:, lo:hi]) - np.outer(xsum, xsum[lo:hi])/n)
        / (np.outer(xstd, xstd[lo:hi])*n)
    )

# construct function to compute columns of correlation matrix
cc = col_correlator(x)

# compute columns of correlation matrix for dimensions 1 thru 3
r = cc(1, 4)

编辑:(piRSquared)

我想把我的编辑放在这篇文章中,以进一步鼓励对这个答案的支持。

这是我使用此建议实现的代码。这个解决方案在大熊猫和numpy之间来回转换。

def corr_closure(df):
    d = df.values
    sums = d.sum(0, keepdims=True)
    stds = d.std(0, keepdims=True)
    n = d.shape[0]

    def corr(k=0, l=10):
        d2 = d.T.dot(d[:, k:l])
        sums2 = sums.T.dot(sums[:, k:l])
        stds2 = stds.T.dot(stds[:, k:l])

        return pd.DataFrame((d2 - sums2 / n) / stds2 / n,
                            df.columns, df.columns[k:l])

    return corr

用例:

corr = corr_closure(df)

corr(0, 2)

enter image description here

答案 1 :(得分:1)

信贷转到@ user20160,@ piRsquared。

我有一个非常相似的问题。我试图计算的只是矩阵的四分之一:某些列组与另一列之间的相关性。

我对2组向量修改了一点代码,它采用了4个参数:

def col_correlator(x):
n = x.shape[0]
xsum = np.sum(x, 0)
xstd = np.std(x, 0)

return lambda lo_c, hi_c, lo_r, hi_r: (
    (np.dot(x[:, lo_r:hi_r].T, x[:, lo_c:hi_c]) - np.outer(xsum[lo_r:hi_r], xsum[lo_c:hi_c]) / n)
    / (np.outer(xstd[lo_r:hi_r], xstd[lo_c:hi_c]) * n)
)

# construct function to compute columns of correlation matrix
cc = col_correlator(x)

# compute columns of correlation matrix for dimensions 1 thru 3
r = cc(n, m,0,n)