Python 在scikit学习中输入类别缺失值

Python 在scikit学习中输入类别缺失值,python,pandas,scikit-learn,imputation,Python,Pandas,Scikit Learn,Imputation,我有一些文本类型的列的数据。这些文本列中有一些NaN值。我想做的是通过sklearn.preprocessing.Imputer(用最频繁的值替换NaN)来插补这些NaN。问题在执行中。 假设有一个包含30列的熊猫数据帧df,其中10列属于分类性质。 一旦我跑步: from sklearn.preprocessing import Imputer imp = Imputer(missing_values='NaN', strategy='most_frequent', axis=0) imp.f

我有一些文本类型的列的数据。这些文本列中有一些NaN值。我想做的是通过
sklearn.preprocessing.Imputer
(用最频繁的值替换NaN)来插补这些NaN。问题在执行中。 假设有一个包含30列的熊猫数据帧df,其中10列属于分类性质。 一旦我跑步:

from sklearn.preprocessing import Imputer
imp = Imputer(missing_values='NaN', strategy='most_frequent', axis=0)
imp.fit(df) 
Python生成一个
错误:“无法将字符串转换为float:“run1”
,其中“run1”是第一列中包含分类数据的普通(非缺失)值

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)

非常欢迎任何帮助

为数字列使用平均值,为非数字列使用最频繁的值,您可以这样做。您可以进一步区分整数和浮点数。我想对整型列使用中位数可能是有意义的

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

此代码以最常见的类别填充系列:

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

复制和修改斯维瑟的答案,我为熊猫系列对象做了一个插补器

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

类似的。修改
策略class='most_frequency'
输入器

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()
用这些值填充缺少的值。其他
策略
值仍然由
插补器

以同样的方式处理,灵感来自这里的答案,并且为了所有用例都需要一个goto插补器,我最后写了这篇文章。它支持四种插补策略
mean、mode、median、fill
适用于
pd.DataFrame
pd.Series

平均值
中值
仅适用于数字数据,
模式
填充
适用于数字和分类数据

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 

您可以使用
sklearn\u pandas.categoricalComputer
进行分类列。详情:

首先,(来自《使用Scikit Learn和TensorFlow进行机器学习》一书),您可以为数字和字符串/分类功能创建子管道,其中每个子管道的第一个转换器是一个选择器,它获取列名称列表(并且
full\u pipeline.fit\u transform()
获取一个数据帧):

然后,您可以将这些子管道与
sklearn.pipeline.FeatureUnion
组合,例如:

full_pipeline = FeatureUnion(transformer_list=[
    ("num_pipeline", num_pipeline),
    ("cat_pipeline", cat_pipeline)
])
现在,在
num_管道
中,您可以简单地使用
sklearn.preprocessing.inputer()
,但在
cat_管道
中,您可以从
sklearn_
包中使用
categoricalcomputer()

注意:
sklearn pandas
软件包可以与
pip安装sklearn pandas
一起安装,但它是作为
import sklearn\u pandas
导入的
  • strategy='most_frequency'只能用于定量特征,不能用于定性特征。此自定义输入器可用于定性和定量输入。同样,使用scikit学习插补器,我们可以将其用于整个数据帧(如果所有特征都是定量的),也可以将“for loop”用于类似类型特征/列的列表(参见下面的示例)。但自定义插补器可用于任何组合

        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)
    
  • 可与策略=中间值一起使用

     sd = CustomImputer(['quantitative_column'], strategy = 'median')
     sd.fit_transform(X)
    
  • 3) 可用于整个数据框架,它将使用默认平均值(或者我们也可以使用中值进行更改。对于定性特征,它使用策略=“最频繁”,对于定量平均值/中值

     call = CustomImputer()
     call.fit_transform(X)   
    

  • 有一个包
    sk
    ,它可以选择对分类变量进行插补


    您可以尝试以下方法:

    replace = df.<yourcolumn>.value_counts().argmax()
    
    df['<yourcolumn>'].fillna(replace, inplace=True) 
    
    
    replace=df..value_counts().argmax()
    df['').fillna(替换,就地=真)
    
    sklearn.impute.SimpleImputer代替Imputer可以很容易地解决这个问题,它可以处理分类变量

    根据Sklearn文档: 如果为“最频繁”,则使用每列最频繁的值替换缺失。可用于字符串或数字数据


    inputer
    处理数字,而不是字符串。转换为数字,然后输入,然后再转换回来。有没有合适的方法通过scikit learn将其自动化?为什么它不允许对最常用的策略使用分类变量?奇怪。您现在可以从sklearn.inpute导入SimpleInputer然后使用
    imp=SimpleInputer(missing_values=np.nan,strategy='most_frequency')
    做得很好。我将在:)中使用您的代码片段。如果您有任何进一步的建议,我很乐意听到。这很好,但是如果任何列都有所有的nan值,它将不起作用。这些所有的nan列都应该从DF中删除。很好:)我将使用它,但将其稍作修改,使其在GridSearchCV中使用时,对浮点使用均值,对整数使用中值,字符串的模式
    DataFrameInputer()不具有get_params()属性。修复方法是从
    sklearn.base.BaseEstimator
    继承。@mamun类提供了
    fit\u transform
    方法。我支持这个答案;pypi网站上的官方sklearn pandas文档提到了这一点:“分类计算机由于scikit learn输入转换器目前仅适用于数字,因此sklearn pandas提供了一个等效的辅助转换器,可以处理字符串,用该列中最频繁的值替换空值。”这是包裹上的。
    replace = df.<yourcolumn>.value_counts().argmax()
    
    df['<yourcolumn>'].fillna(replace, inplace=True) 
    
    
    impute_size=SimpleImputer(strategy="most_frequent") 
    data['Outlet_Size']=impute_size.transform(data[['Outlet_Size']])