2013-04-06 25 views
30

Jestem całkiem nowy, pandy, więc myślę, że robię coś złego -Korelacja między kolumnami w DataFrame

Mam 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() daje mi:

a b 
a NaN NaN 
b NaN NaN 

ale np.correlate(df["a"], df["b"]) daje: 1.875

Dlaczego t kapelusz? Chcę mieć macierz korelacji dla mojej DataFrame i myślałem, że robi to corr() (przynajmniej zgodnie z dokumentacją). Dlaczego zwraca NaN?

Jaki jest prawidłowy sposób obliczenia?

Wielkie dzięki!

Odpowiedz

63

np.correlate oblicza (nieznormalizowanego) cross-correlation między dwiema sekwencjami 1-wymiarowe:

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

podczas df.corr (domyślnie) oblicza Pearson correlation coefficient.

Współczynnik korelacji (jeśli istnieje) wynosi zawsze od -1 do 1 włącznie. Korelacja krzyżowa nie jest ograniczona.

Formuły są nieco podobne, ale należy zauważyć, że w formule korelacji krzyżowej (powyżej) nie ma odejmowania środków, ani podziału przez odchylenia standardowe, które są częścią wzoru dla współczynnika korelacji Pearsona.

Fakt, że standardowe odchylenie df['a'] i df['b'] wynosi zero, powoduje, że df.corr ma wszędzie NaN.


Z poniższego komentarza wygląda na to, że szukasz Beta. Wiąże się to współczynnik korelacji Pearsona, ale zamiast dzieląc przez iloczyn odchyleń standardowych:

enter image description here

podzielić przez wariancji:

enter image description here


Można obliczyć Beta użycie 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

Stosunek mu s wynosi 2, a beta wynosi około 2,1.


I można również obliczyć ją df.corr, choć jest to o wiele bardziej okrągłe o sposób to zrobić (ale miło jest zobaczyć istnieje spójność):

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

Dzięki! Tak więc, w przypadku, gdy moje "a" i "b" są dziennymi zmianami cen i chcę zmierzyć, w jaki sposób "b" ma wartość "a" (czyli - jeśli za każdym razem "a" wzrasta o 1% b wzrasta o 2%. Spodziewam się zobaczyć 2,0, jeśli "b" zawsze wynosi -0,5%, oczekiwam -0,5). Myślę, że "korelacja krzyżowa" jest tym, czego chcę, prawda? –

Powiązane problemy