2015-10-16 10 views
15

Ich habe verschiedene Zeitreihen, die ich korrelieren - oder vielmehr kreuzkorrelieren möchte - um herauszufinden, bei welcher Zeitverzögerung der Korrelationsfaktor am größten ist.Kreuzkorrelation (Time-Lag-Korrelation) mit Pandas?

Ich fand variousquestions und Antworten/Links diskutieren, wie es mit numpy tun, aber das würde bedeuten, dass ich meine Datenframes in numply Arrays verwandeln müssen. Und da meine Zeitreihen oft unterschiedliche Zeiträume abdecken, fürchte ich, dass ich ins Chaos stürze.

bearbeiten

Das Problem, das ich mit allen numpy/scipy Methoden habe ist, dass sie scheinen das Bewusstsein für die Zeitreihen der Natur meiner Daten fehlen. Wenn ich eine Zeitreihe korreliere, die etwa 1940 mit einer beginnt, die 1970 beginnt, weiß Pandas corr dies, während np.correlate nur ein 1020 Einträge (Länge der längeren Serie) Array voller Nan erzeugt.

Die verschiedenen Q's zu diesem Thema zeigen an, dass es eine Möglichkeit geben sollte, das Problem mit unterschiedlicher Länge zu lösen, aber bisher habe ich keine Hinweise gesehen, wie man es für bestimmte Zeiträume verwendet. Ich muss mich nur um 12 Monate in Schritten von 1 verschieben, um die Zeit maximaler Korrelation innerhalb eines Jahres zu sehen.

EDIT2

Einige minimalen Probendaten:

import pandas as pd 
import numpy as np 
dfdates1 = pd.date_range('01/01/1980', '01/01/2000', freq = 'MS') 
dfdata1 = (np.random.random_integers(-30,30,(len(dfdates1)))/10.0) #My real data is from measurements, but random between -3 and 3 is fitting 
df1 = pd.DataFrame(dfdata1, index = dfdates1) 
dfdates2 = pd.date_range('03/01/1990', '02/01/2013', freq = 'MS') 
dfdata2 = (np.random.random_integers(-30,30,(len(dfdates2)))/10.0) 
df2 = pd.DataFrame(dfdata2, index = dfdates2) 

Aufgrund verschiedenen Verarbeitungsschritte, diese dfs am Ende in df geändert, die von 1940 bis 2015 indiziert ist dies dies reproduzieren soll:

Das ist, was ich bekomme, wenn ich mit Pandas korreliere und einen Datensatz verschiebe:

In [451]: corr_coeff_0 = big1[0].corr(big2[0]) 
In [452]: corr_coeff_0 
Out[452]: 0.030543266378853299 
In [453]: big2_shift = big2.shift(1) 
In [454]: corr_coeff_1 = big1[0].corr(big2_shift[0]) 
In [455]: corr_coeff_1 
Out[455]: 0.020788314779320523 

Und versuchen scipy:

In [456]: scicorr = scipy.signal.correlate(big1,big2,mode="full") 
In [457]: scicorr 
Out[457]: 
array([[ nan], 
     [ nan], 
     [ nan], 
     ..., 
     [ nan], 
     [ nan], 
     [ nan]]) 

die nach whos ist

scicorr    ndarray      1801x1: 1801 elems, type `float64`, 14408 bytes 

Aber ich würde nur 12 Einträge haben möchten. /Edit2

Die Idee, die ich mit gekommen sind, ist eine Zeitverzögerung Korrelation selbst zu implementieren, etwa so:

corr_coeff_0 = df1['Data'].corr(df2['Data']) 
df1_1month = df1.shift(1) 
corr_coeff_1 = df1_1month['Data'].corr(df2['Data']) 
df1_6month = df1.shift(6) 
corr_coeff_6 = df1_6month['Data'].corr(df2['Data']) 
...and so on 

Aber das ist wahrscheinlich langsam, und ich versuche, wahrscheinlich erfinden Sie das Rad hier neu. Edit Der obige Ansatz scheint zu funktionieren, und ich habe es in eine Schleife gelegt, um alle 12 Monate eines Jahres zu durchlaufen, aber ich würde immer noch eine eingebaute Methode bevorzugen.

+0

