模型预测不在目标中的类(零数组)

Posted

技术标签:

【中文标题】模型预测不在目标中的类(零数组)【英文标题】:model predicts class not in target (array of zeros) 【发布时间】:2021-02-16 02:30:53 【问题描述】:

我已经使用 MultiLabelBinarizer 对我的目标变量进行了编码。然后我以这种方式从转换的结果中创建了一个新的 DataFrame

y_trans = pd.DataFrame(MultiLabelBinarizer().fit_transform(y))

这里是head()

    0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17
   -----------------------------------------------------------------------
0   0   0   0   0   0   0   0   0   0   1   0   0   0   1   0   0   0   0
1   0   0   0   0   0   0   0   0   0   1   0   0   0   1   0   0   0   0
2   0   0   0   0   0   0   0   0   0   1   0   0   0   1   0   0   0   0
3   0   0   0   0   0   0   1   0   0   0   0   0   0   0   0   0   0   0
4   0   0   0   0   0   0   1   0   0   0   0   0   0   0   0   0   0   0

我使用

创建训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_trans, y_trans, random_state=0)

在拟合RandomForestKNN 后,预测X_test 变量会返回一个数组,其中一些预测是这样的

array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])

编码的目标变量中不存在这样的类,因为

len(y_trans.where(y_trans == [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]).dropna())

实际上是 0。

我不明白为什么会这样。 Somewhat related question.

重现我的问题

我提供encoded features and labels 供下载。它们以二进制格式腌制。 从那里,重现我的错误的步骤很简单

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
import pickle

X_trans = pickle.load(open('features.pkl', 'rb'))
y_trans = pickle.load(open('target.pkl', 'rb'))

X_train, X_test, y_train, y_test = train_test_split(X_trans, y_trans, random_state=0)

rfc = RandomForestClassifier(random_state=0)
rfc.fit(X_train, y_train)
print(rfc.predict(X_test)[1])

打印预测中的第二个值将返回[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

我的分类目标

我的目标是创建一个分类器,它可以预测至少一个“正确的类”,由条目中的 1 表示。 例如,y 的第一个条目是[0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0]。 我会考虑正确的

[0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0]

但这是一个评估问题,一旦预测正确,就会发生。正如我所说,不能有“空洞”的预测。有18个类,127个独特的组合,没有一个是[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

Sklearn examples 有同样的“问题”

此时,这个输出必须有意义。但我无法弄清楚。 注意:在这个例子中,使用的分类器是KNN,我显示的是RandomForest,但如果我使用KNN,我会遇到同样的问题。

from sklearn.datasets import make_multilabel_classification
from sklearn.multioutput import MultiOutputClassifier
from sklearn.neighbors import KNeighborsClassifier

X, y = make_multilabel_classification(n_classes=18, random_state=0)
clf = MultiOutputClassifier(KNeighborsClassifier()).fit(X, y)
clf.predict(X)[3]

>>> array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

分割成训练集和测试集时同样适用

from sklearn.datasets import make_multilabel_classification
from sklearn.multioutput import MultiOutputClassifier
from sklearn.neighbors import KNeighborsClassifier

X, y = make_multilabel_classification(n_classes=18, random_state=0)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0, test_size=0.2)
clf = MultiOutputClassifier(KNeighborsClassifier()).fit(X_train, y_train)
clf.predict(X_test)[8]

>>> array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

【问题讨论】:

【参考方案1】:

首先,感谢问题的质量。

我认为这里有几件事要解释:

您的分类目标:您需要定义自己的指标来衡量您所描述的内容。 (见make_scorer function in sklearn)。这是第一步,因为如果无法衡量改进是什么,就无法改进模型。 接下来,在训练模型时,您需要调整模型参数(称为超参数)以优化分数。为了快速解释,您选择一组参数,训练您的模型,并检查测试集上的分数。您通过修改参数进行迭代以优化测试分数。一个简单的方法是使用sklearn's GridSearchCV。 现在,回答您的问题:您的模型独立地预测您的 18 个类别中的每一个样本是否属于此类。这就是为什么在某些情况下,您可能会拥有一个似乎不属于任何类的样本。

你能做些什么呢?

首先,您需要检查您的模型是否正确拟合,并调整超参数以提高分数。目前,它严重过度拟合(训练分数远高于测试分数)。您可能会发现数据中没有足够的信号使其无法正常工作。 也许其他模型可以帮助您获得更好的结果,具体取决于数据的拓扑结构(您需要尝试并查看) 您还可以使用 rfc.predict_proba 获取每个类别的预测概率:这将允许您设置不同于默认 0.5 的阈值,甚至选择更高的阈值。

【讨论】:

感谢您的回答。我知道我必须定义自己的评分函数,但由于我无法做出好的(有意义的)预测,我无法继续。我尝试过 KNN、RF 和 SVC,但都没有给出好的结果。还有 GridSearch,让我们运行 30 分钟,但没有大的改进。我被困住了,sklearn 的例子似乎也没有帮助。 选择模型和优化可以改善结果,但最好的改进将来自更好的输入数据(更好的特征,意味着添加特征、改进编码等)。一个好的分数是 90% 的数据,10% 的模型优化。我的建议是:首先定义你的分数,其次像你一样实现一个基本的随机森林模型,第三个获得更好的功能来提高分数。但有时你只是没有足够的信号来获得显着的结果。你能用你的输入特征手动分类吗?如果没有,您可能无法使用 ML 来做到这一点

以上是关于模型预测不在目标中的类(零数组)的主要内容,如果未能解决你的问题,请参考以下文章

“神算子”EasyDL时序预测模型零门槛

深度学习时间序列预测如何构建矩阵

灰色预测 模型GM(1,1)级比检验不在区域(exp(-2/(n+1)),exp(2/(n+1)))内,怎么处理

如何获得 Huggingface Transformer 模型预测 [零样本分类] 的 SHAP 值?

根据决策树算法生成的模型进行预测

SAS时间序列模型预测未来航班数量