我有一个4×3矩阵X
,并希望形成3×3皮尔逊相关矩阵C
,该矩阵通过计算的所有3种可能的列组合之间的相关性而获得X
。但是,与统计意义上不显着的相关性对应的C
条目应设置为零。
我知道如何使用pearsonr
中的scipy.stats
获得成对的相关性和重要性值。例如,
import numpy as np
from scipy.stats.stats import pearsonr
X = np.array([[1, 1, -2], [0, 0, 0], [0, .2, 1], [5, 3, 4]])
pearsonr(X[:, 0], X[:, 1])
返回(0.9915008164289165, 0.00849918357108348)
,X
的第一和第二列之间的相关性约为.9915,p值为.0085。
我可以使用嵌套循环轻松获得所需的矩阵:
C
预先填充为3乘3的零矩阵。X
的两列。如果p值小于或等于我的阈值(例如.01),则与这对列对应的C
条目将设置为成对相关。我想知道是否有更简单的方法。我知道在Pandas中,我基本上可以在一行中创建相关矩阵C
:
import pandas as pd
df = pd.DataFrame(data=X)
C_frame = df.corr(method='pearson')
C = C_frame.to_numpy()
有没有一种方法可以获取没有循环的p值P
的矩阵或数据帧?如果是这样,应该如何将C
中的相应p值超过我的阈值,将P
的每个条目设置为零?
答案 0 :(得分:2)
仔细阅读pearsonr
的文档,可以发现用于计算相关性的公式。使用矢量化获取矩阵各列之间的相关性应该不太困难。
虽然您可以使用熊猫计算C
的值,但我将展示整个过程的纯numpyan实现。
首先,计算r值:
X = np.array([[1, 1, -2],
[0, 0, 0],
[0, .2, 1],
[5, 3, 4]])
n = X.shape[0]
X -= X.mean(axis=0)
s = (X**2).sum(axis=0)
r = (X[..., None] * X[..., None, :]).sum(axis=0) / np.sqrt(s[:, None] * s[None, :])
考虑到scipy中存在beta分布,计算p
的值变得很简单。直接从文档中获取:
dist = scipy.stats.beta(n/2 - 1, n/2 - 1, loc=-1, scale=2)
p = 2 * dist.cdf(-abs(r))
您可以使用阈值从p
制作一个简单的蒙版,并将其应用于r
来制作C
:
mask = (p <= 0.01)
C = np.zeros_like(r)
C[mask] = r[mask]
更好的选择可能是就地修改r
:
r[p > 0.1] = 0
以函数形式:
def non_trivial_correlation(X, threshold=0.1):
n = X.shape[0]
X = X - X.mean(axis=0) # Don't modify the original
x = (X**2).sum(axis=0)
r = (X[..., None] * X[..., None, :]).sum(axis=0) / np.sqrt(s[:, None] * s[None, :])
p = 2 * scipy.stats.beta(n/2 - 1, n/2 - 1, loc=-1, scale=2).cdf(-abs(r))
r[p > threshold] = 0
return r