如何在 scikit-learn 中有效地编码数字目标变量?

Posted

技术标签:

【中文标题】如何在 scikit-learn 中有效地编码数字目标变量?【英文标题】:How to validly encode a numerical target variable in scikit-learn? 【发布时间】:2020-01-13 02:51:45 【问题描述】:

我试图让 Scikit-learn 处理具有 500 个观察、20 个特征和 5 个分类目标标签(1、2、3、4、5)的数据集的分类问题。这些特征都是 float64 类型,并且已经标准化为 z 分数。只要将目标变量 (y) 作为一维 NumPy 数组输入,拟合和验证就可以正常工作。

然而,我最近意识到单热编码目标变量的重要性,因为分类的结果似乎会根据分配给类的整数而略有不同。

例如,下面是对编码变量使用不同顺序的 k-NN 分类器的平均结果的快速概述: (1, 2, 3, 4, 5) = 52,7%, (2, 4, 6, 8, 10) = 52.5% 和 (4, 3, 5, 1, 2) = 52.1%。这是有问题的,因为 y 的标签最初是字符串,而整数本身并不能说明数据的任何信息。

解决此问题的一种方法当然是将 y 作为字符串值提供(例如“1”、“2”、“3”、“4”、“5”)。但是,我发现 scikit-learn 会自动将字符串转换为整数,只要这些值可以转换为整数。这并不能消除问题本身,因为 ("1", "2", "3", "4", "5") 仍然会导致准确率为 52.7% 的平均准确度。使用 ("a", "b", "c", "d", "e") 之类的值可能是一种解决方案,但会导致错误消息:

ValueError: int() 以 10 为底的无效文字:'a'

与 Keras 不同,目标变量似乎必须作为一维 NumPy 数组提供,因此不能作为形状为 (500, 5) 的一次性编码矩阵给出。这会导致以下错误消息:

ValueError: 错误的输入形状 (500, 5)

这是一个简单的高斯朴素贝叶斯模型的代码示例:

random_state = 123
n_splits = 10
cv = StratifiedKFold(n_splits=n_splits, random_state=random_state,
shuffle=False)

model = GaussianNB()

for train, test in cv.split(X, y): 
    y_dummies = np_utils.to_categorical(y)
    y_dummies = y_dummies[:, 1:]

    X_train, X_test = X[train], X[test]
    y_train, y_test = y_dummies[train], y_dummies[test]

    model.fit(X_train, y_train) 
    y_pred = model.predict(X_test)

    conf = confusion_matrix(y_test.argmax(axis=1), y_pred)
    print(conf)

最后,我希望能够输出混淆矩阵 (conf),它消除了为五个类中的每一个分配的抽象数字标签的影响。

【问题讨论】:

这很奇怪,因为 K-NN 在模型计算中没有以任何方式使用标签(不像神经网络,其中一个热编码工作得很好),除了检查是否实例在邻域中被正确分类 【参考方案1】:

在使用 K-NN 时,您表示类/目标标签的方式不会影响您用于评估模型的所有其他指标的准确度/精度/召回率

如果 k 个最近邻居中的大多数属于该实例的同一类,那么您将实例分类为正确分类

我认为您的实施中还有其他问题。在评估完成之前,您的数据集上可能会有一些随机抽样或其他随机抽样(这当然会轻微或很大影响,具体取决于数据集的大小和性能)。

或者您在进行更改时可能没有始终如一地修改您的标签

【讨论】:

以上是关于如何在 scikit-learn 中有效地编码数字目标变量?的主要内容,如果未能解决你的问题,请参考以下文章

SciKit-Learn 标签编码器导致错误“参数必须是字符串或数字”

使用 Scikit-learn 和 Pandas 将编码列连接到原始数据帧

如何在 pandas 数据帧中有效地使用 one-hot 编码规范化列?

scikit-learn,线性回归中的分类(但数字)特征

在 python 中,如何有效地找到列表中不一定相邻的最大连续数字集?

在 C# 中有效地将字符串转换为字节数组(不使用编码)[重复]