2013-04-06 27 views
30

Sono abbastanza nuovo per i panda, quindi credo che sto facendo qualcosa di sbagliato -Correlazione tra le colonne in dataframe

Ho un dataframe:

 a  b 
0 0.5 0.75 
1 0.5 0.75 
2 0.5 0.75 
3 0.5 0.75 
4 0.5 0.75 

df.corr() mi da:

a b 
a NaN NaN 
b NaN NaN 

ma np.correlate(df["a"], df["b"]) dà: 1.875

Perché è t cappello? Voglio avere la matrice di correlazione per il mio DataFrame e ho pensato che lo faccia corr() (almeno secondo la documentazione). Perché restituisce NaN?

Qual è il modo corretto per calcolare?

Grazie mille!

risposta

63

np.correlate calcola il (normalizzato) cross-correlation tra due sequenze 1-dimensionali:

z[k] = sum_n a[n] * conj(v[n+k]) 

mentre df.corr (di default) calcola il Pearson correlation coefficient.

Il coefficiente di correlazione (se esiste) è sempre compreso tra -1 e 1 incluso. La correlazione incrociata non è limitata.

Le formule sono in qualche modo correlate, ma si noti che nella formula di cross-correlazione (sopra) non vi è sottrazione delle medie e nessuna divisione delle deviazioni standard che fa parte della formula per il coefficiente di correlazione di Pearson.

Il fatto che la deviazione standard di df['a'] e df['b'] sia zero è ciò che fa sì che df.corr sia NaN ovunque.


Dal commento di seguito, sembra che stiate cercando Beta. È collegato al coefficiente di correlazione di Pearson, ma invece di dividere per il prodotto delle deviazioni standard:

enter image description here

si divide per una varianza:

enter image description here


È possibile calcolare Beta utilizzando np.cov

cov = np.cov(a, b) 
beta = cov[1, 0]/cov[0, 0] 

import numpy as np 
import matplotlib.pyplot as plt 
np.random.seed(100) 


def geometric_brownian_motion(T=1, N=100, mu=0.1, sigma=0.01, S0=20): 
    """ 
    http://stackoverflow.com/a/13203189/190597 (unutbu) 
    """ 
    dt = float(T)/N 
    t = np.linspace(0, T, N) 
    W = np.random.standard_normal(size=N) 
    W = np.cumsum(W) * np.sqrt(dt) # standard brownian motion ### 
    X = (mu - 0.5 * sigma ** 2) * t + sigma * W 
    S = S0 * np.exp(X) # geometric brownian motion ### 
    return S 

N = 10 ** 6 
a = geometric_brownian_motion(T=1, mu=0.1, sigma=0.01, N=N) 
b = geometric_brownian_motion(T=1, mu=0.2, sigma=0.01, N=N) 

cov = np.cov(a, b) 
print(cov) 
# [[ 0.38234755 0.80525967] 
# [ 0.80525967 1.73517501]] 
beta = cov[1, 0]/cov[0, 0] 
print(beta) 
# 2.10609347015 

plt.plot(a) 
plt.plot(b) 
plt.show() 

enter image description here

Il rapporto tra mu s è 2, e beta è ~ 2.1.


E si potrebbe anche calcolare con df.corr, anche se questo è un modo molto più rotonda di farlo (ma è bello vedere la coerenza):

import pandas as pd 
df = pd.DataFrame({'a': a, 'b': b}) 
beta2 = (df.corr() * df['b'].std() * df['a'].std()/df['a'].var()).ix[0, 1] 
print(beta2) 
# 2.10609347015 
assert np.allclose(beta, beta2) 
+0

Grazie! Quindi nel caso in cui il mio "a" e "b" sono variazioni giornaliere dei prezzi e voglio misurare come fa "b" fa rispetto a "a" (che significa - se ogni volta "a" sale dell'1% b sale del 2% mi aspetterei di vedere 2.0, se "b" è sempre -0.5% mi aspetterei -0.5). Immagino che la "cross-correlazione" sia ciò che voglio, giusto? –

Problemi correlati