Wenn Sie diese nicht bereits gesehen haben, sollten Sie das ['scipy.signal.correlate'] (http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.correlate) verwenden .html) und ['scipy.signal.correlate2d'] (http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.correlate2d.html). Ich würde sagen, dass die Umwandlung in numplige Arrays wahrscheinlich die beste Wahl ist. – wgwz

+0

Ich habe diese gesehen, aber ich möchte vermeiden, zu numpy zu gehen, denn nach diesem Schritt müsste ich für weitere Berechnungen wieder in einen Datenrahmen konvertieren. Ich schätze, ich werde versuchen, das Rad neu zu erfinden, dann ... –

+0

Das ist ein ziemlich üblicher Arbeitsablauf, soweit ich weiß, der zu numpy und zurück konvertiert. Ich sehe keine Notwendigkeit, damit zu zögern. Ich würde empfehlen, Ihre Arrays auf die Festplatte zu schreiben, damit Sie die Conversions in Ihrem Code nicht wiederholen. Kasse 'pd.HDFStore' und' h5py'. Wenn Sie Lust haben, das Rad neu zu erfinden, gehen Sie darauf ein. – wgwz

Antwort

21

Soweit ich sagen kann, gibt es keine integrierte Methode, die genau was Sie fragen.Aber wenn man sich den Quellcode suchen die Pandas Series Methode autocorr können Sie sehen Sie die richtige Idee haben:

def autocorr(self, lag=1): 
    """ 
    Lag-N autocorrelation 

    Parameters 
    ---------- 
    lag : int, default 1 
     Number of lags to apply before performing autocorrelation. 

    Returns 
    ------- 
    autocorr : float 
    """ 
    return self.corr(self.shift(lag)) 

So eine einfache timelagged Kreuzkovarianzfunktion

def crosscorr(datax, datay, lag=0): 
    """ Lag-N cross correlation. 
    Parameters 
    ---------- 
    lag : int, default 0 
    datax, datay : pandas.Series objects of equal length 

    Returns 
    ---------- 
    crosscorr : float 
    """ 
    return datax.corr(datay.shift(lag)) 

Dann wäre wenn man sich die Kreuzkorrelationen in jedem Monat suchen will, könnten Sie

xcov_monthly = [crosscorr(datax, datay, lag=i) for i in range(12)] 
+0

Danke, das hilft ein bisschen! Total vergessen, dass die eingebaute Autokorrelation im Wesentlichen eine Zeitverzögerung ist. Ich werde sehen, ob ich damit arbeiten kann, um eine nützlichere Ausgabe als nur eine Liste zu produzieren. –

0

tun Es ist ein besserer Ansatz: Sie können eine Funktion erstellen, die verschoben Ihr Dataform zuerst vor dem Aufruf der corr().

Holen Sie sich diese Datenrahmen wie ein Beispiel:

d = {'prcp': [0.1,0.2,0.3,0.0], 'stp': [0.0,0.1,0.2,0.3]} 
df = pd.DataFrame(data=d) 

>>> df 
    prcp stp 
0 0.1 0.0 
1 0.2 0.1 
2 0.3 0.2 
3 0.0 0.3 

Ihre Funktion auf andere Spalten zu verschieben (mit Ausnahme des Ziels):

def df_shifted(df, target=None, lag=0): 
    if not lag and not target: 
     return df  
    new = {} 
    for c in df.columns: 
     if c == target: 
      new[c] = df[target] 
     else: 
      new[c] = df[c].shift(periods=lag) 
    return pd.DataFrame(data=new) 

der Annahme, dass Ihr Ziel, die PrCp (Fällungs Variable) vergleicht mit stp (Atmosphärendruck)

Wenn Sie in der Gegenwart tun werden:

>>> df.corr() 
     prcp stp 
prcp 1.0 -0.2 
stp -0.2 1.0 

Aber wenn Sie 1 verschoben (eins) Zeitraum alle anderen Spalten und halten die Ziel (PrCp):

df_new = df_shifted(df, 'prcp', lag=-1) 

>>> print df_new 
    prcp stp 
0 0.1 0.1 
1 0.2 0.2 
2 0.3 0.3 
3 0.0 NaN 

Beachten Sie, dass jetzt die Spalte stp ein Hochschalten Position in der Periode ist, so wenn Sie die korr() aufrufen, wird sein:

>>> df_new.corr() 
     prcp stp 
prcp 1.0 1.0 
stp 1.0 1.0 

So können Sie mit Verzögerung tun -1, -2, -n !!