一个热编码训练,其值在测试中不存在



>我有一个存储为数据帧的训练和测试集。我正在尝试对我的数据集上的名义特征进行一热编码。但我有以下问题:

  1. 总共有 3 个分类特征,但我不知道每个特征的值是多少,因为数据集很大。
  2. 测试集具有训练集中不存在的值,因此当我进行独热编码时,训练集应将不可见值的向量标记为 0。但正如我在 1 中提到的,我不知道所有功能。
  3. 发现我可以使用df = pd.get_dummies(df, prefix_sep='_')进行一个热编码,该命令适用于所有分类特征,但我注意到它将新功能移动到训练 DataFrame 的末尾,我认为这是一个问题,因为我们不知道哪个功能的索引。还有问题 2,新火车/集应该具有相同的索引。

有没有自动化的方法可以做到这一点?或者图书馆?

编辑

多亏了下面的答案,我才能对许多功能执行一种热编码。但是下面的代码给出了以下问题:

  1. 我认为scikit-learn剥离列标题并将结果生成为数组而不是数据帧
  2. 由于特征被条带走,我们不知道哪个向量属于哪个特征。即使我执行df_scaled = pd.DataFrame(ct.fit_transform(data2))将结果存储在数据帧中,创建的数据帧df_scaled也没有标头,尤其是当标头现在在预处理后发生更改时。也许sklearn.preprocessing.OneHotEncoder有一种跟踪新功能及其索引的方法?

不要使用pd.get_dummies,它具有您确定的缺点,请使用sklearn.preprocessing.OneHotEncoder。它会自动从训练数据中获取所有标称类别,然后根据训练步骤中确定的类别对测试数据进行编码。如果测试数据中有新类别,它只会将您的数据编码为 0。

例:

from sklearn.preprocessing import OneHotEncoder
import numpy as np
x_train = np.array([["A1","B1","C1"],["A2","B1","C2"]])
x_test = np.array([["A1","B2","C2"]]) # As you can see, "B2" is a new attribute for column B
ohe = OneHotEncoder(handle_unknown = 'ignore') #ignore tells the encoder to ignore new categories by encoding them with 0's
ohe.fit(x_train)
print(ohe.transform(x_train).toarray())
>>> array([[1., 0., 1., 1., 0.],
[0., 1., 1., 0., 1.]])

要按列获取训练集中类别的摘要,请执行以下操作:

print(ohe.categories_)
>>> [array(['A1', 'A2'], dtype='<U2'), 
array(['B1'], dtype='<U2'), 
array(['C1', 'C2'], dtype='<U2')]

要将一个热编码列映射到类别,请执行以下操作:

print(ohe.get_feature_names())
>>> ['x0_A1' 'x0_A2' 'x1_B1' 'x2_C1' 'x2_C2']

最后,这是编码器在新测试数据上的工作方式:

print(ohe.transform(x_test).toarray())
>>> [[1. 0. 0. 0. 1.]] # 1 for A1, 0 for A2, 0 for B1, 0 for C1, 1 for C2

编辑

您似乎担心在进行编码后丢失标签。实际上很容易回到这些,只需将答案包装在数据框中并从ohe.get_feature_names()中指定列名:

pd.DataFrame(ohe.transform(x_test).toarray(), columns = ohe.get_feature_names())

pd.get_dummies应该以一种允许您分辨哪些列与每个分类特征匹配的方式命名新列。如果要为其提供一组要使用的自定义前缀,可以使用prefix参数。然后,您可以查看列列表以查看与每个功能对应的所有列。(您不需要prefix_sep='_',这是默认值。

df = pd.get_dummies(df, prefix=['first_feature', 'second_feature', 'third_feature']
first_feature_column_names = [c for c in df.columns if c.startswith('first_feature_')]

您还可以一次对一个分类特征执行独热编码,如果这有助于您了解每个特征的列。

df = pd.get_dummies(df, columns=['first_feature'])

至于某些标签仅存在于测试集或训练集中的问题:如果df包含训练集和测试集(并且您打算稍后使用类似sklearn.model_selection.train_test_split的内容将它们分开(,那么仅存在于测试集中的任何特征都将在训练集中有一个全零列。显然,这实际上不会为您的模型提供任何价值,但它会使您的列索引保持一致。但是,使用单热列实际上没有意义,其中任何训练数据在该特征中都没有非零值 - 它对您的模型没有影响。您可以使用sklearn.preprocessing.OneHotEncoder避免训练和测试之间的错误和不一致的列索引。

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import Normalizer
ct = ColumnTransformer([
("onehot", OneHotEncoder(handle_unknown='ignore'), ['first_feature', 'second_feature', 'third_feature']),
], remainder='passthrough')
df_train = ct.fit_transform(df_train)
df_test = ct.transform(df_test)
# Or simply
df = ct.fit_transform(df)

handle_unknown告诉它忽略(而不是抛出错误(初始训练集中不存在的任何值。

最新更新