首页 文章

矩阵的所有行对的相关系数和p值

提问于
浏览
14

我有一个m行和n列的矩阵 data . 我曾经使用np.corrcoef来计算所有行对之间的相关系数:

import numpy as np
data = np.array([[0, 1, -1], [0, -1, 1]])
np.corrcoef(data)

现在我还想看看这些系数的p值 . np.corrcoef 不提供这些; scipy.stats.pearsonr . 但是, scipy.stats.pearsonr 不接受输入矩阵 .

有一种快速的方法可以计算所有行对的系数和p值(例如,到达m m矩阵为2 m,一个具有相关系数,另一个具有相应的p值),而无需手动完成所有对?

4 回答

  • 12

    这样做的最有效的方法可能是 pandas 中的buildin方法 .corr ,得到r:

    In [79]:
    
    import pandas as pd
    m=np.random.random((6,6))
    df=pd.DataFrame(m)
    print df.corr()
              0         1         2         3         4         5
    0  1.000000 -0.282780  0.455210 -0.377936 -0.850840  0.190545
    1 -0.282780  1.000000 -0.747979 -0.461637  0.270770  0.008815
    2  0.455210 -0.747979  1.000000 -0.137078 -0.683991  0.557390
    3 -0.377936 -0.461637 -0.137078  1.000000  0.511070 -0.801614
    4 -0.850840  0.270770 -0.683991  0.511070  1.000000 -0.499247
    5  0.190545  0.008815  0.557390 -0.801614 -0.499247  1.000000
    

    要使用t检验获得p值:

    In [84]:
    
    n=6
    r=df.corr()
    t=r*np.sqrt((n-2)/(1-r*r))
    
    import scipy.stats as ss
    ss.t.cdf(t, n-2)
    Out[84]:
    array([[ 1.        ,  0.2935682 ,  0.817826  ,  0.23004382,  0.01585695,
             0.64117917],
           [ 0.2935682 ,  1.        ,  0.04363408,  0.17836685,  0.69811422,
             0.50661121],
           [ 0.817826  ,  0.04363408,  1.        ,  0.39783538,  0.06700715,
             0.8747497 ],
           [ 0.23004382,  0.17836685,  0.39783538,  1.        ,  0.84993082,
             0.02756579],
           [ 0.01585695,  0.69811422,  0.06700715,  0.84993082,  1.        ,
             0.15667393],
           [ 0.64117917,  0.50661121,  0.8747497 ,  0.02756579,  0.15667393,
             1.        ]])
    In [85]:
    
    ss.pearsonr(m[:,0], m[:,1])
    Out[85]:
    (-0.28277983892175751, 0.58713640696703184)
    In [86]:
    #be careful about the difference of 1-tail test and 2-tail test:
    0.58713640696703184/2
    Out[86]:
    0.2935682034835159 #the value in ss.t.cdf(t, n-2) [0,1] cell
    

    您也可以使用OP中提到的 scipy.stats.pearsonr

    In [95]:
    #returns a list of tuples of (r, p, index1, index2)
    import itertools
    [ss.pearsonr(m[:,i],m[:,j])+(i, j) for i, j in itertools.product(range(n), range(n))]
    Out[95]:
    [(1.0, 0.0, 0, 0),
     (-0.28277983892175751, 0.58713640696703184, 0, 1),
     (0.45521036266021014, 0.36434799921123057, 0, 2),
     (-0.3779357902414715, 0.46008763115463419, 0, 3),
     (-0.85083961671703368, 0.031713908656676448, 0, 4),
     (0.19054495489542525, 0.71764166168348287, 0, 5),
     (-0.28277983892175751, 0.58713640696703184, 1, 0),
     (1.0, 0.0, 1, 1),
    #etc, etc
    
  • 9

    我今天遇到了同样的问题 .

    经过半小时的谷歌搜索,我在numpy / scipy库中找不到任何代码可以帮我做到这一点 .

    所以我写了自己的 corrcoef 版本

    import numpy as np
    from scipy.stats import pearsonr, betai
    
    def corrcoef(matrix):
        r = np.corrcoef(matrix)
        rf = r[np.triu_indices(r.shape[0], 1)]
        df = matrix.shape[1] - 2
        ts = rf * rf * (df / (1 - rf * rf))
        pf = betai(0.5 * df, 0.5, df / (df + ts))
        p = np.zeros(shape=r.shape)
        p[np.triu_indices(p.shape[0], 1)] = pf
        p[np.tril_indices(p.shape[0], -1)] = pf
        p[np.diag_indices(p.shape[0])] = np.ones(p.shape[0])
        return r, p
    
    def corrcoef_loop(matrix):
        rows, cols = matrix.shape[0], matrix.shape[1]
        r = np.ones(shape=(rows, rows))
        p = np.ones(shape=(rows, rows))
        for i in range(rows):
            for j in range(i+1, rows):
                r_, p_ = pearsonr(matrix[i], matrix[j])
                r[i, j] = r[j, i] = r_
                p[i, j] = p[j, i] = p_
        return r, p
    

    第一个版本使用np.corrcoef的结果,然后根据corrcoef矩阵的三角形上限值计算p值 .

    第二个循环版本只是遍历行,手动执行pearsonr .

    def test_corrcoef():
        a = np.array([
            [1, 2, 3, 4],
            [1, 3, 1, 4],
            [8, 3, 8, 5]])
    
        r1, p1 = corrcoef(a)
        r2, p2 = corrcoef_loop(a)
    
        assert np.allclose(r1, r2)
        assert np.allclose(p1, p2)
    

    测试通过,他们是一样的 .

    def test_timing():
        import time
        a = np.random.randn(100, 2500)
    
        def timing(func, *args, **kwargs):
            t0 = time.time()
            loops = 10
            for _ in range(loops):
                func(*args, **kwargs)
            print('{} takes {} seconds loops={}'.format(
                func.__name__, time.time() - t0, loops))
    
        timing(corrcoef, a)
        timing(corrcoef_loop, a)
    
    
    if __name__ == '__main__':
        test_corrcoef()
        test_timing()
    

    我的Macbook对100x2500矩阵的性能

    corrcoef需要0.06608104705810547秒循环= 10 corrcoef_loop需要7.585600137710571秒循环= 10

  • 4

    有点hackish和可能效率低下,但我认为这可能是你正在寻找的:

    import scipy.spatial.distance as dist
    
    import scipy.stats as ss
    
    # Pearson's correlation coefficients
    print dist.squareform(dist.pdist(data, lambda x, y: ss.pearsonr(x, y)[0]))    
    
    # p-values
    print dist.squareform(dist.pdist(data, lambda x, y: ss.pearsonr(x, y)[1]))
    

    Scipy's pdist是一个非常有用的函数,主要用于查找n维空间中观测值之间的成对距离 .

    但它允许用户定义可调用'distance metrics',可以利用它来执行任何类型的成对操作 . 结果以压缩距离矩阵形式返回,可以使用Scipy's 'squareform' function轻松更改为方形矩阵形式 .

  • 0

    如果您不必使用pearson correlation coefficient,则可以使用spearman correlation coefficient,因为它返回相关矩阵和p值(请注意,前者要求您的数据是正态分布的,而spearman相关是非参数度量,因此,不假设您的数据正常分布) . 示例代码:

    from scipy import stats
    import numpy as np
    
    data = np.array([[0, 1, -1], [0, -1, 1], [0, 1, -1]])
    print 'np.corrcoef:', np.corrcoef(data)
    cor, pval = stats.spearmanr(data.T)
    print 'stats.spearmanr - cor:\n', cor
    print 'stats.spearmanr - pval\n', pval
    

相关问题