缺少类别的单热编码

Posted

技术标签:

【中文标题】缺少类别的单热编码【英文标题】:One-hot-encoding with missing categories 【发布时间】:2018-07-31 04:27:32 【问题描述】:

我有一个包含类别列的数据集。为了使用线性回归,我对这一列进行了 1-hot 编码。

我的集合有 10 列,包括类别列。删除该列并附加 1-hot 编码矩阵后,我最终得到 14 列 (10 - 1 + 5)。

所以我用形状为 (n, 14) 的矩阵训练(拟合)我的 LinearRegression 模型。

在训练之后,我想在训练集的一个子集上对其进行测试,所以我先只取 5 个,然后将它们通过相同的管道。但是这 5 个首先只包含 3 个类别。因此,在通过管道之后,我只剩下一个形状为 (n, 13) 的矩阵,因为它缺少 2 个类别。

如何强制 1-hot 编码器使用 5 个类别?

我正在使用来自 sklearn 的 LabelBinarizer。

【问题讨论】:

您应该只对新数据使用 LabelBinarizer.transform()。永远不适合()。显示代码,我们将根据需要对其进行修改。 就是这样@VivekKumar - 一旦安装了变压器(在本例中为 LabelBinarizer),就不应重新安装。谢谢! 【参考方案1】:

错误是“将测试数据通过同一管道”。基本上我在做:

data_prepared = full_pipeline.fit_transform(train_set)

lin_reg = LinearRegression()
lin_reg.fit(data_prepared, labels)

some_data = train_set.iloc[:5]
some_data_prepared = full_pipeline.fit_transform(some_data)

lin_reg.predict(some_data_prepared)
# => error because mismatching shapes

有问题的行是:

some_data_prepared = full_pipeline.fit_transform(some_data)

通过执行fit_transform,我会将 LabelBinarizer 安装到仅包含 3 个标签的集合中。相反,我应该这样做:

some_data_prepared = full_pipeline.transform(some_data)

这样我就使用了全套(train_set)安装的管道,并以相同的方式对其进行转换。

谢谢@Vivek Kumar

【讨论】:

【参考方案2】:

我遇到了这个问题,通过scikit-learn找不到解决办法。

我正在使用 pandas .get_dummies() 做类似于 OneHotEncoder 的事情。

下面是我为处理这个确切问题而制作的一个函数,请随意使用并改进它(如果您发现任何错误,请告诉我,实际上我只是从一个更具体的函数中制作的在我的代码库中)

import numpy as np
import pandas as pd

def one_hot_encoding_fixed_columns(pandas_series, fixed_columns):

    # Creates complete fixed columns list (with nan and 'other')
    fixed_columns = list(fixed_columns)
    fixed_columns.extend([np.nan, 'other'])

    # Get dummies dataset
    ohe_df = pd.get_dummies(pandas_series, dummy_na=True)

    # Create blank 'other' column
    ohe_df['other'] = 0

    # Check if columns created by get_dummies() are in 'fixed_columns' list.
    for column in ohe_df.columns:

        if column not in fixed_columns:
            # If not in 'fixed_columns', transforms exceeding column into 'other'.
            ohe_df['other'] = ohe_df['other'] + ohe_df[column]
            ohe_df.drop(columns=[column])

    # Check if elements in 'fixed_columns' are in the df generated by get_dummies()
    for column in fixed_columns:

        if column not in ohe_df.columns:
            # If the element is not present, create a new column with all values set to 0.
            ohe_df['column'] = 0

    # Reorders columns according to fixed columns
    ohe_df = ohe_df[fixed_columns]

    return ohe_df

基本上,您可以创建一个包含将始终使用的列的列表。如果test 样本没有给定类别的任何元素,则会创建具有values = 0 的对应列。如果test 具有不在train 样本中的新值,则将其归类为other

我已将代码注释掉,希望它可以理解,如果您有任何问题,请告诉我,我会澄清它。

此函数的输入是pandas_series = df['column_name'],您可以在训练集上执行fixed_columns = df[selected_column].str[0].value_counts().index.values 之类的操作,以生成也将用于测试集的值。

【讨论】:

【参考方案3】:

基本上,首先我们需要对基础数据应用 fit_transform,然后对样本数据应用变换,因此样本数据也将获得与基础数据相对应的确切列数。

【讨论】:

以上是关于缺少类别的单热编码的主要内容,如果未能解决你的问题,请参考以下文章

使用单热编码处理sklearn中的分类变量

熊猫单热编码列到假人,包括“其他”编码[重复]

python 提取单热编码向量。

如何在单热编码中修复“索引 3 超出轴 1 大小为 3 的范围”? [复制]

“特征重要性”的“单热编码”变量的显示名称

pd.get_dummies 是单热编码吗?