web-dev-qa-db-de.com

Korrelationskoeffizienten und p-Werte für alle Zeilenpaare einer Matrix

Ich habe eine Matrix data mit m Zeilen und n Spalten. Ich habe die Korrelationskoeffizienten zwischen allen Zeilenpaaren mit np.corrcoef berechnet:

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

Nun möchte ich auch die p-Werte dieser Koeffizienten betrachten. np.corrcoef liefert diese nicht; scipy.stats.pearsonr tut. scipy.stats.pearsonr akzeptiert jedoch keine Matrix bei der Eingabe. 

Gibt es eine schnelle Methode, um sowohl den Koeffizienten als auch den p-Wert für alle Zeilenpaare zu berechnen (z. B. bei zwei m durch m Matrizen, eine mit Korrelationskoeffizienten, die andere) mit entsprechenden p-Werten), ohne manuell alle Paare durchlaufen zu müssen?

16
John Manak

Ich bin heute dem gleichen Problem begegnet.

Nach einer halben Stunde googeln finde ich keinen Code in der numpy/scipy-Bibliothek, der mir dabei helfen kann. 

Also schrieb ich meine eigene Version von 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

Die erste Version verwendet das Ergebnis von np.corrcoef und berechnet dann den p-Wert basierend auf den oberen Dreieckswerten der Corrcoef-Matrix.

Die zweite Loop-Version, die nur über Zeilen iteriert, führt Pearsonr manuell aus.

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)

Der Test ist bestanden, sie sind gleich.

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 __== '__main__':
    test_corrcoef()
    test_timing()

Die Leistung auf meinem Macbook gegen 100x2500-Matrix

corrcoef dauert 0,06608104705810547 Sekunden = 10

corrcoef_loop dauert 7,585600137710571 Sekunden = 10

12
jingchao

Die einfachste Methode ist die Buildin-Methode .corr in pandas, um r zu erhalten:

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

Um p-Werte mit t-test zu erhalten:

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

Sie können auch den scipy.stats.pearsonr verwenden, den Sie in OP erwähnt haben:

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
CT Zhu

Irgendwie hackig und möglicherweise ineffizient, aber ich denke, das könnte das sein, wonach Sie suchen:

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 ist eine sehr hilfreiche Funktion, die hauptsächlich dazu dient, paarweise Abstände zwischen Beobachtungen im n-dimensionalen Raum zu finden. 

Es ermöglicht jedoch benutzerdefiniert aufrufbare "Entfernungsmesswerte", die zur Ausführung jeder Art von paarweiser Operation verwendet werden können. Das Ergebnis wird in einer komprimierten Abstandsmatrixform zurückgegeben, die mit Scipys 'squareform'-Funktion leicht in die quadratische Matrixform geändert werden kann.

4
Ketan

Wenn Sie Pearson-Korrelationskoeffizient nicht verwenden müssen, können Sie den Spearman-Korrelationskoeffizienten verwenden, da er sowohl die Korrelationsmatrix als auch die p-Werte zurückgibt. Beachten Sie, dass Ihre Daten normalerweise normalverteilt sind , während die Spearman-Korrelation ein nicht parametrisches Maß ist und daher nicht die Normalverteilung Ihrer Daten annimmt). Ein Beispielcode:

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
1
Sahar

dies ist genau die gleiche Leistung wie der Corrcoef in MATLAB:

damit diese Funktion funktioniert, müssen Sie pandas sowie scipy installieren.

# Compute correlation correfficients matrix and p-value matrix
# Similar function as corrcoef in MATLAB
# dframe: pandas dataframe
def corrcoef(dframe):

    fmatrix = dframe.values
    rows, cols = fmatrix.shape

    r = np.ones((cols, cols), dtype=float)
    p = np.ones((cols, cols), dtype=float)

    for i in range(cols):
        for j in range(cols):
            if i == j:
                r_, p_ = 1., 1.
            else:
                r_, p_ = pearsonr(fmatrix[:,i], fmatrix[:,j])

            r[j][i] = r_
            p[j][i] = p_

    return r, p
1
Zejian Zhang