scikit-learn:如果经过一次热编码后它的特征少于训练/测试集,如何预测新数据

Posted

技术标签:

【中文标题】scikit-learn:如果经过一次热编码后它的特征少于训练/测试集,如何预测新数据【英文标题】:scikit-learn: how to predict new data if after one hot encoding it has fewer features than the training/testing sets 【发布时间】:2020-03-19 18:00:57 【问题描述】:

我正在尝试在我的第一个 ML 项目中使用 scikit-learn,将其 DecisionTreeClassifier 与包含数字和分类特征的数据样本一起使用,例如:['High', 33, '不',4]

我已经到了能够做到的地步。

    从 .csv 文件中读取训练和测试数据。

    physio = pd.read_csv('data.csv', header=None, names=['HR', 'M', 'T', 'W', 'D'])

    提取目标类:labels = physio.pop('D')

    使用pandas.get_dummies 对分类特征进行一次热编码。这也将特征数量从 4 个增加到 6 个(因为 'HR' 和 'T' 分别变为 'HR_High'/'HR_Low' 和 'T_Yes'/'T_No')

    for col in physio.dtypes[physio.dtypes == 'object'].index:
        for_dummy = physio.pop(col)
        physio = pd.concat([physio, pd.get_dummies(for_dummy, prefix=col)], axis=1)
    

    将集合拆分为训练和测试子集。

    x_train, x_test, y_train, y_test = train_test_split(physio, labels, test_size=0.25)
    

    实例化并拟合树

    dt = DecisionTreeClassifier(max_depth=8, min_samples_split=.3, min_samples_leaf=.26, max_features=4)
    dt.fit(x_train, y_train)
    

    在第一次测试拆分中对测试集进行分类

    y_pred = dt.predict(x_test)
    

    并使用y_testy_pred使用混淆矩阵(也是ROC的AUC)评估分类

    conf_matrix = confusion_matrix(y_true=y_test, y_pred=y_pred, labels=['Yes', 'No'])
    

如果我使用了错误的术语,我很抱歉,但是,现在我正在尝试做这一切应该做的事情,即对传入的数据进行分类,不幸的是,这是我见过的所有教程的落脚点简而言之,一旦所有拆分、训练和测试都发生了,他们就永远不会进入对新数据进行分类的程序部分。

我天真地尝试过的方式:

    由于实际数据将来自命令行参数,我想我会将它们存储在一个数组中并将其传递给 DataFrame。

    newSample = [['Low', 2, 'No', 8]]
    newSampleDF = pd.DataFrame(newSample, columns=['HR', 'M', 'T', 'W'])
    

    然后我尝试对其进行单热编码。这就是问题出现的地方,因为在编码完成后,仍然有 4 个特征,因为只是一个数据样本,它对“高”和“是”一无所知,所以“HR”和“T”就变成了“ HR_Low' 和 'T_No' 分别

    for col in newSampleDF.dtypes[newSampleDF.dtypes == 'object'].index:
        for_dummy = newSampleDF.pop(col)
        newSampleDF = pd.concat([newSampleDF, pd.get_dummies(for_dummy, prefix=col)], axis=1)
    

当我打印 newSampleDF 时,它显示:

M  W  HR_Low  T_No
2  8    1      1

而我试图对其进行分类的数据的形式是

 M   W  HR_High  HR_Low  T_No  T_Yes
12  48     0       1      0      1

这就是我收到错误的原因:

ValueError:模型的特征数量必须与输入匹配。模型 n_features 为 6,输入 n_features 为 4

这是不言自明的,我只是不知道如何解决它。如何让我的新数据以意识到缺失值的方式编码,在这种情况下为“高”和“是”。

我希望我是有道理的,请随时指出错误和改进,但请记住,第一次来这里。

谢谢

【问题讨论】:

【参考方案1】:

我认为整个方法有点问题。我们不需要使用pd.get_dummies,因为我们已经知道类别列。那我们为什么不直接使用呢?

因此我更喜欢以下解决方案:

import pandas as pd

cats = ["HR", "T"]

training_data = pd.DataFrame([[12, 48, 0, 1, 0, 1]], columns=["M","W", "HR_High", "HR_Low", "T_No", "T_Yes"])

raw_cols = ['HR', 'M', 'T', 'W']
newSample = [['Low', 2, 'No', 8]]
newSampleDF = pd.DataFrame(newSample, columns=raw_cols)

cols = ["M","W", "HR_High", "HR_Low", "T_No", "T_Yes"]
template = pd.DataFrame([6 * [None]], columns=cols)

for col in raw_cols:
    if col in cats:
        template.loc[0, col + "_" + newSampleDF.loc[0, col]] = 1
    else:
        template.loc[0, col] = newSampleDF.loc[0, col]

# replace Nans with 0
newSampleDF = template.fillna(0)
print(newSampleDF)

输出:

   M  W  HR_High  HR_Low  T_No  T_Yes
0  2  8        0       1     1      0

【讨论】:

关于您的编辑:如果按 ...order 将根据输入而改变。,您的意思是 [['Low', 2, 'No', 8]] 的项目的订单,那么不,该订单是完全由我控制。还是你的意思是别的? 另外,我现在正在尝试您的答案,并且:有没有办法告诉 get_dummies 不要用_nans 填充它并以某种方式将它应该填充的字符串传递给它?在这种情况下:“高”和“是”。还是太多了?谢谢 @Scaramouche 查看我对您问题的解决方案。 如果您保留以前的解决方案而不是隐藏(因为编辑)我会很好,因为我相信这是一个更通用的解决方案,不像现在的解决方案更适合我情景,这将有助于未来的读者

以上是关于scikit-learn:如果经过一次热编码后它的特征少于训练/测试集,如何预测新数据的主要内容,如果未能解决你的问题,请参考以下文章

一次热编码多维数据

一次热编码期间的 RunTimeError

如何使用 sklearn 对 CSV 文件中的多列进行一次热编码?

一次对多列进行一次热编码并附加到主数据集?

对两列字符串数据执行一次热编码

如何在 R 中对多个分类变量进行一次热编码