web-dev-qa-db-fra.com

Imputation de données avec fancyimpute et pandas

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?

Mise à jour

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?

13
Rachel
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.

2
NicolasWoloszko

Ajoutez les lignes suivantes après votre code:

df_filled.columns = df_numeric.columns
df_filled.index = df_numeric.index
6
Miriam Farber

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)

4
jander081

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

2
Beau Hilton