sklearn.preprocessing.OneHotEncoder:使用 drop 和 handle_unknown='ignore'

bla*_*ite 6 python machine-learning scikit-learn

我有一些pandas.Series- s,下面 - 我想进行单热编码。我通过研究发现,'b'级别对于我的预测建模任务并不重要。我可以像这样从我的分析中排除它:

import pandas as pd
from sklearn.preprocessing import OneHotEncoder

s = pd.Series(['a', 'b', 'c']).values.reshape(-1, 1)

enc = OneHotEncoder(drop=['b'], sparse=False, handle_unknown='error')
enc.fit_transform(s)
# array([[1., 0.],
#        [0., 0.],
#        [0., 1.]])
enc.get_feature_names()
# array(['x0_a', 'x0_c'], dtype=object)
Run Code Online (Sandbox Code Playgroud)

但是当我要转换一个新系列时,一个包含两个'b'和一个新级别的系列'd',我收到一个错误:

new_s = pd.Series(['a', 'b', 'c', 'd']).values.reshape(-1, 1)
enc.transform(new_s)
Run Code Online (Sandbox Code Playgroud)

回溯(最近一次调用):文件“”,第 1 行,文件“/Users/user/Documents/assets/envs/data-science/venv/lib/python3.7/site-packages/sklearn/preprocessing/_encoders .py”,第 390 行,在转换 X_int, X_mask = self._transform(X, handle_unknown=self.handle_unknown) 文件“/Users/user/Documents/assets/envs/data-science/venv/lib/python3.7/ site-packages/sklearn/preprocessing/_encoders.py”,第 124 行,在 _transform 中引发 ValueError(msg) ValueError:在转换期间在第 0 列中发现未知类别 ['d']

这是可以预料的,因为我在handle_unknown='error'上面设置。但是,我想完全忽略除['a', 'c']拟合和后续转换步骤之外的所有类。我试过这个:

enc = OneHotEncoder(drop=['b'], sparse=False, handle_unknown='ignore')
enc.fit_transform(s)
enc.transform(new_s)
Run Code Online (Sandbox Code Playgroud)

回溯(最近一次调用):文件“”,第 1 行,文件“/Users/user/Documents/assets/envs/data-science/venv/lib/python3.7/site-packages/sklearn/preprocessing/_encoders .py”,第 371 行,在 fit_transform self._validate_keywords() 文件“/Users/user/Documents/assets/envs/data-science/venv/lib/python3.7/site-packages/sklearn/preprocessing/_encoders.py ", line 289, in _validate_keywords "handle_unknown当 drop 参数为 " ValueError: handle_unknownmust be 'error' when the drop parameter is specified, 因为两者都会创建全为零的类别。

scikit-learn 似乎不支持这种模式。有谁知道一个 scikit-learn-compatible 模式来完成这个任务?

bla*_*ite 1

您还可以使用以下方法来解决此问题:

class IgnorantOneHotEncoder(OneHotEncoder):
    def transform(self, X, y=None):
        try:
            return super().transform(X)
        except ValueError as e:
            if 'Found unknown categories' in str(e):
                X = np.copy(X)
                # Keep track of indices corresponding to unknown categories
                unknown_categories_mask = ~np.isin(X, self.categories_[0]).ravel()
                # Overwrite the unknown categories in the input matrix, X, with the first known category
                X[unknown_categories_mask] = self.categories_[0][0]
                # Transform X, whose categories are all known now
                X = super().transform(X)
                # Overwrite originally unknown-category records with 0 to indicate
                # absence of any value for any category for that feature
                X[unknown_categories_mask, 0] = 0
                return X
            else:
                raise
Run Code Online (Sandbox Code Playgroud)

试试看:

>>> ienc = IgnorantOneHotEncoder(sparse=False)
>>> ienc.fit(s)
IgnorantOneHotEncoder(sparse=False)
>>> ienc.transform(s)
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])
>>> ienc.transform(new_s)
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.],
       [0., 0., 0.]])
Run Code Online (Sandbox Code Playgroud)