Attribuer des valeurs manquantes catégoriques à scikit-learn

j'ai des données pandas avec des colonnes de type texte. Il y a quelques valeurs de NaN avec ces colonnes de texte. Ce que j'essaie de faire, c'est d'imputer ces NaN à sklearn.preprocessing.Imputer (remplaçant NaN par la valeur la plus fréquente). Le problème est dans la mise en œuvre. Supposons Qu'il existe une base de données Pandas avec 30 colonnes, dont 10 sont de nature catégorique. Une fois que j'ai lancer:

from sklearn.preprocessing import Imputer
imp = Imputer(missing_values='NaN', strategy='most_frequent', axis=0)
imp.fit(df) 

Python génère un error: 'could not convert string to float: 'run1'', où 'run1' est une valeur ordinaire (non manquante) de la première colonne avec données catégoriques.

Toute aide serait la bienvenue

39
demandé sur smci 2014-08-11 13:26:41

6 réponses

pour utiliser les valeurs moyennes pour les colonnes numériques et la valeur la plus fréquente pour les colonnes non numériques, vous pourriez faire quelque chose comme ça. Vous pouvez encore distinguer entre les entiers et les flotteurs. Je suppose qu'il pourrait être logique d'utiliser la médiane pour les colonnes entières à la place.

import pandas as pd
import numpy as np

from sklearn.base import TransformerMixin

class DataFrameImputer(TransformerMixin):

    def __init__(self):
        """Impute missing values.

        Columns of dtype object are imputed with the most frequent value 
        in column.

        Columns of other types are imputed with mean of column.

        """
    def fit(self, X, y=None):

        self.fill = pd.Series([X[c].value_counts().index[0]
            if X[c].dtype == np.dtype('O') else X[c].mean() for c in X],
            index=X.columns)

        return self

    def transform(self, X, y=None):
        return X.fillna(self.fill)

data = [
    ['a', 1, 2],
    ['b', 1, 1],
    ['b', 2, 2],
    [np.nan, np.nan, np.nan]
]

X = pd.DataFrame(data)
xt = DataFrameImputer().fit_transform(X)

print('before...')
print(X)
print('after...')
print(xt)

qui imprime,

before...
     0   1   2
0    a   1   2
1    b   1   1
2    b   2   2
3  NaN NaN NaN
after...
   0         1         2
0  a  1.000000  2.000000
1  b  1.000000  1.000000
2  b  2.000000  2.000000
3  b  1.333333  1.666667
71
répondu sveitser 2014-08-29 15:29:17

Vous pouvez utiliser sklearn_pandas.CategoricalImputer pour les colonnes catégoriques. Détails:

tout D'abord, (du livre Hands-On Machine Learning with Scikit-Learn and TensorFlow) vous pouvez avoir des sous-lignes pour les caractéristiques numériques et string/categorical, où le premier transformateur de chaque sous-ligne est un sélecteur qui prend une liste de noms de colonne (et le full_pipeline.fit_transform() prend une pandas DataFrame):

class DataFrameSelector(BaseEstimator, TransformerMixin):
    def __init__(self, attribute_names):
        self.attribute_names = attribute_names
    def fit(self, X, y=None):
        return self
    def transform(self, X):
        return X[self.attribute_names].values

Vous pouvez ensuite combiner ces sous pipelines sklearn.pipeline.FeatureUnion, pour exemple:

full_pipeline = FeatureUnion(transformer_list=[
    ("num_pipeline", num_pipeline),
    ("cat_pipeline", cat_pipeline)
])

Maintenant, dans le num_pipeline vous pouvez simplement utiliser sklearn.preprocessing.Imputer(), mais dans l' cat_pipline, vous pouvez utiliser CategoricalImputer()sklearn_pandas paquet.

remarque:sklearn-pandas le paquet peut être installé avec pip install sklearn-pandas, mais il est importé comme import sklearn_pandas

4
répondu Austin 2018-01-09 06:51:35

copier et modifier la réponse de sveitser, j'ai fait un emputer pour un pandas.La série de l'objet

import numpy
import pandas 

from sklearn.base import TransformerMixin

