如何使用 sklearn 决策树更喜欢没有选择而不是糟糕的选择

数据挖掘 机器学习 scikit-学习 决策树
2022-02-05 14:05:13

我正在使用 sklearn 决策树将文档分类为两种可能的类型“type1”和“type2”。

我已经分离出一些看起来相关的特征,并尝试手动组合它们来评估模型的结果。手动分类文档时,我使用以下结果:

  • 1型
  • 类型 2
  • 未知

然后我将相同的特征赋予决策树。在这种情况下结果更糟,因为它总是尝试将文档分类为“type1”或“type2”类别之一,但无法将文档分类为“未知”

是否可以配置 sklearn 决策树,以在高度不确定性的情况下不对文档进行分类,而不是选择可能错误的类别?

1个回答

TL;博士

您可以像往常一样训练分类器并在预测概率上设置阈值。

Scikit-学习

你不会开箱即用,但你可以使用这个简单的类来做到这一点!

from sklearn.tree import DecisionTreeClassifier
from numpy import argmax, max

class MyClassifier(DecisionTreeClassifier):

    unknown_class = 'unknown'

    def __init__(self, no_class_threshold=0.75, **kwargs):
        self.no_class_threshold = no_class_threshold
        super().__init__(**kwargs)

    def predict(self, X):
        preds = self.predict_proba(X)
        y_pred = [self.classes_[i] if v > self.no_class_threshold else self.unknown_class
                  for i, v in zip(argmax(preds, axis=1), max(preds, axis=1))]
        return y_pred

只需像使用之前一样使用此类DecisionTreeClassifier您可以传递所有参数,DecisionTreeClassifier加上一个额外的:no_class_threshold.

no_class_threshold工作方式如下

IF
    prediction_probability > no_class_threshold
THEN
    output predicted class
ELSE
    output 'unknown'

更改分类器

您可能不想继续使用DecisionsTreeClassfier,相反,您可能想尝试使用其他分类器。您可以通过从另一个 Scikit-learn 类继承来做到这一点。就那么简单!

例如:

from sklearn.svm import SVC

class MyClassifier(SVC):
    [...]

选择no_class_threshold

你可以:

  • 手动选择它,直到您感到自信的程度
  • 如果您有标记为“未知”的数据点,请使用超参数调整来学习它

例子

这是一个脚本,您可以运行它来测试上述所有内容。

from numpy import argmax, max
from sklearn.svm import SVC


class MyClassifier(SVC):
    unknown_class = 'unknown'

    def __init__(self, no_class_threshold=0.75, **kwargs):
        self.no_class_threshold = no_class_threshold
        super().__init__(**kwargs)

    def predict(self, X):
        preds = self.predict_proba(X)
        y_pred = [self.classes_[i] if v > self.no_class_threshold else self.unknown_class
                  for i, v in zip(argmax(preds, axis=1), max(preds, axis=1))]
        return y_pred


if __name__ == '__main__':
    X = [[1, 1, 1],
         [1, 0, 1],
         [0, 0, 0],
         [0, 1, 0],
         [0, 1, 1]]
    y = ['class1', 'class1', 'class0', 'class0', 'class0']

    clf = MyClassifier(no_class_threshold=0.55, probability=True, C=1)

    clf.fit(X, y)

    X2 = [[1, 1, 0],
          [0, 1, 1],
          [0, 0, 1]]
    pred = clf.predict(X2)
    print(pred)