Corrélation croisée (décalage-corrélation) avec pandas?

j'ai plusieurs séries chronologiques, que je veux corréler - ou plutôt, Cross-correlate - avec l'autre, pour savoir à quel décalage le facteur de corrélation est le plus grand.

j'ai trouvé divers questions et réponses/liens discutant comment le faire avec numpy, mais cela signifierait que je dois transformer mes images de données en tableaux numpy. Et puisque mes séries chronologiques couvrent souvent des périodes différentes, je crains que je sera exécuté dans le chaos.

Modifier

le problème que j'ai avec toutes les méthodes numpy/scipy, c'est qu'ils semblent manquer de conscience de la nature des séries temporelles de mes données. Quand je mets en corrélation une série chronologique qui commence par exemple en 1940 avec celle qui commence en 1970, pandas corr le sait, alors que np.correlate ne produit qu'un tableau 1020 entrées (longueur de la série plus longue) plein de nan.

les différents Q sur ce sujet indiquent qu'il devrait être un moyen de résoudre les différents longueur de problème, mais jusqu'à présent, je n'ai vu aucune indication sur la façon de l'utiliser pour des périodes de temps spécifiques. J'ai juste besoin de changer de 12 mois par incréments de 1, pour voir le temps de corrélation maximale dans un an.

Edit2

un minimum de données d'exemple:

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)

en raison de diverses étapes de traitement, ces FD se retrouvent changé en df qui sont indexés de 1940 à 2015. ceci devrait reproduire ceci:

bigdates = pd.date_range('01/01/1940', '01/01/2015', freq = 'MS')
big1 = pd.DataFrame(index = bigdates)
big2 = pd.DataFrame(index = bigdates)
big1 = pd.concat([big1, df1],axis = 1)
big2 = pd.concat([big2, df2],axis = 1)

C'est ce que j'obtiens quand je suis en corrélation avec pandas et changer un ensemble de données:

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

Et en essayant de scipy:

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

qui, selon whos est

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

mais j'aimerais juste avoir 12 entrées. / Edit2

l'idée est venue avec, est de mettre en œuvre un décalage dans le temps de corrélation moi-même, comme suit:

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

mais c'est probablement lent, et j'essaie probablement de réinventer la roue ici. Modifier L'approche ci-dessus semble fonctionner, et je l'ai mis dans une boucle, de passer par tous les 12 mois de l'année, mais je préfère encore une méthode intégrée.

21
demandé sur Community 2015-10-16 16:12:10

2 réponses

autant que je puisse dire, il n'y a pas de méthode intégrée qui fait exactement ce que vous demandez. Mais si vous regardez le code source pour la méthode de la série pandas autocorr , vous pouvez voir que vous avez la bonne idée:

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))

ainsi une fonction de covariance croisée décalée dans le temps simple serait

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))

alors si vous vouliez regarder les corrélations croisées à chaque mois, vous pourriez faire

 xcov_monthly = [crosscorr(datax, datay, lag=i) for i in range(12)]
27
répondu Daniel Watkins 2016-05-13 17:23:14

il y a une meilleure approche : vous pouvez créer une fonction qui décalé votre dataframe d'abord avant d'appeler le corr().

Obtenez cette base de données comme un exemple:

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

votre fonction pour déplacer d'autres colonnes (sauf la cible):

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)

supposons que votre cible compare la prcp (variable de précipitation) avec stp(pression atmosphérique)

Si vous faites dans le présent:

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

mais si vous décalé période 1(Un) toutes les autres colonnes et de garder le objectif (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

notez que maintenant la colonne stp est décaler une position vers le haut à la période, Donc si vous appelez le corr (), sera:

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

donc, vous pouvez faire avec lag -1, -2, - n!!

1
répondu Andre Araujo 2018-02-13 17:56:31