将连续模型概率得分转换为分类评级

Converting Continuous Model Probability Score to a Categorical Rating

我有一个经过训练的标准 xgboost 分类模型,现在可以预测概率分数。但是,为了使用户界面更简单,我想将此分数转换为 5 星评级方案。 IE。离散化分数。

推导此量化阈值的智能方法是什么,以便高评分代表具有高置信度的高概率得分?

例如,我正在考虑生成置信区间以及预测并将高置信度高分分组为 5 星。高置信度低分作为 1 星。高置信度中高分如 4 星等。

你可以使用Pandas.cut()方法:

In [62]: np.random.seed(0)

In [63]: a = np.random.rand(10)

In [64]: a
Out[64]: array([0.5488135 , 0.71518937, 0.60276338, 0.54488318, 0.4236548 , 0.64589411, 0.43758721, 0.891773  , 0.96366276, 0.38344152])

In [65]: pd.cut(a, bins=np.linspace(0, 1, 6), labels=[1,2,3,4,5])
Out[65]:
[3, 4, 4, 3, 3, 4, 3, 5, 5, 2]
Categories (5, int64): [1 < 2 < 3 < 4 < 5]

更新: .

演示:

In [117]: a
Out[117]: array([0.6 , 0.8 , 0.85, 0.9 , 0.95, 0.97])

In [118]: pd.cut(a, bins=np.linspace(a.min(), a.max(), 6),
                 labels=[1,2,3,4,5], include_lowest=True)
Out[118]:
[1, 3, 4, 5, 5, 5]
Categories (5, int64): [1 < 2 < 3 < 4 < 5]

假设一个class化问题:either 1's or 0's

计算 ROC 曲线的 AUC 时,您按模型预测对 "events" 进行排序。所以在顶部,您很可能会有很多 1,并且在排序列表中越往下,0 就越多。

现在假设您尝试确定分数的阈值 "5"。 您可以计算您愿意承受的数据中 0 的相对百分比。

给出以下 table:

item   A    score
1      1    0.99
2      1    0.92
3      0    0.89
4      1    0.88
5      1    0.74
6      0    0.66
7      0    0.64
8      0    0.59
9      1    0.55

如果我希望 "user score" "5" 的误报率为 0%,我会确定“5”的阈值高于 0.89

如果我可以容忍 10% 的误报,我会确定阈值高于 0.66

您可以对每个阈值执行相同的操作。

在我看来,这是一个 100% 的商业决策,选择这些阈值的最明智的方法是根据您对用户的了解。

如果用户期望 "5" 是对 class(生死攸关的情况)的完美预测,则误报率为 0%。

我为此研究了多种解决方案并制作了 V0 解决方案的原型。解决方案的主要要求如下:

  • 随着评级水平的提高(5 星优于 1 星),误报数必须减少。

  • 用户不必手动定义得分概率的阈值,阈值是自动导出的。

  • 阈值源自某些更高级别的业务需求。

  • 阈值源自标记数据,并可在发现新信息时重新导出。

考虑的其他解决方案:

  • 基于置信区间的评级。例如,您可能有 0.9 的高预测分数但低置信度(即大置信区间)和 0.9 的高预测分数但高置信度(即小区间)。我怀疑我们可能希望后者成为 5 星候选人,而前者可能是 4*?
  • 识别ROC曲线的凸凹度以识别最大值点
  • 利用约登指数确定最佳点

最终解决方案 - 使用一组给定的业务需求(一组与每个星级相关联的 FPR)对 ROC 曲线进行采样,然后转换为阈值。 注意:这可行,但假设精度曲线有些单调,但情况可能并非总是如此。我通过将问题表述为优化问题来改进解决方案,其中评级阈值是自由度,objective 函数是每个评级桶之间转换率的线性度。我相信您可以尝试不同的 objective 函数,但就我的目的而言,效果非常好。

参考文献:

原型解决方案:

import numpy as np
import pandas as pd
# The probas and fpr/tpr/thresholds come from the roc curve.
probas_ = xgb_model_copy.fit(features.values[train], label.values[train]).predict_proba(features.values[test])
# Compute ROC curve and area the curve
fpr, tpr, thresholds = roc_curve(label.values[test], probas_[:, 1])

fpr_req = [0.01, 0.3, 0.5,0.9]
def find_nearest(array,value):
    idx = (np.abs(array-value)).argmin()
    return idx

fpr_indexes = [find_nearest(fpr, fpr_req_val) for fpr_req_val in fpr_req]
star_rating_thresholds = thresholds[fpr_indexes]
star_rating_thresholds = np.append(np.append([1],star_rating_thresholds),[0])
candidate_ratings = pd.cut(probas_,
star_rating_thresholds[::-1], labels=[5,4,3,2,1],right=False,include_lowest=True)

star_rating_thresolds
array([1. , 0.5073538 , 0.50184137, 0.5011086 , 0.4984425 ,
0. ])
candidate_ratings
[5, 5, 5, 5, 5, ..., 2, 2, 2, 2, 1]
Length: 564
Categories (5, int64): [5 < 4 < 3 < 2 < 1]