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_test
和y_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:如果经过一次热编码后它的特征少于训练/测试集,如何预测新数据的主要内容,如果未能解决你的问题,请参考以下文章