web-dev-qa-db-ja.com

scikit-learnでカテゴリの欠損値を代入する

pandasテキストタイプのいくつかの列を持つデータがあります。これらのテキスト列と一緒にいくつかのNaN値があります。私がやろうとしているのは、sklearn.preprocessing.Imputer(NaNを最も頻度の高い値に置き換えます。問題は実装にあります。Pandas 30列のデータフレームdfがあり、そのうち10がカテゴリの性質です。実行したら:

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

Pythonはerror: 'could not convert string to float: 'run1''を生成します。ここで、「run1」は、カテゴリデータを含む最初の列からの通常の(欠損がない)値です。

どんな助けでも大歓迎です

50
night_bat

数値列に平均値を使用し、非数値列に最も頻繁に使用する値を使用するには、次のようにします。整数と浮動小数点をさらに区別できます。代わりに整数列の中央値を使用するのが理にかなっていると思います。

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)

印刷する、

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

カテゴリー列には_sklearn_pandas.CategoricalImputer_を使用できます。詳細:

まず、(Scikit-LearnおよびTensorFlowを使用したハンズオン機械学習の書籍から)数値および文字列/カテゴリの機能のサブパイプラインを使用できます。各サブパイプラインの最初のトランスフォーマーは、列名のリスト(およびfull_pipeline.fit_transform()は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
_

次に、これらのサブパイプラインを_sklearn.pipeline.FeatureUnion_と組み合わせることができます。次に例を示します。

_full_pipeline = FeatureUnion(transformer_list=[
    ("num_pipeline", num_pipeline),
    ("cat_pipeline", cat_pipeline)
])
_

現在、_num_pipeline_ではsklearn.preprocessing.Imputer()を使用できますが、_cat_pipline_では、_sklearn_pandas_パッケージのCategoricalImputer()を使用できます。

注: _sklearn-pandas_パッケージは_pip install sklearn-pandas_でインストールできますが、_import sklearn_pandas_としてインポートされます

7
Austin

Sveitserの答えをコピーして変更し、pandas.Seriesオブジェクトのimputerを作成しました

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)

それを使用するには、次のようにします。

# 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
3
user1367204

パッケージがありますsklearn-pandasカテゴリ変数の代入のオプションがあります 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)
3
prashanth

ここでの答えに触発され、すべてのユースケースでgoto Imputerが必要であるため、私はこれを書きました。代入の4つの戦略mean, mode, median, fillは両方で機能しますpd.DataFrameおよびPd.Series

meanおよびmedianは数値データに対してのみ機能し、modeおよびfillは数値データとカテゴリデータの両方に対して機能します。

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)

使用法

>> 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
  • strategy = 'most_frequent'は、定性的ではなく、定量的機能でのみ使用できます。このカスタムインピュアは、定性的および定量的の両方に使用できます。また、scikit学習インプターでは、データフレーム全体に使用するか(すべての機能が定量的である場合)、または類似タイプの機能/列のリストで「forループ」を使用できます(以下の例を参照)。ただし、カスタム入力は任意の組み合わせで使用できます。

        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]])
    
  • カスタム入力:

       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
    
  • データフレーム:

          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)同様のタイプの機能のリストで使用できます。

     cci = CustomImputer(cols=['city', 'boolean']) # here default strategy = mean
     cci.fit_transform(X)
    
  • strategy = medianで使用できます

     sd = CustomImputer(['quantitative_column'], strategy = 'median')
     sd.fit_transform(X)
    
  • 3)データフレーム全体で使用できます。デフォルトの平均値を使用します(または中央値で変更することもできます。定性的な機能の場合はstrategy = 'most_frequent'を使用し、定量的な平均値/中央値を使用します。

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

このコードは、最も頻繁なカテゴリでシリーズを埋めます:

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)

出力:

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

同様。 _strategy='most_frequent'_のImputerを変更します。

_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()は各列の最も頻繁な値を見つけ、pandas.DataFrame.fillna()は欠損値をこれらの値で埋めます。他のstrategy値は、Imputerによって引き続き同じ方法で処理されます。

0
immarried