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

时间:2020-11-03 11:57:28

标签: python machine-learning scikit-learn

我已经使用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 个答案:

答案 0 :(得分:1)

首先,感谢您提出的问题。

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

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

您能做什么?

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