web-dev-qa-db-fra.com

Pandas Rolling Apply personnalisé

J'ai suivi une réponse similaire ici , mais j'ai des questions lors de l'utilisation de sklearn et de l'application de roulement. J'essaie de créer des z-scores et de faire de l'APC avec roulement, mais je continue à obtenir 'only length-1 arrays can be converted to Python scalars' error.

En suivant l'exemple précédent, je crée un cadre de données

from sklearn.preprocessing import StandardScaler
import pandas as pd
import numpy as np
sc=StandardScaler() 
tmp=pd.DataFrame(np.random.randn(2000,2)/10000,index=pd.date_range('2001-01-01',periods=2000),columns=['A','B'])

Si j'utilise la commande rolling:

 tmp.rolling(window=5,center=False).apply(lambda x: sc.fit_transform(x))
 TypeError: only length-1 arrays can be converted to Python scalars

Je reçois cette erreur. Je peux cependant créer des fonctions avec des écarts moyens et standard sans problème.

def test(df):
    return np.mean(df)
tmp.rolling(window=5,center=False).apply(lambda x: test(x))

Je crois que l'erreur se produit lorsque j'essaie de soustraire la moyenne des valeurs actuelles du z-score.

def test2(df):
    return df-np.mean(df)
tmp.rolling(window=5,center=False).apply(lambda x: test2(x))
only length-1 arrays can be converted to Python scalars

Comment puis-je créer des fonctions de roulement personnalisées avec sklearn pour d'abord standardiser puis exécuter PCA?

EDIT: Je me rends compte que ma question n'était pas exactement claire, je vais donc réessayer. Je souhaite standardiser mes valeurs, puis exécuter PCA pour obtenir la quantité de variance expliquée par chaque facteur. Faire cela sans rouler est assez simple.

testing=sc.fit_transform(tmp)
pca=decomposition.pca.PCA() #run pca
pca.fit(testing) 
pca.explained_variance_ratio_
array([ 0.50967441,  0.49032559])

Je ne peux pas utiliser cette même procédure lors du roulement. L'utilisation de la fonction de zscore mobile de @piRSquared donne les zscores. Il semble que PCA de sklearn est incompatible avec la fonction personnalisée de roulement. (En fait, je pense que c'est le cas avec la plupart des modules sklearn.) J'essaie simplement d'obtenir la variance expliquée qui est un élément unidimensionnel, mais ce code ci-dessous renvoie un tas de NaN.

def test3(df):
    pca.fit(df)
    return pca.explained_variance_ratio_
tmp.rolling(window=5,center=False).apply(lambda x: test3(x))

Cependant, je peux créer ma propre fonction de variance expliquée, mais cela ne fonctionne pas non plus.

def test4(df):
    cov_mat=np.cov(df.T) #need covariance of features, not observations
    eigen_vals,eigen_vecs=np.linalg.eig(cov_mat)
    tot=sum(eigen_vals)
    var_exp=[(i/tot) for i in sorted(eigen_vals,reverse=True)]
    return var_exp
tmp.rolling(window=5,center=False).apply(lambda x: test4(x))

Je reçois cette erreur 0-dimensional array given. Array must be at least two-dimensional.

Pour récapituler, je voudrais exécuter des z-scores roulants, puis rouler pca produisant la variance expliquée à chaque rouleau. J'ai les z-scores glissants mais la variance non expliquée.

9
Bobe Kryant

Comme l'a commenté @BrenBarn, la fonction de roulement doit réduire un vecteur à un seul nombre. Ce qui suit est équivalent à ce que vous essayez de faire et aide à mettre en évidence le problème.

zscore = lambda x: (x - x.mean()) / x.std()
tmp.rolling(5).apply(zscore)
TypeError: only length-1 arrays can be converted to Python scalars

Dans la fonction zscore, x.mean() réduit, x.std() réduit, mais x est un tableau. Ainsi, le tout est un tableau.


La solution consiste à effectuer le roulement sur les parties du calcul du score z qui l'exigent, et non sur les parties à l'origine du problème.

(tmp - tmp.rolling(5).mean()) / tmp.rolling(5).std()

enter image description here

15
piRSquared