据我了解,
numpy.correlate
和numpy.corrcoef
对于对齐的归一化向量应该产生相同的结果。两个直接相反的情况:
from math import isclose as near
import numpy as np
def normalizedCrossCorrelation(a, b):
assert len(a) == len(b)
normalized_a = [aa / np.linalg.norm(a) for aa in a]
normalized_b = [bb / np.linalg.norm(b) for bb in b]
return np.correlate(normalized_a, normalized_b)[0]
def test_normalizedCrossCorrelationOfSimilarVectorsRegression0():
v0 = [1, 2, 3, 2, 1, 0, -2, -1, 0]
v1 = [1, 1.9, 2.8, 2, 1.1, 0, -2.2, -0.9, 0.2]
assert near(normalizedCrossCorrelation(v0, v1), 0.9969260391224474)
print(f"{np.corrcoef(v0, v1)=}")
assert near(normalizedCrossCorrelation(v0, v1), np.corrcoef(v0, v1)[0, 1])
def test_normalizedCrossCorrelationOfSimilarVectorsRegression1():
v0 = [1, 2, 3, 2, 1, 0, -2, -1, 0]
v1 = [0.8, 1.9, 2.5, 2.1, 1.2, -0.3, -2.4, -1.4, 0.4]
assert near(normalizedCrossCorrelation(v0, v1), 0.9809817769512982)
print(f"{np.corrcoef(v0, v1)=}")
assert near(normalizedCrossCorrelation(v0, v1), np.corrcoef(v0, v1)[0, 1])
Pytest 输出:
E assert False
E + where False = near(0.9969260391224474, 0.9963146417122921)
E + where 0.9969260391224474 = normalizedCrossCorrelation([1, 2, 3, 2, 1, 0, ...], [1, 1.9, 2.8, 2, 1.1, 0, ...])
E assert False
E + where False = near(0.9809817769512982, 0.9826738919606931)
E + where 0.9809817769512982 = normalizedCrossCorrelation([1, 2, 3, 2, 1, 0, ...], [0.8, 1.9, 2.5, 2.1, 1.2, -0.3, ...])
我认为你的
np.correlate
公式是错误的,它不会产生相关系数。
考虑第一个例子
v0 = [1, 2, 3, 2, 1, 0, -2, -1, 0]
v1 = [1, 1.9, 2.8, 2, 1.1, 0, -2.2, -0.9, 0.2]
np.correlate(v0 / np.linalg.norm(v0), v1 / np.linalg.norm(v1))[0] # 0.9969260391224474
# you can also use
# np.correlate(v0 , v1 , mode='valid') / np.linalg.norm(v0) / np.linalg.norm(v1)
# but you get same number
np.corrcoef(v0, v1)[0][1] # 0.9963146417122921
不使用浮点计算的正确答案应该是 59 Sqrt[5/17534],近似于
0.99631464171229218403
,与 np.corrcoef
惊人地相同。
考虑到
np.correlate(a, b)
当
a
和 b
是相同大小的一维数组时,返回标量积(例如 np.dot(a, b)
)。协方差可以计算(即使不推荐)为 E[v0 v1] - E[v0]E[v1]
。这可以这样做
(np.correlate(v0 , v1 , mode='valid') / len(v0) - np.mean(v0) * np.mean(v1))[0]
这等于
np.cov(v0, v1, ddof=0)[0][1]
。所以你可以将相关性计算为
((np.correlate(v0 , v1 , mode='valid') / len(v0) - np.mean(v0) * np.mean(v1)) / np.std(v0) / np.std(v1))[0]
顺便说一句,只需使用
np.corrcoef
或 np.cov
。