首页 > 解决方案 > 为什么 ColumnTransformer 中的 SimpleImputer 会创建额外的列?

问题描述

我正在关注 Aurelion Geron 的机器学习书。

我正在尝试ColumnTransformer上课。当我包含SimplerImputer时,创建了一个额外的列。我知道这SimplerImputer是为了填充列中的缺失值total_bedrooms(结果中的列索引 4),因此我不清楚它为什么要在结果中添加新列(列索引:10)。

当我不包括SimplerImputerfrom ColumnTransformer,但创建一个实例和fit_transform的输出时ColumnTransformer,我不会得到额外的列。请指教。

category_att = X.select_dtypes(include='object').columns
num_att = X.select_dtypes(include='number').columns

transformer = ColumnTransformer(
    [
    ('adder', AttributeAdder(), num_att ),
    ('imputer', SimpleImputer(strategy='median'), ['total_bedrooms']),
    ('ohe', OneHotEncoder(), category_att)
    ],
    remainder = 'passthrough'
)

用于添加两个新功能/列的自定义类

class AttributeAdder(BaseEstimator, TransformerMixin):
    
    def __init__(self, add_bed_room = False):
        self.add_bed_room = add_bed_room
    
    def fit(self,y=None):
        return self
    
    def transform(self,X,y=None):
        
        room_per_household = X.iloc[: , t_room ] / X.iloc[: , t_household ]
        population_per_household = X.iloc[: , t_population ] / X.iloc[: , t_household ]
        return np.c_[X,room_per_household,population_per_household]

结果 在此处输入图像描述

标签: pythonscikit-learn

解决方案


为什么

SimpleImputer完全是;它ColumnTransformer本身。 ColumnTransformer并行应用其转换器,而不是顺序应用(另请参见[1][2]),因此如果一列被传递给多个转换器,您将在输出中多次使用该列。在您的情况下,输出第 4 列来自"adder"on total_bedrooms(它什么也没做,所以仍然有缺失值),输出第 10 列来自"imputer"(因此没有缺失值)。

修复

在这种特殊情况下,两种方法似乎是最简单的。

归咎于一切

任何没有缺失的数字特征都不会受到影响。但是,如果您希望管道对具有缺失值的未来数据出错,请不要这样做。

num_pipe = Pipeline([
    ("add_feat", AttributeAdder()),
    ("impute", SimpleImputer(strategy="median")),
])
transformer = ColumnTransformer(
    [
        ('num', num_pipe, num_att),
        ('cat', OneHotEncoder(), category_att),
    ],
    remainder = 'passthrough',
)

较小的变压器柱组

由于您实际上并不需要您的total_bedrooms列,AttributeAdder因此您无需将其传递到该变压器中。具体情况取决于您如何使用t_rooms,t_households等,但通常:

transformer = ColumnTransformer(
    [
        ('adder', AttributeAdder(), [["total_rooms", "households", "population"]]),
        ('imputer', SimpleImputer(strategy='median'), ['total_bedrooms']),
        ('ohe', OneHotEncoder(), category_att)
    ],
    remainder = 'passthrough'  # now you're relying on this one much more
)

在相关方法中,您可以更灵活地计算添加的特征。更改您以AttributeAdder返回新功能(不要在 的最后一步中连接),并依靠来传递这些功能。(请注意,我们不能依赖这些,但我们可以将其用作变压器之一。)XtransformColumnTransformerremainder"passthrough"

class AttributeAdder(BaseEstimator, TransformerMixin):
    ...
    def transform(self,X,y=None):
        ...
        return np.c_[room_per_household,population_per_household]


transformer = ColumnTransformer(
    [
        ('adder', AttributeAdder(), num_att),
        ('num', "passthrough", num_att.drop(['total_bedrooms'])),
        ('imputer', SimpleImputer(strategy='median'), ['total_bedrooms']),
        ('ohe', OneHotEncoder(), category_att)
    ],
    passthrough=True,  # if you have columns in neither of num_att and category_att that you want kept
)

推荐阅读