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

标签 python numpy pandas

我偏向于对数据帧使用 pandas 内置 corr 方法。但是,我正在尝试计算具有 45,000 列的数据框的相关矩阵。然后重复 250 次。计算正在压垮我的 ram(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])   

最佳答案

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

改进1:拉出点积的手段

我们可以从点积中提取平均值,以避免从每个值中减去它们(类似于您从点积中提取标准差的方式,我们也会这样做)。

x, y是向量 n元素。让a, b是标量。让<x,y>表示 x 和 y 之间的点积。

x之间的相关性和 y可以用点积表示

<(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

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

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

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

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

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

代码

将这两个改进放在一起,我们有以下内容(我不会说 pandas,所以它在 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)

我想将我的修改放在这篇文章中,以进一步鼓励对该答案的支持。

这是我利用此建议实现的代码。该解决方案在 pandas 和 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

关于python - 计算相关矩阵子集的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38177464/

相关文章:

python - 如何计算 Pandas 数据框中每分钟出现的次数

Python 解决方案 - 使用 Python 将 Microsoft BI 工作表导出到 Excel

Python/Pandas - 如果A列等于X或Y,则从B列分配值。如果不是,则分配C列。如何用Python编写?

python - 试图在 python 中创建一个菜单,但循环不会退出

javascript - 在 Bokeh 应用程序之间传输来自点击事件的数据

python - 运行我的系统时具有相同的输出

python - 使用 putmask 替换数组中的列值并保留顺序

python - 在不同的 .text 文件中查找通用 ID 并附加额外的对应行

python - 散点图上的 Bokeh 图回归线

numpy - 如何在 Python 3.3 的 numpy 中启用 nditer 中的 REFS_OK 标志?