scikit .predict()默认阈值

时间:2013-11-14 18:00:48

标签: python machine-learning classification scikit-learn

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

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

在scikit中,某些分类器具有class_weight='auto'选项,但并非所有分类器都具有class_weight='auto'选项。使用.predict()MultinomialNB会将实际人口比例用作阈值吗?

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

6 个答案:

答案 0 :(得分:35)

  

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

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

  

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

您可以设置class_prior,即每个班级 y 的先验概率P( y )。这有效地改变了决策边界。 E.g。

# 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])

答案 1 :(得分:27)

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

调整阈值的大多数方法都基于receiver operating characteristics (ROC)Youden's J statistic,但也可以通过其他方法完成,例如使用遗传算法进行搜索。

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

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

答案 2 :(得分:14)

可以使用class ViewController: UIViewController { @IBOutlet weak var iv: UIImageView! @IBOutlet weak var tf: UITextField! @IBAction func doGo(_ sender: Any) { let s = tf.text! let s2 = NSAttributedString(string: s, attributes: [.font:UIFont(name: "Georgia", size: 100)!, .foregroundColor: UIColor.yellow]) let sz = iv.image!.size let r = UIGraphicsImageRenderer(size:sz) iv.image = r.image { _ in iv.image!.draw(at:.zero) s2.draw(at: CGPoint(x:30, y:sz.height-150)) } } @IBAction func doRevert(_ sender: Any) { config() } func config() { iv.image = UIImage(named:"nice.jpg") } override func viewDidLoad() { super.viewDidLoad() config() } }

设置阈值

例如:

clf.predict_proba()

答案 3 :(得分:8)

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

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

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

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

来自documentation

  

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

答案 4 :(得分:2)

0.5与人口比例无关。它的概率输出。没有“阈值”,如果一个类的概率为0.51,那么它似乎是最可能的类。 0.5如果总是应该使用的是*,并且没有包使用不同的“阈值”。如果您的概率分数是* ccurate且真正具有代表性*,那么您必须始终选择最可能的类。否则只会降低您的准确性。由于我们使用各种算法进行假设,我们不知道概率是正确的 - 但是你会违背模型所做的假设。

对class_weight的作用感到困惑。改变类权重会增加较少表示的类中数据点的权重(对于过度表示的类减少/),以便每个类的“权重”相等 - 好像它们具有相同数量的正面和负面示例。这是尝试避免总是为最常见的类投票的分类器的常见技巧。因为这样,从学习算法的角度来看,这两个类同样很常见。

  • 注意:如果你害怕误报/漏报,那么你可以选择只接受一个类,如果它的概率满足某个最小值。但这并不会改变学习方式,也不会改变概率背后的含义。

答案 5 :(得分:1)

如果有人访问此线程,希望使用即用型功能(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

随意批评/修改。希望它在极少数情况下有助于课堂平衡是不可能的,而且数据集本身也是高度不平衡的。