scikit .predict()默认阈值

ADJ*_*ADJ 62 python classification machine-learning scikit-learn

我正在研究不平衡类(5%1)的分类问题.我想预测班级,而不是概率.

在二进制分类问题中,scikit 默认classifier.predict()使用0.5?如果没有,那么默认方法是什么?如果是,我该如何更改?

在scikit中,一些分类器可以class_weight='auto'选择,但并非所有分类器都可以.有class_weight='auto',会.predict()用实际人口比例作为门槛吗?

在像MultinomialNB这样的分类器中不支持的方法是class_weight什么?除了使用predict_proba()然后自己计算类.

Fre*_*Foo 38

是scikit classifier.predict()默认使用0.5?

在概率分类器中,是的.正如其他人所解释的那样,这是数学观点上唯一明智的门槛.

在像MultinomialNB这样不支持的分类器中,这样做的方法是什么class_weight

您可以设置class_prior,即每个类y的先验概率P(y).这有效地改变了决策边界.例如

# minimal dataset
>>> X = [[1, 0], [1, 0], [0, 1]]
>>> y = [0, 0, 1]
# use empirical prior, learned from y
>>> MultinomialNB().fit(X,y).predict([1,1])
array([0])
# use custom prior to make 1 more likely
>>> MultinomialNB(class_prior=[.1, .9]).fit(X,y).predict([1,1])
array([1])
Run Code Online (Sandbox Code Playgroud)

  • RandomForestClassifier 没有 class_prior 参数,但它有一个可以使用的 class_weight 参数。 (2认同)
  • 实际上0.5的默认值是任意的,并且不一定是最优的,例如[在Frank的简历中由Frank Harrell回答](https://stats.stackexchange.com/a/73364/35989),他是一个被切除的权威. (2认同)
  • “在概率分类器中,是的。正如其他人所解释的那样,从数学角度来看,这是唯一合理的阈值。” - 这似乎完全没有根据。例如,如果您想重视召回率而不是准确率,该怎么办? (2认同)

den*_*son 30

对于二元分类,scikit学习中的阈值为0.5,无论哪个类具有多类分类的最大概率.在许多问题中,通过调整阈值可以获得更好的结果.但是,这必须小心谨慎,而不是在保持测试数据上,而是通过对训练数据的交叉验证.如果对测试数据进行任何阈值调整,则只会过度拟合测试数据.

大多数调整阈值的方法都是基于接收器操作特性(ROC)Youden的J统计量,但也可以通过其他方法完成,例如使用遗传算法进行搜索.

这是一篇同行评审期刊文章,描述了在医学中这样做:

http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2515362/

据我所知,在Python中没有用于执行此操作的软件包,但在Python中使用强力搜索来查找它是相对简单的(但效率低下).

这是一些R代码.

## load data
DD73OP <- read.table("/my_probabilites.txt", header=T, quote="\"")

library("pROC")
# No smoothing
roc_OP <- roc(DD73OP$tc, DD73OP$prob)
auc_OP <- auc(roc_OP)
auc_OP
Area under the curve: 0.8909
plot(roc_OP)

# Best threshold
# Method: Youden
#Youden's J statistic (Youden, 1950) is employed. The optimal cut-off is the threshold that maximizes the distance to the identity (diagonal) line. Can be shortened to "y".
#The optimality criterion is:
#max(sensitivities + specificities)
coords(roc_OP, "best", ret=c("threshold", "specificity", "sensitivity"), best.method="youden")
#threshold specificity sensitivity 
#0.7276835   0.9092466   0.7559022
Run Code Online (Sandbox Code Playgroud)

  • 很棒的帖子!最重要的一点是:“如果您对测试数据的阈值进行任何调整,都将过度拟合测试数据。” (2认同)

Yuc*_*ang 29

可以使用设置阈值 clf.predict_proba()

例如:

from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier(random_state = 2)
clf.fit(X_train,y_train)
# y_pred = clf.predict(X_test)  # default threshold is 0.5
y_pred = (clf.predict_proba(X_test)[:,1] >= 0.3).astype(bool) # set threshold as 0.3
Run Code Online (Sandbox Code Playgroud)

  • 您如何将其与 GridSearchCV 联系起来,其中正在执行的预测是内部的并且您无法访问?假设阈值 0.3 会给我一个不同的最佳模型选择。 (5认同)
  • 我认为GridSearchCV只会使用默认阈值0.5。在训练期间改变这个阈值是不合理的,因为我们希望一切都是公平的。仅在最后的预测阶段,我们才调整概率阈值以支持更积极或消极的结果。例如,为了获得更大的捕获率(以更高的误报为代价),我们可以手动降低阈值。 (3认同)
  • 为了澄清起见,您没有“设置阈值”,因为这意味着您将永久更改“ clf.predict()”的行为,而您并没有这样做。 (2认同)

lej*_*lot 8

你似乎在这里混淆概念.阈值不是"通用分类器"的概念 - 最基本的方法基于一些可调阈值,但是大多数现有方法创建了复杂的分类规则,这些规则不能(或至少不应该)被视为阈值.

所以首先 - 一个人无法回答你的问题scikit的分类器默认阈值,因为没有这样的事情.

第二类加权不是关于阈值,关于分类器处理不平衡类的能力,它是依赖于特定分类器的东西.例如 - 在SVM情况下,它是在优化问题中加权松弛变量的方法,或者如果您愿意,则是与特定类相关联的拉格朗日乘数值的上限.将其设置为"auto"意味着使用一些默认启发式,但再一次 - 它不能简单地转换为某些阈值.

另一方面,朴素贝叶斯直接估计训练集中的类概率.它被称为"类优先",您可以使用"class_prior"变量在构造函数中设置它.

文档:

类的先验概率.如果指定,则不根据数据调整先验.

  • @lejlot,如果是这样的话,那么用predict_proba绘制的roc曲线的整个概念是否也变得无关紧要了?在不同阈值绘制的roc曲线的不同点是否应用于predict_proba的结果? (4认同)
  • 让我以不同的方式解释这一点,然后可以随意说我仍然感到困惑:-)。说我有两个班级。大多数分类器会预测概率。我可以使用概率来评估我的模型,比如使用 ROC。但是如果我想预测一个类别,我需要选择一个临界值,比如 0.5,然后说“p&lt;0.5 的每个观察都进入第 0 类,而 p&gt;0.5 的观察进入第 1 类。这通常是好的如果您的先验是 0.5-0.5,则选择。但是对于不平衡的问题,我需要一个不同的截止点。我的问题实际上是询问在使用 .predict() 时如何在 scikit 中处理该截止点。 (3认同)

小智 6

如果有人访问此线程希望获得现成可用的函数(python 2.7)。在此示例中,截止值旨在反映原始数据集df中事件与非事件的比率,而y_prob可以是 .predict_proba 方法的结果(假设分层训练/测试分割)。

def predict_with_cutoff(colname, y_prob, df):
    n_events = df[colname].values
    event_rate = sum(n_events) / float(df.shape[0]) * 100
    threshold = np.percentile(y_prob[:, 1], 100 - event_rate)
    print "Cutoff/threshold at: " + str(threshold)
    y_pred = [1 if x >= threshold else 0 for x in y_prob[:, 1]]
    return y_pred
Run Code Online (Sandbox Code Playgroud)

欢迎批评/修改。希望它在极少数情况下有所帮助,即类别平衡无法实现并且数据集本身高度不平衡。