ily*_*lya 5 performance numpy correlation pearson-correlation
原始问题
我将大小为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))
Run Code Online (Sandbox Code Playgroud)
它比天真的方法更有效:
def ColumnWiseCorrcoefNaive(O, P):
return np.corrcoef(P,O.T)[0,1:O[0].size+1]
Run Code Online (Sandbox Code Playgroud)
以下是我在Intel核心上使用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
Run Code Online (Sandbox Code Playgroud)
现在的问题是:你能为这个问题建议一个更快的代码版本吗?挤出额外的20%将是伟大的.
2017年5月更新
经过一段时间我回到了这个问题,重新运行并扩展了任务和测试.
使用einsum,我已经将代码扩展到P不是行而是矩阵的情况.因此,任务是将O的所有列与P的所有列相关联.
由于对如何通过常用于科学计算的不同语言解决同一问题感到好奇,我在MATLAB,Julia和R中实现了它(在其他人的帮助下).MATLAB和Julia是最快的,他们有一个专门的例程计算列向相关.R也有专门的例行程序但速度最慢.
在当前版本的numpy(来自Anaconda的1.12.1)中,einsum仍然胜过我使用的专用功能.
所有脚本和时序都可以在https://github.com/ikizhvatov/efficient-columnwise-correlation上找到.
我们可以介绍np.einsum一下;但是,您的里程可能会因您的编译以及是否使用 SSE2而异。einsum替换求和操作的额外调用可能看起来无关紧要,但是直到 numpy 1.8 while 使用 numpy ufunc 才使用 SSE2 einsum,我们可以避免使用一些if语句。
在带有 intel mkl blas 的 opteron 内核上运行它,我得到了一个奇怪的结果,因为我预计dot调用会占用大部分时间。
def newColumnWiseCorrcoef(O, P):
n = P.size
DO = O - (np.einsum('ij->j',O) / np.double(n))
P -= (np.einsum('i->',P) / np.double(n))
tmp = np.einsum('ij,ij->j',DO,DO)
tmp *= np.einsum('i,i->',P,P) #Dot or vdot doesnt really change much.
return np.dot(P, DO) / np.sqrt(tmp)
O = np.reshape(np.random.rand(100000), (1000,100))
P = np.random.rand(1000)
old = ColumnWiseCorrcoef(O,P)
new = newColumnWiseCorrcoef(O,P)
np.allclose(old,new)
True
%timeit ColumnWiseCorrcoef(O,P)
100 loops, best of 3: 1.52ms per loop
%timeit newColumnWiseCorrcoef(O,P)
1000 loops, best of 3: 518us per loop
Run Code Online (Sandbox Code Playgroud)
再次使用带有 intel mkl 的 intel 系统运行它,我得到了更合理/预期的结果:
%timeit ColumnWiseCorrcoef(O,P)
1000 loops, best of 3: 524 µs per loop
%timeit newColumnWiseCorrcoef(O,P)
1000 loops, best of 3: 354 µs per loop
Run Code Online (Sandbox Code Playgroud)
再次在英特尔机器上使用更大的东西:
O = np.random.rand(1E5,1E3)
P = np.random.rand(1E5)
%timeit ColumnWiseCorrcoef(O,P)
1 loops, best of 3: 1.33 s per loop
%timeit newColumnWiseCorrcoef(O,P)
1 loops, best of 3: 791 ms per loop
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1205 次 |
| 最近记录: |