class SeriesImputer(TransformerMixin):

    def __init__(self):
        """Impute missing values.

        If the Series is of dtype Object, then impute with the most frequent object.
        If the Series is not of dtype Object, then impute with the mean.  

        """
    def fit(self, X, y=None):
        if   X.dtype == numpy.dtype('O'): self.fill = X.value_counts().index[0]
        else                            : self.fill = X.mean()
        return self

    def transform(self, X, y=None):
       return X.fillna(self.fill)

Pour l'utiliser, il ferait:

# Make a series
s1 = pandas.Series(['k', 'i', 't', 't', 'e', numpy.NaN])


a  = SeriesImputer()   # Initialize the imputer
a.fit(s1)              # Fit the imputer
s2 = a.transform(s1)   # Get a new series
2
répondu user1367204 2017-03-17 15:06:14

ce code remplit une série avec la catégorie la plus fréquente:

import pandas as pd
import numpy as np

# create fake data 
m = pd.Series(list('abca'))
m.iloc[1] = np.nan #artificially introduce nan

print('m = ')
print(m)

#make dummy variables, count and sort descending:
most_common = pd.get_dummies(m).sum().sort_values(ascending=False).index[0] 

def replace_most_common(x):
    if pd.isnull(x):
        return most_common
    else:
        return x

new_m = m.map(replace_most_common) #apply function to original data

print('new_m = ')
print(new_m)

Sorties:

m =
0      a
1    NaN
2      c
3      a
dtype: object

new_m =
0    a
1    a
2    c
3    a
dtype: object
1
répondu scottlittle 2016-07-28 16:32:07

Inspiré par les réponses ici et un goto Imputer pour tous les cas d'utilisation j'ai fini par écrire. Il soutient quatre stratégies pour l'imputation mean, mode, median, fill fonctionne sur les deux pd.DataFrame et Pd.Series.

mean et median fonctionne uniquement pour les données numériques,mode et fill fonctionne à la fois pour les données numériques et catégoriques.

class CustomImputer(BaseEstimator, TransformerMixin):
    def __init__(self, strategy='mean',filler='NA'):
       self.strategy = strategy
       self.fill = filler

    def fit(self, X, y=None):
       if self.strategy in ['mean','median']:
           if not all(X.dtypes == np.number):
               raise ValueError('dtypes mismatch np.number dtype is \
                                 required for '+ self.strategy)
       if self.strategy == 'mean':
           self.fill = X.mean()
       elif self.strategy == 'median':
           self.fill = X.median()
       elif self.strategy == 'mode':
           self.fill = X.mode().iloc[0]
       elif self.strategy == 'fill':
           if type(self.fill) is list and type(X) is pd.DataFrame:
               self.fill = dict([(cname, v) for cname,v in zip(X.columns, self.fill)])
       return self

   def transform(self, X, y=None):
       return X.fillna(self.fill)

utilisation

>> df   
    MasVnrArea  FireplaceQu
Id  
1   196.0   NaN
974 196.0   NaN
21  380.0   Gd
5   350.0   TA
651 NaN     Gd


>> CustomImputer(strategy='mode').fit_transform(df)
MasVnrArea  FireplaceQu
Id      
1   196.0   Gd
974 196.0   Gd
21  380.0   Gd
5   350.0   TA
651 196.0   Gd

>> CustomImputer(strategy='fill', filler=[0, 'NA']).fit_transform(df)
MasVnrArea  FireplaceQu
Id      
1   196.0   NA
974 196.0   NA
21  380.0   Gd
5   350.0   TA
651 0.0     Gd 
1
répondu Gautham Kumaran 2017-11-07 20:58:41

Similaire. Modifier Imputerstrategy='most_frequent':

class GeneralImputer(Imputer):
    def __init__(self, **kwargs):
        Imputer.__init__(self, **kwargs)

    def fit(self, X, y=None):
        if self.strategy == 'most_frequent':
            self.fills = pd.DataFrame(X).mode(axis=0).squeeze()
            self.statistics_ = self.fills.values
            return self
        else:
            return Imputer.fit(self, X, y=y)

    def transform(self, X):
        if hasattr(self, 'fills'):
            return pd.DataFrame(X).fillna(self.fills).values.astype(str)
        else:
            return Imputer.transform(self, X)

pandas.DataFrame.mode() trouve la valeur la plus fréquente pour chaque colonne et ensuite pandas.DataFrame.fillna() remplit des valeurs manquantes. D'autres strategy les valeurs sont toujours traités de la même façon par Imputer.

0
répondu immarried 2017-07-24 07:46:49