J'ai été motivé pour utiliser les pandas rolling
pour effectuer une régression multifactorielle glissante. PAS sur la régression multi-factorielle glissante). Je m'attendais à ce que je puisse utiliser apply
après un df.rolling(2)
et prendre le résultat pd.DataFrame
extraire le ndarray avec .values
et effectuer la multiplication matricielle requise. Ça ne s'est pas passé comme ça.
Voici ce que j'ai trouvé :
import pandas as pd
import numpy as np
np.random.seed([3,1415])
df = pd.DataFrame(np.random.rand(5, 2).round(2), columns=['A', 'B'])
X = np.random.rand(2, 1).round(2)
A quoi ressemblent les objets :
print "\ndf = \n", df
print "\nX = \n", X
print "\ndf.shape =", df.shape, ", X.shape =", X.shape
df =
A B
0 0.44 0.41
1 0.46 0.47
2 0.46 0.02
3 0.85 0.82
4 0.78 0.76
X =
[[ 0.93]
[ 0.83]]
df.shape = (5, 2) , X.shape = (2L, 1L)
La multiplication matricielle se comporte normalement :
df.values.dot(X)
array([[ 0.7495],
[ 0.8179],
[ 0.4444],
[ 1.4711],
[ 1.3562]])
L'utilisation de apply pour effectuer le produit scalaire ligne par ligne se comporte comme prévu :
df.apply(lambda x: x.values.dot(X)[0], axis=1)
0 0.7495
1 0.8179
2 0.4444
3 1.4711
4 1.3562
dtype: float64
Groupby -> Apply se comporte comme je m'y attendais :
df.groupby(level=0).apply(lambda x: x.values.dot(X)[0, 0])
0 0.7495
1 0.8179
2 0.4444
3 1.4711
4 1.3562
dtype: float64
Mais quand je cours :
df.rolling(1).apply(lambda x: x.values.dot(X))
J'ai compris :
AttributeError : L'objet 'numpy.ndarray' ne possède pas d'attribut 'values'.
Ok, donc pandas utilise directement ndarray
au sein de son rolling
mise en œuvre. Je peux m'en occuper. Au lieu d'utiliser .values
pour obtenir le ndarray
essayons :
df.rolling(1).apply(lambda x: x.dot(X))
Les formes (1,) et (2,1) ne sont pas alignées : 1 (dim 0) != 2 (dim 0)
Attends ! Quoi ?!
J'ai donc créé une fonction personnalisée pour examiner ce que fait le roulement.
def print_type_sum(x):
print type(x), x.shape
return x.sum()
Puis a couru :
print df.rolling(1).apply(print_type_sum)
<type 'numpy.ndarray'> (1L,)
<type 'numpy.ndarray'> (1L,)
<type 'numpy.ndarray'> (1L,)
<type 'numpy.ndarray'> (1L,)
<type 'numpy.ndarray'> (1L,)
<type 'numpy.ndarray'> (1L,)
<type 'numpy.ndarray'> (1L,)
<type 'numpy.ndarray'> (1L,)
<type 'numpy.ndarray'> (1L,)
<type 'numpy.ndarray'> (1L,)
A B
0 0.44 0.41
1 0.46 0.47
2 0.46 0.02
3 0.85 0.82
4 0.78 0.76
Mon résultat pd.DataFrame
est le même, c'est bien. Mais ça a imprimé 10 dimensions uniques ndarray
objets. Qu'en est-il rolling(2)
print df.rolling(2).apply(print_type_sum)
<type 'numpy.ndarray'> (2L,)
<type 'numpy.ndarray'> (2L,)
<type 'numpy.ndarray'> (2L,)
<type 'numpy.ndarray'> (2L,)
<type 'numpy.ndarray'> (2L,)
<type 'numpy.ndarray'> (2L,)
<type 'numpy.ndarray'> (2L,)
<type 'numpy.ndarray'> (2L,)
A B
0 NaN NaN
1 0.90 0.88
2 0.92 0.49
3 1.31 0.84
4 1.63 1.58
Même chose, je m'attendais à une sortie mais elle a imprimé 8 ndarray
objets. rolling
produit une image unidimensionnelle ndarray
de longueur window
pour chaque colonne, alors que je m'attendais à ce que ce soit une ndarray
de la forme (window, len(df.columns))
.
La question est : pourquoi ?
Je n'ai maintenant aucun moyen de faire facilement une régression multi-factorielle.