使用点积计算相关性(如您的示例所示)似乎是一种好方法。我将描述两个改进,然后是实现它们的代码。
改进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)