>我有一个存储为数据帧的训练和测试集。我正在尝试对我的数据集上的名义特征进行一热编码。但我有以下问题:
- 总共有 3 个分类特征,但我不知道每个特征的值是多少,因为数据集很大。
- 测试集具有训练集中不存在的值,因此当我进行独热编码时,训练集应将不可见值的向量标记为 0。但正如我在 1 中提到的,我不知道所有功能。 我
- 发现我可以使用
df = pd.get_dummies(df, prefix_sep='_')
进行一个热编码,该命令适用于所有分类特征,但我注意到它将新功能移动到训练 DataFrame 的末尾,我认为这是一个问题,因为我们不知道哪个功能的索引。还有问题 2,新火车/集应该具有相同的索引。
有没有自动化的方法可以做到这一点?或者图书馆?
编辑
多亏了下面的答案,我才能对许多功能执行一种热编码。但是下面的代码给出了以下问题:
- 我认为
scikit-learn
剥离列标题并将结果生成为数组而不是数据帧 - 由于特征被条带走,我们不知道哪个向量属于哪个特征。即使我执行
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
告诉它忽略(而不是抛出错误(初始训练集中不存在的任何值。