95

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

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

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

MultinomialNB在不支持的分类器中执行此操作的方法是什么class_weight?除了predict_proba()自己使用然后计算类。

4

5 回答 5

59

可以使用设置阈值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
于 2018-08-03T19:32:20.930 回答
47

scikitclassifier.predict()默认使用 0.5 吗?

在概率分类器中,是的。正如其他人所解释的那样,从数学角度来看,这是唯一合理的阈值。

在 MultinomialNB 这样不支持的分类器中执行此操作的方法是什么class_weight

您可以设置,这是每个类别yclass_prior的先验概率 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])
于 2013-11-15T09:23:53.603 回答
47

在 scikit learn 中,二元分类的阈值为 0.5,无论哪个类具有最大的多类分类概率。在许多问题中,通过调整阈值可以获得更好的结果。但是,这必须小心完成,而不是在保留测试数据上,而是通过对训练数据的交叉验证。如果您对测试数据的阈值进行任何调整,那么您只是过度拟合了测试数据。

大多数调整阈值的方法是基于接收器操作特征 (ROC)和约登 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
于 2016-02-09T19:32:18.897 回答
8

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

所以首先 - 因为没有这样的东西,所以无法回答你关于 scikit 分类器默认阈值的问题。

第二类加权与阈值无关,与分类器处理不平衡类的能力有关,它取决于特定分类器。例如 - 在 SVM 情况下,它是优化问题中松弛变量的加权方式,或者如果您愿意 - 与特定类相关的拉格朗日乘数值的上限。将此设置为“自动”意味着使用一些默认的启发式方法,但再一次 - 它不能简单地转换为一些阈值。

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

文档中:

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

于 2013-11-14T21:47:20.323 回答
5

万一有人访问这个线程希望使用现成的功能(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

随意批评/修改。希望在极少数情况下,当无法进行类平衡并且数据集本身高度不平衡时,它会有所帮助。

于 2017-09-06T13:59:58.210 回答