【问题标题】:Scikit-learn Label Encoding followed by one hot encoding resulting in different feature set for train and test data sets. How to fix this?Scikit-learn 标签编码后跟一种热编码,导致训练和测试数据集的特征集不同。如何解决这个问题?
【发布时间】:2019-01-07 10:14:34
【问题描述】:

我正在尝试将包含数千个样本和大约 41 个特征的数据集 (KDD-cup-99) 用于我的一个机器学习项目。这实质上是使用 TCP DUMP 收集的特定网络的数据包捕获。

我使用 scikit-learn train_test_split 函数如下

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, 
random_state=42) 

拆分后,上面的每一个都有下面的形状。

X_train : (444618, 41)
y_train :  (444618,)
X_test  : (49403, 41)
y_test  :  (49403,)

在 41 个特征中,3 个特征是字符串类型的。使用这些数据的人可以理解这些。这三个是:protocol_type、service和flag。

我将这三个特征数组从训练样本和测试样本中分离出来,分别对训练样本和测试样本进行标签编码和 1hot 编码。现在这三个特征的数组大小如下:

X_train_obj1: (444618, 3)
X_train_obj2: (444618, 65)
X_train_obj3: (444618, 11)

X_test_obj1: (49403, 3)
X_test_obj2: (49403, 64)
X_test_obj3: (49403, 11)

这就是我的问题所在。出于某种原因,train_obj2 有 65 个特征/列,而 test_obj2 数组有 64 个特征/列。这会导致应用任何标准算法(如 KNeighborClassifier、SVM 等)的拟合/预测方法时出现问题,然后将它们与各自的训练集和测试集合并并开始使用它们。 API 失败,错误指示大小不一致..

对应代码:

label_encoder = LabelEncoder()
train_proto_label_encoded = 
label_encoder.fit_transform(X_train_obj['protocol_type'])
train_srv_label_encoded = 
label_encoder.fit_transform(X_train_obj['service'])
train_flag_label_encoded = 
label_encoder.fit_transform(X_train_obj['flag'])
test_proto_label_encoded = 
label_encoder.fit_transform(X_test_obj['protocol_type'])
test_srv_label_encoded = 
label_encoder.fit_transform(X_test_obj['service'])
test_flag_label_encoded = 
label_encoder.fit_transform(X_test_obj['flag'])

hot_encoder = OneHotEncoder()
train_proto_1hot_encoded = 
hot_encoder.fit_transform(train_proto_label_encoded.reshape(-1, 1))
train_srv_1hot_encoded = 
hot_encoder.fit_transform(train_srv_label_encoded.reshape(-1, 1))
train_flag_1hot_encoded = 
hot_encoder.fit_transform(train_flag_label_encoded.reshape(-1, 1))
test_proto_1hot_encoded = 
hot_encoder.fit_transform(test_proto_label_encoded.reshape(-1, 1))
test_srv_1hot_encoded = 
hot_encoder.fit_transform(test_srv_label_encoded.reshape(-1, 1))
test_flag_1hot_encoded = 
hot_encoder.fit_transform(test_flag_label_encoded.reshape(-1, 1))

我对打印语句进行了一些调试,基本上训练集获取所有 65 种不同类型服务的样本,而测试集仅获取 64 种不同类型服务的样本。

你能帮我理解和解决这个问题吗?

1) 当我们使用 scikit-learn API 进行标签编码和 1_hot_encoding 时,这种行为是预期的吗?

2) 在这种情况下,如何修复并确保训练和测试数据集都具有所有服务类型或字符串类型?

如果需要,我可以将完整代码添加到问题中。

【问题讨论】:

  • 你永远不会在测试数据上调用fit(或fit_transform)。仅致电transform()。在测试中进行拟合只会记住测试中存在的那些值,因此也会记住列数的变化。
  • 我并不是说适合测试数据。当我对测试数据调用预测时,问题就出现了
  • 您在测试数据上从 LabelEncoder 和 OnehotEncoder 调用 fit_transform。您需要为每个列维护单独的 LabelEncoders,然后从相同的 labelencoder 对象调用 transform() 测试数据。
  • 查看我的其他答案中的代码,了解需要做什么:stackoverflow.com/a/48079345/3374996
  • Vivek,感谢您的意见。它们很有用。上面的链接帮助我了解出了什么问题,但是,我仍然面临一个问题,即训练数据中不存在一些标签,而只存在于测试数据中。 Gabriel 的回答帮助我解决了这个问题。

标签: machine-learning scikit-learn svm knn


【解决方案1】:

1) 当我们使用 scikit-learn API 进行标签编码和 1_hot_encoding 时,这种行为是预期的吗?

是的,但这是因为您使用 fit_transform 的方式错误

2) 在这种情况下,如何修复并确保训练和测试数据集都具有所有服务类型或字符串类型?

如果不是所有 train 上的 caregories 都在测试中,反之亦然,您必须在 train 和 test 数据上都安装编码器。 以便编码器考虑到所有类别。

编码器安装好后,您可以在训练和测试中分别调用变换。您将获得相同数量的功能。

最后一个细节。如果您有仅在测试中的类别,使用这些类别训练模型可能会导致一些意外行为。

【讨论】:

    猜你喜欢
    • 2020-03-19
    • 2018-08-27
    • 2019-05-13
    • 2019-06-18
    • 2021-06-28
    • 2017-10-21
    • 2021-07-26
    • 1970-01-01
    • 2015-01-17
    相关资源
    最近更新 更多