原始问题
我正在将大小为n的行P与大小为n×m的矩阵O的每一列进行相关。我编写了以下代码:
import numpy as np
def ColumnWiseCorrcoef(O, P):
n = P.size
DO = O - (np.sum(O, 0) / np.double(n))
DP = P - (np.sum(P) / np.double(n))
return np.dot(DP, DO) / np.sqrt(np.sum(DO ** 2, 0) * np.sum(DP ** 2))
它比朴素方法更有效:
def ColumnWiseCorrcoefNaive(O, P):
return np.corrcoef(P,O.T)[0,1:O[0].size+1]
这是我在Intel Core上使用numpy-1.7.1-MKL得到的时间:
O = np.reshape(np.random.rand(100000), (1000,100))
P = np.random.rand(1000)
%timeit -n 1000 A = ColumnWiseCorrcoef(O, P)
1000 loops, best of 3: 787 us per loop
%timeit -n 1000 B = ColumnWiseCorrcoefNaive(O, P)
1000 loops, best of 3: 2.96 ms per loop
现在的问题是:你能提出一个更快的代码版本来解决这个问题吗?能够挤出额外的20%将会很棒。
更新于2017年5月
经过相当长的时间,我回到了这个问题,重新运行并扩展了任务和测试。
1. 使用einsum,我已经将代码扩展到P不是一行而是一个矩阵的情况。因此,任务是将O的所有列与P的所有列相关联。
2. 对于如何使用不同的用于科学计算的语言解决相同问题感到好奇,我(在其他人的帮助下)在MATLAB、Julia和R中实现了它。MATLAB和Julia是最快的,并且它们有专门的例程来计算逐列相关性。R也有一个专门的例程,但速度最慢。
3. 在当前版本的numpy(来自Anaconda的1.12.1)中,einsum仍然胜过我使用的专用函数。
所有脚本和时间都可以在https://github.com/ikizhvatov/efficient-columnwise-correlation中找到。
O
和P
可以更改吗?此外,这些方法严重依赖于链接到numpy的BLAS库,如果您尚未使用某种优化的BLAS,我建议您使用它。 - DanielP
可以更改,O
不能更改。我正在使用链接到Intel MKL的numpy,网址为http://www.lfd.uci.edu/~gohlke/pythonlibs/。 - ilyanp.einsum('ij,ij->j', DO, DO)
代替np.sum(DO ** 2, 0)
,以及使用np.dot(DP, DP)
代替np.sum(DP ** 2)
,可能会有一些边际改进。 - Jaime