N X T
とM X T
の形状を持つ2つの配列があります。 T
とn
のすべての可能なペアの間のm
の相関係数を計算したい(それぞれN
とM
から).
これを行うための最も速く、最もPython的な方法は何ですか? (N
およびM
をループすると、高速でもPythonicでもないように思えます。)numpy
および/またはscipy
が関係することを期待しています。現在、私の配列はnumpy
array
sですが、別の型に変換することはできます。
私の出力は、形状N X M
の配列になると予想しています。
N.B. 「相関係数」と言うときは、 ピアソンの積率相関係数 を意味します。
以下に注意する点を示します。
numpy
関数correlate
では、入力配列が1次元である必要があります。numpy
関数corrcoef
は2次元配列を受け入れますが、同じ形状でなければなりません。scipy.stats
関数pearsonr
では、入力配列が1次元である必要があります。2つの2D配列間の相関(デフォルトの「有効な」場合):
単純に行列乗算を使用できます np.dot
のように-
out = np.dot(arr_one,arr_two.T)
2つの入力配列の各ペアワイズ行の組み合わせ(row1、row2)間のデフォルトの"valid"
ケースとの相関は、各(row1、row2)位置での乗算結果に対応します。
2つの2D配列の行ごとの相関係数の計算:
def corr2_coeff(A,B):
# Rowwise mean of input arrays & subtract from input arrays themeselves
A_mA = A - A.mean(1)[:,None]
B_mB = B - B.mean(1)[:,None]
# Sum of squares across rows
ssA = (A_mA**2).sum(1);
ssB = (B_mB**2).sum(1);
# Finally get corr coeff
return np.dot(A_mA,B_mB.T)/np.sqrt(np.dot(ssA[:,None],ssB[None]))
これは How to apply corr2 functions in Multidimentional arrays in MATLAB
のこのソリューションに基づいています
ベンチマーク
このセクションでは、 その他の回答 (関数test_generate_correlation_map()
から取得)にリストされているgenerate_correlation_map
およびloopy pearsonr
ベースのアプローチに対する提案されたアプローチとランタイムパフォーマンスを比較します。最後に値の正当性検証コード)。提案されたアプローチのタイミングには、他の回答でも行われているように、2つの入力配列の列数が等しいかどうかをチェックするための開始時のチェックも含まれています。次にランタイムをリストします。
ケース#1:
In [106]: A = np.random.Rand(1000,100)
In [107]: B = np.random.Rand(1000,100)
In [108]: %timeit corr2_coeff(A,B)
100 loops, best of 3: 15 ms per loop
In [109]: %timeit generate_correlation_map(A, B)
100 loops, best of 3: 19.6 ms per loop
ケース#2:
In [110]: A = np.random.Rand(5000,100)
In [111]: B = np.random.Rand(5000,100)
In [112]: %timeit corr2_coeff(A,B)
1 loops, best of 3: 368 ms per loop
In [113]: %timeit generate_correlation_map(A, B)
1 loops, best of 3: 493 ms per loop
ケース#3:
In [114]: A = np.random.Rand(10000,10)
In [115]: B = np.random.Rand(10000,10)
In [116]: %timeit corr2_coeff(A,B)
1 loops, best of 3: 1.29 s per loop
In [117]: %timeit generate_correlation_map(A, B)
1 loops, best of 3: 1.83 s per loop
他のループpearsonr based
アプローチは遅すぎるように見えましたが、ここに1つの小さなデータサイズのランタイムがあります-
In [118]: A = np.random.Rand(1000,100)
In [119]: B = np.random.Rand(1000,100)
In [120]: %timeit corr2_coeff(A,B)
100 loops, best of 3: 15.3 ms per loop
In [121]: %timeit generate_correlation_map(A, B)
100 loops, best of 3: 19.7 ms per loop
In [122]: %timeit pearsonr_based(A,B)
1 loops, best of 3: 33 s per loop
@Divakarは、スケーリングされていない相関を計算するための優れたオプションを提供します。
相関係数を計算するには、もう少し必要です。
import numpy as np
def generate_correlation_map(x, y):
"""Correlate each n with each m.
Parameters
----------
x : np.array
Shape N X T.
y : np.array
Shape M X T.
Returns
-------
np.array
N X M array in which each element is a correlation coefficient.
"""
mu_x = x.mean(1)
mu_y = y.mean(1)
n = x.shape[1]
if n != y.shape[1]:
raise ValueError('x and y must ' +
'have the same number of timepoints.')
s_x = x.std(1, ddof=n - 1)
s_y = y.std(1, ddof=n - 1)
cov = np.dot(x,
y.T) - n * np.dot(mu_x[:, np.newaxis],
mu_y[np.newaxis, :])
return cov / np.dot(s_x[:, np.newaxis], s_y[np.newaxis, :])
この関数のテストは次のとおりです。
from scipy.stats import pearsonr
def test_generate_correlation_map():
x = np.random.Rand(10, 10)
y = np.random.Rand(20, 10)
desired = np.empty((10, 20))
for n in range(x.shape[0]):
for m in range(y.shape[0]):
desired[n, m] = pearsonr(x[n, :], y[m, :])[0]
actual = generate_correlation_map(x, y)
np.testing.assert_array_almost_equal(actual, desired)