我们可以通过处理数组数据来优化内存和性能。
方法1
首先,让我们使用一个数组解决方案来获取两个1D数组之间对应元素的相关系数。这基本上是受到
这篇帖子启发的,并且可能看起来像这样 -
def corrcoeff_1d(A,B):
A_mA = A - A.mean(-1,keepdims=1)
B_mB = B - B.mean(-1,keepdims=1)
ssA = np.einsum('i,i->',A_mA, A_mA)
ssB = np.einsum('i,i->',B_mB, B_mB)
return np.einsum('i,i->',A_mA,B_mB)/np.sqrt(ssA*ssB)
现在,要使用它,请使用相同的循环但在数组数据上 -
lcl = 100
ar = tabla.values
N = len(ar)
out = np.zeros(N)
for i in range(N):
out[i] = corrcoeff_1d(ar[i:i+lcl,0], ar[i:i+lcl,1])
我们可以通过使用卷积来预先计算滚动均值,以计算
corrcoeff_1d
中使用的
A_mA
的性能进行进一步优化,但首先让我们解决内存错误问题。
方法#2
这是一个几乎向量化的方法,我们将向量化大部分迭代,除了最后剩余的片段,它们没有正确的窗口长度。循环次数将从97165降至lcl-1,即仅为99。
lcl = 100
ar = tabla.values
N = len(ar)
out = np.zeros(N)
col0_win = strided_app(ar[:,0],lcl,S=1)
col1_win = strided_app(ar[:,1],lcl,S=1)
vectorized_out = corr2_coeff_rowwise(col0_win, col1_win)
M = len(vectorized_out)
out[:M] = vectorized_out
for i in range(M,N):
out[i] = corrcoeff_1d(ar[i:i+lcl,0], ar[i:i+lcl,1])
辅助函数 -
def strided_app(a, L, S ):
nrows = ((a.size-L)//S)+1
n = a.strides[0]
return np.lib.stride_tricks.as_strided(a, shape=(nrows,L), strides=(S*n,n))
def corr2_coeff_rowwise(A,B):
A_mA = A - A.mean(-1,keepdims=1)
B_mB = B - B.mean(-1,keepdims=1)
ssA = np.einsum('ij,ij->i',A_mA, A_mA)
ssB = np.einsum('ij,ij->i',B_mB, B_mB)
return np.einsum('ij,ij->i',A_mA,B_mB)/np.sqrt(ssA*ssB)
填充NaN数据的相关性
下面列出了使用NumPy解决方案进行基于Pandas计算相关性的方法,用于计算1D数组之间的相关性和行向相关性值。
1)计算两个1D数组之间的标量相关值 -
def nancorrcoeff_1d(A,B):
comb_mask = ~(np.isnan(A) & ~np.isnan(B))
count = comb_mask.sum()
A_mA = A - np.nansum(A * comb_mask,-1,keepdims=1)/count
B_mB = B - np.nansum(B * comb_mask,-1,keepdims=1)/count
A_mA[~comb_mask] = 0
B_mB[~comb_mask] = 0
ssA = np.inner(A_mA,A_mA)
ssB = np.inner(B_mB,B_mB)
return np.inner(A_mA,B_mB)/np.sqrt(ssA*ssB)
2) 两个 2D
数组 (m,n)
之间的逐行相关性,得到一个形状为 (m,)
的一维数组 -
def nancorrcoeff_rowwise(A,B):
comb_mask = ~(np.isnan(A) & ~np.isnan(B))
count = comb_mask.sum(axis=-1,keepdims=1)
A_mA = A - np.nansum(A * comb_mask,-1,keepdims=1)/count
B_mB = B - np.nansum(B * comb_mask,-1,keepdims=1)/count
A_mA[~comb_mask] = 0
B_mB[~comb_mask] = 0
ssA = np.einsum('ij,ij->i',A_mA, A_mA)
ssB = np.einsum('ij,ij->i',B_mB, B_mB)
return np.einsum('ij,ij->i',A_mA,B_mB)/np.sqrt(ssA*ssB)