更改随机森林分类器的阈值

Posted

技术标签:

【中文标题】更改随机森林分类器的阈值【英文标题】:Change threshold value for Random Forest classifier 【发布时间】:2019-12-09 22:29:52 【问题描述】:

我需要开发一个没有(或接近于)假阴性值的模型。为此,我绘制了 Recall-Precision 曲线并确定阈值应设置为 0.11

我的问题是,如何在模型训练时定义阈值?稍后在评估时定义它是没有意义的,因为它不会反映新数据。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=101)

rfc_model = RandomForestClassifier(random_state=101)
rfc_model.fit(X_train, y_train)
rfc_preds = rfc_model.predict(X_test)


recall_precision_vals = []

for val in np.linspace(0, 1, 101):
    predicted_proba = rfc_model.predict_proba(X_test)
    predicted = (predicted_proba[:, 1] >= val).astype('int')
    
    recall_sc = recall_score(y_test, predicted)
    precis_sc = precision_score(y_test, predicted)

    recall_precision_vals.append(
        'Threshold': val,
        'Recall val': recall_sc,
        'Precis val': precis_sc
    )


recall_prec_df = pd.DataFrame(recall_precision_vals)

有什么想法吗?

【问题讨论】:

【参考方案1】:

模型训练时如何定义阈值?

模型训练过程中根本没有没有阈值;随机森林是一个概率分类器,它只输出类概率。确实需要阈值的“硬”类(即 0/1)既不会在模型训练的任何阶段产生也不会使用 - 仅在预测期间,即使这样也仅在我们确实需要硬分类的情况下(并不总是案子)。详情请见Predict classes or class probabilities?。

实际上,RF 的 scikit-learn 实现实际上根本没有使用阈值,即使对于硬类预测也是如此;仔细阅读docs 的predict 方法:

预测的类是在树中具有最高平均概率估计的类

简单来说,这意味着实际的RF输出是[p0, p1](假设二进制分类),predict方法只是返回具有最高值的类,即如果p0 > p1则返回0,否则返回1。

假设你真正想要做的是如果p1大于小于0.5的某个阈值,则返回1,你必须放弃predict,改用predict_proba,然后操纵这些返回的概率来得到什么你要。这是一个带有虚拟数据的示例:

from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification

X, y = make_classification(n_samples=1000, n_features=4,
                          n_informative=2, n_redundant=0,
                           n_classes=2, random_state=0, shuffle=False)

clf = RandomForestClassifier(n_estimators=100, max_depth=2,
                            random_state=0)

clf.fit(X, y)

在这里,简单地使用predict 表示X 的第一个元素,将得到0:

clf.predict(X)[0] 
# 0

因为

clf.predict_proba(X)[0]
# array([0.85266881, 0.14733119])

p0 > p1.

为了得到你想要的(即这里返回第 1 类,因为 p1 > threshold 的阈值为 0.11),这是你必须做的:

prob_preds = clf.predict_proba(X)
threshold = 0.11 # define threshold here
preds = [1 if prob_preds[i][1]> threshold else 0 for i in range(len(prob_preds))]

之后,很容易看出,现在对于我们拥有的第一个预测样本:

preds[0]
# 1

因为,如上所示,对于这个示例,我们有 p1 = 0.14733119 > threshold

【讨论】:

以上是关于更改随机森林分类器的阈值的主要内容,如果未能解决你的问题,请参考以下文章

scikit学习随机森林分类器概率阈值

如何测量随机森林分类器的准确性?

随机森林分类器的决策路径

为啥以两种不同方式应用随机森林分类器的特征选择结果不同

最后一行 #5 与随机森林分类器的分类有问题

为啥打乱训练数据会影响我的随机森林分类器的准确性?