webentwicklung-frage-antwort-db.com.de

Erzwingen Sie kategoriale fehlende Werte in Scikit-Learn

Ich habe Pandas-Daten mit einigen Textspalten erhalten. Neben diesen Textspalten gibt es einige NaN-Werte. Was ich versuche zu tun, ist, diese NaNs durch sklearn.preprocessing.Imputer zu unterstellen (wobei NaN durch den häufigsten Wert ersetzt wird). Das Problem ist in der Implementierung . Angenommen, es gibt einen Pandas-Datenrahmen df mit 30 Spalten, von denen 10 kategorialer Natur sind.

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

Python generiert einen error: 'could not convert string to float: 'run1'', wobei 'run1' ein gewöhnlicher (nicht fehlender) Wert aus der ersten Spalte mit kategorialen Daten ist.

Jede Hilfe wäre sehr willkommen

44
night_bat

Um Mittelwerte für numerische Spalten und den häufigsten Wert für nicht numerische Spalten zu verwenden, können Sie so etwas tun. Sie können weiter zwischen Ganzzahlen und Floats unterscheiden. Ich denke, es könnte sinnvoll sein, stattdessen den Median für ganzzahlige Spalten zu verwenden.

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)

welche druckt,

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
77
sveitser

Sie können sklearn_pandas.CategoricalImputer für die Kategoriespalten verwenden. Einzelheiten:

Erstens können Sie (aus dem Buch Hands-On Machine Learning mit Scikit-Learn und TensorFlow) über Unterpipelines für numerische und string-/kategoriale Funktionen verfügen, wobei der erste Transformator jeder Unterpipeline ein Selektor ist, der eine Liste von Spaltennamen (und die full_pipeline.fit_transform() nimmt) ein 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

Sie können diese Subpipelines dann mit sklearn.pipeline.FeatureUnion kombinieren, zum Beispiel:

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

In num_pipeline können Sie einfach sklearn.preprocessing.Imputer() verwenden, aber in cat_pipline können Sie CategoricalImputer() aus dem sklearn_pandas-Paket verwenden.

Hinweis: sklearn-pandas-Paket kann mit pip install sklearn-pandas installiert werden, es wird jedoch als import sklearn_pandas importiert.

4
Austin

Inspiriert durch die Antworten hier und für das Fehlen eines Umgangs mit Imputer für alle Anwendungsfälle, schrieb ich das hier. Es unterstützt vier Strategien für die Imputation, wobei mean, mode, median, fill sowohl für pd.DataFrame als auch für Pd.Series funktioniert.

mean und median funktionieren nur für numerische Daten, mode und fill für numerische und kategoriale Daten.

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)

verwendungszweck 

>> 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 
2
Gautham Kumaran

Ich kopierte und modifizierte die Antwort von sveitser

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)

Um es zu benutzen, würden Sie folgendes tun:

# 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
user1367204
  • strategy = 'most_frequent' kann nur mit quantitativen Merkmalen verwendet werden, nicht mit qualitativen. Dieser kundenspezifische Impuer kann sowohl qualitativ als auch quantitativ verwendet werden. Auch mit scikit learn imputer können wir es entweder für den gesamten Datenrahmen verwenden (wenn alle Features quantitativ sind) oder wir können 'for loop' mit einer Liste ähnlicher Typen von Features/Spalten verwenden (siehe das folgende Beispiel). Custom Imputer kann jedoch mit beliebigen Kombinationen verwendet werden.

        from sklearn.preprocessing import Imputer
        impute = Imputer(strategy='mean')
        for cols in ['quantitative_column', 'quant']:  # here both are quantitative features.
              xx[cols] = impute.fit_transform(xx[[cols]])
    
  • Benutzerdefinierte Betrüger: 

       from sklearn.preprocessing import Imputer
       from sklearn.base import TransformerMixin
    
       class CustomImputer(TransformerMixin):
             def __init__(self, cols=None, strategy='mean'):
                   self.cols = cols
                   self.strategy = strategy
    
             def transform(self, df):
                   X = df.copy()
                   impute = Imputer(strategy=self.strategy)
                   if self.cols == None:
                          self.cols = list(X.columns)
                   for col in self.cols:
                          if X[col].dtype == np.dtype('O') : 
                                 X[col].fillna(X[col].value_counts().index[0], inplace=True)
                          else : X[col] = impute.fit_transform(X[[col]])
    
                   return X
    
             def fit(self, *_):
                   return self
    
  • Datenrahmen:

          X = pd.DataFrame({'city':['tokyo', np.NaN, 'london', 'seattle', 'san 
                                     francisco', 'tokyo'], 
              'boolean':['yes', 'no', np.NaN, 'no', 'no', 'yes'], 
              'ordinal_column':['somewhat like', 'like', 'somewhat like', 'like', 
                                'somewhat like', 'dislike'], 
              'quantitative_column':[1, 11, -.5, 10, np.NaN, 20]})
    
    
                city              boolean   ordinal_column  quantitative_column
            0   tokyo             yes       somewhat like   1.0
            1   NaN               no        like            11.0
            2   london            NaN       somewhat like   -0.5
            3   seattle           no        like            10.0
            4   san francisco     no        somewhat like   NaN
            5   tokyo             yes       dislike         20.0
    
  • 1) Kann mit einer Liste ähnlicher Art von Funktionen verwendet werden.

     cci = CustomImputer(cols=['city', 'boolean']) # here default strategy = mean
     cci.fit_transform(X)
    
  • kann mit Strategie = Median verwendet werden

     sd = CustomImputer(['quantitative_column'], strategy = 'median')
     sd.fit_transform(X)
    
  • 3) Kann mit dem gesamten Datenrahmen verwendet werden, er verwendet den voreingestellten Mittelwert (oder wir können ihn auch mit dem Median ändern. Für qualitative Merkmale wird die Strategie = 'most_frequent' und für den quantitativen Mittelwert/Median verwendet.

     call = CustomImputer()
     call.fit_transform(X)   
    
2
Piyush

Dieser Code füllt eine Reihe mit der häufigsten Kategorie aus:

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)

Ausgänge:

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

new_m =
0    a
1    a
2    c
3    a
dtype: object
1
scottlittle

Es gibt ein Paket sklearn-pandas, das eine Option zur Imputation für die kategoriale Variable enthält https://github.com/scikit-learn-contrib/sklearn-pandas#categoricalimputer

>>> from sklearn_pandas import CategoricalImputer
>>> data = np.array(['a', 'b', 'b', np.nan], dtype=object)
>>> imputer = CategoricalImputer()
>>> imputer.fit_transform(data)
array(['a', 'b', 'b', 'b'], dtype=object)
0
prashanth

Ähnlich. Ändern Sie Imputer für strategy='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)

dabei findet pandas.DataFrame.mode() den häufigsten Wert für jede Spalte und füllt dann mit pandas.DataFrame.fillna() fehlende Werte auf. Andere strategy-Werte werden von Imputer immer noch genauso behandelt.

0
immarried