训练与测试中不同数量的特征

数据挖掘 Python 熊猫 分类数据
2021-09-28 08:38:19

我在 kaggle 上做泰坦尼克号练习,有一个分类 Cabin 属性,它有很多不同的字符串:C41、C11、B20 等(大约 100 个)。

为了能够训练我的模型,我将其转换为数字属性(使用 pandas get_dummies())。所以最后我得到了100多个属性。

然而,在测试数据集上,小屋更少,所以我最终会得到更少的属性。

我做了这样的事情来使它们相等(创建训练集中的列并删除那些不在训练集中的列):

for column in X.columns:
    if column not in X_test.columns:
        X_test[column] = 0

for column in X_test.columns:
    if column not in X.columns:
        X_test.drop([column], axis=1, inplace=True)

但我知道这不是一件好事。那么我还应该如何处理呢?

我尝试完全移除机舱列,但我的模型在该列的测试数据上表现更好。

4个回答

尽管@Jekaterina Kokatjuhha 的回答被接受,但我完全不同意它的建议。在创建管道时,您永远不应该使用您的测试集。从技术上讲,在您的管道完成之前,您不知道您的测试集是什么。

你原来的方法是正确的。

为了使过程不那么复杂,我建议使用scikit-learn 的 OneHotEncoder而不是pd.get_dummies. 当您在训练数据上安装编码器时,它将跟踪要创建的虚拟对象。在你的情况下,这是你训练集中的所有小屋。这意味着当您将编码器应用于测试数据时,它将创建与训练数据相同数量的列。如果您的测试数据包含训练数据中不存在的小屋,它将被简单地忽略。handle_unknown您还可以选择通过将参数设置为来引发错误"error"

您可以连接您的训练和测试数据集,创建虚拟变量,然后将它们分开数据集。

像这样的东西:

train_objs_num = len(train)
dataset = pd.concat(objs=[train, test], axis=0)
dataset = pd.get_dummies(dataset)
train = copy.copy(dataset[:train_objs_num])
test = copy.copy(dataset[train_objs_num:])

正如@Valentin Calomme 所提到的,正确的方法是使用 scikit learn 的一种热编码方法。合并训练和测试数据无益的原因是,当您将模型投入生产然后突然映射更改并最终导致模型失败时,这种方法会失败。

按照以下实现该方法的端到端实现:

import pandas as pd
import pickle
from sklearn.preprocessing import OneHotEncoding

df_trn = pd.read_csv('train.csv')

# You can use other methods to remove nan records
df_trn.dropna(axis=0, inplace=True)

# Always perform following step on training records
cabin_onehot = OneHotEncoder()
cabin_arr = cabin_onehot.fit_transform(df_trn.loc[:, ['Cabin']]).toarray()

# Save this onehot encoding object for reuse purpose
with open('cb.pkl', 'wb') as f:
    pickle.dump(cabin_onehot, f)

# Write code to merge df_trn & cabin_arr
...

# Now let's apply same technique on test records
df_test = df.read_csv('test.csv')

# Load it before using it & same thing we do we when use in production/testing environment
with open('cb.pkl', 'rb') as f:
    cabin_onehot = pickle.load(f)
cabin_arr_test = cabin_onehot.transform(df_test.loc[:, ['Cabin']]).toarray()

这样您就不会面临测试记录中不同维度的问题。

您希望先连接数据,然后转换为假人,然后按照@Jekaterina Kokatjuhha 的建议再次将它们拆分到训练和测试数据集中。

尽管合并数据集的选项可能是特定于问题的,但您也可以阅读此处的文章,以更好地了解在训练和测试数据集中具有不同的观察结果。