J'ai un grand pandas renommée des données df
. Il y a pas mal de manques. Il n'est pas possible de laisser des lignes/ou des couleurs. Imputant des médianes, des moyennes ou les plus fréquentes valeurs n'est pas une option non plus (d'où l'imputation avec pandas
et/ou scikit
malheureusement ne fait pas l'affaire).
Je suis tombé sur ce qui semble être un paquet soigné appelé fancyimpute
(vous pouvez le trouver ici ). Mais j'ai quelques problèmes avec ça.
Voici ce que je fais:
#the neccesary imports
import pandas as pd
import numpy as np
from fancyimpute import KNN
# df is my data frame with the missings. I keep only floats
df_numeric = = df.select_dtypes(include=[np.float])
# I now run fancyimpute KNN,
# it returns a np.array which I store as a pandas dataframe
df_filled = pd.DataFrame(KNN(3).complete(df_numeric))
Cependant, df_filled
Est en quelque sorte un vecteur unique, au lieu du bloc de données rempli. Comment saisir la trame de données avec des imputations?
J'ai réalisé que fancyimpute
a besoin d'un numpay array
. J'ai donc converti le df_numeric
En un tableau en utilisant as_matrix()
.
# df is my data frame with the missings. I keep only floats
df_numeric = df.select_dtypes(include=[np.float]).as_matrix()
# I now run fancyimpute KNN,
# it returns a np.array which I store as a pandas dataframe
df_filled = pd.DataFrame(KNN(3).complete(df_numeric))
La sortie est une trame de données avec les étiquettes de colonne manquantes. Une façon de récupérer les étiquettes?
df=pd.DataFrame(data=mice.complete(d), columns=d.columns, index=d.index)
Le np.array
Renvoyé par la méthode .complete()
de l'objet fantaisie (qu'il s'agisse de souris ou de KNN) est alimenté en tant que contenu (argument data=)
D'un pandas dataframe dont les cols et les index sont les mêmes que le data frame d'origine.
Ajoutez les lignes suivantes après votre code:
df_filled.columns = df_numeric.columns
df_filled.index = df_numeric.index
Je vois la frustration de l'imputation fantaisiste et des pandas. Voici un wrapper assez basique utilisant la méthode de remplacement récursif. Prend et délivre une trame de données - les noms des colonnes sont intacts. Ces types d'enveloppes fonctionnent bien avec les pipelines.
from fancyimpute import SoftImpute
class SoftImputeDf(SoftImpute):
"""DataFrame Wrapper around SoftImpute"""
def __init__(self, shrinkage_value=None, convergence_threshold=0.001,
max_iters=100,max_rank=None,n_power_iterations=1,init_fill_method="zero",
min_value=None,max_value=None,normalizer=None,verbose=True):
super(SoftImputeDf, self).__init__(shrinkage_value=shrinkage_value,
convergence_threshold=convergence_threshold,
max_iters=max_iters,max_rank=max_rank,
n_power_iterations=n_power_iterations,
init_fill_method=init_fill_method,
min_value=min_value,max_value=max_value,
normalizer=normalizer,verbose=False)
def fit_transform(self, X, y=None):
assert isinstance(X, pd.DataFrame), "Must be pandas dframe"
for col in X.columns:
if X[col].isnull().sum() < 10:
X[col].fillna(0.0, inplace=True)
z = super(SoftImputeDf, self).fit_transform(X.values)
return pd.DataFrame(z, index=X.index, columns=X.columns)
J'apprécie vraiment l'approche de @ jander081, et je l'ai développée un peu pour gérer la définition de colonnes catégorielles. J'ai eu un problème où les colonnes catégorielles se désélectionnaient et créaient des erreurs pendant la formation, j'ai donc modifié le code comme suit:
from fancyimpute import SoftImpute
import pandas as pd
class SoftImputeDf(SoftImpute):
"""DataFrame Wrapper around SoftImpute"""
def __init__(self, shrinkage_value=None, convergence_threshold=0.001,
max_iters=100,max_rank=None,n_power_iterations=1,init_fill_method="zero",
min_value=None,max_value=None,normalizer=None,verbose=True):
super(SoftImputeDf, self).__init__(shrinkage_value=shrinkage_value,
convergence_threshold=convergence_threshold,
max_iters=max_iters,max_rank=max_rank,
n_power_iterations=n_power_iterations,
init_fill_method=init_fill_method,
min_value=min_value,max_value=max_value,
normalizer=normalizer,verbose=False)
def fit_transform(self, X, y=None):
assert isinstance(X, pd.DataFrame), "Must be pandas dframe"
for col in X.columns:
if X[col].isnull().sum() < 10:
X[col].fillna(0.0, inplace=True)
z = super(SoftImputeDf, self).fit_transform(X.values)
df = pd.DataFrame(z, index=X.index, columns=X.columns)
cats = list(X.select_dtypes(include='category'))
df[cats] = df[cats].astype('category')
# return pd.DataFrame(z, index=X.index, columns=X.columns)
return df