混淆矩阵是衡量分类型模型准确度中最基本,最直观,计算最简单的方法。
简单来说,混淆矩阵就是一张表格。
他的四个基础指标如下:
将这四个指标合并在一个表格中,就是:
confusion matrix | positive(predict) | negative(predict) |
---|---|---|
positive(true) | TP | FN |
negative(true) | FP | TN |
再次基础上,又衍生了如下四个指标:
python代码实现绘制混淆矩阵
def confusion_matrix_(y_pred,y_true):
'''
params:
y_pred:预测值
y_true:真实值
result:
绘制混淆矩阵和准确率、精确率、F1值
'''
CM = confusion_matrix(y_true,y_pred)
fig = plt.figure(figsize=(12,6))
fig.suptitle(r'Confusion Matrix')
#画热力图
ax1 = fig.add_subplot(1,2,1)
sns.heatmap(CM,annot=True,cmap='Blues',linewidths=0.5,ax=ax1)
ax1.set_xlabel('predicate')
ax1.set_ylabel('true')
#文本显示指标
(tn,fp,fn,tp) = CM.ravel()
acc = format_2(accuracy_score(y_true, y_pred))
pre0 = format_2(tn/(fn+tn)); pre1 = format_2(tp/(tp+fp))
recall0 = format_2(tn/(fp+tn)); recall1 = format_2(tp/(tp+fn))
f10 = format_2(2*tn/(2*tn+fp+fn))
f11 = format_2(2*tp/(2*tp+fp+fn))
col_labels = ['precision','recall','F1']
row_labels = [' '*4+'0'+' '*4,' '*4+'1'+' '*4]
table_vals = [[pre0,recall0,f10],[pre1,recall1,f11]]
ax2 = fig.add_subplot(1,2,2)
ax2.table(cellText=table_vals,rowLabels=row_labels,
colLabels=col_labels,loc='center')
ax2.text(0.35,0.6,
r'''
accuracy: {acc}
'''.format(acc=acc),
horizontalalignment='center',
verticalalignment='center',
fontsize=20, color='black',
transform=ax2.transAxes)
ax2.axis('off')
ax2.set_xticks([])
ax2.set_yticks([])
plt.show()
总结
真正率 TPR(true positive rate): 真实值是positive中预测正确的占比
T P R = t p t p + f n TPR = \frac{tp}{tp+fn} TPR=tp+fntp
假正率 FPR(false negative rate) 真实值是negative中预测错误的占比
F P R = f p f p + t n FPR = \frac{fp}{fp+tn} FPR=fp+tnfp
我们根据学习器的预测结果,把阈值从0变到最大,即刚开始是把每个样本作为正例进行预测,随着阈值的增大,学习器预测正样例数越来越少,直到最后没有一个样本是正样例。在这一过程中,每次计算出TPR和FPR,分别以它们为横、纵坐标作图,就得到了 ROC 曲线。
AUC就是ROC曲线下的面积。AUC是指随机给定一个正样本和一个负样本,分类器输出该正样本为正的那个概率值比分类器输出该负样本为正的那个概率值要大的可能性。所以AUC反应的是分类器对样本的排序能力。
python代码实现auc曲线绘制
def auc_roc_ks_(y_predproab,y_true,plot=True):
'''
params:
y_predproab:预测值概率
y_true:真实值
plot:是否绘制roc曲线,默认绘制
result:
绘制roc曲线,并显示auc和ks
'''
fpr,tpr,threshold = roc_curve(y_true,y_predproab)
auc_ = format_4(auc(fpr,tpr))
ks = format_4(max(abs(tpr - fpr)))
if plot:
plt.figure(figsize=(6,6))
plt.title('ROC_AUC_KS',fontsize=25)
plt.plot(fpr,tpr,color='navy',lw=2,
label='auc:{}'.format(auc_))
plt.plot([0,1],[0,1],color='darkorange',lw=2,linestyle='--')
#标记ks
gap = abs(fpr-tpr)
plt.plot(fpr,gap,linewidth=2,color='r',label='ks:{}'.format(ks))
plt.xlabel('False Positive Rate',fontsize=20)
plt.ylabel('True Positiobe Rate',fontsize=20)
plt.legend(loc='best')
plt.show()
else:
print('auc:{auc_}\nks:{ks}'.format(auc_=auc_,ks=ks))
总结
ks用于对模型风险区分能力进行评估。计算好坏样本的累计差异,差异最大值为ks。ks值越大,模型的风险区分能力越强。
计算步骤
def calc_ks(y_predproab,y_true):
'''
params:
y_predproab:预测值概率/正样本分组
y_true:真实值/正负样本标记label
return:
ks
'''
fpr,tpr,threshold = roc_curve(y_true,y_predproab)
ks = format_4(max(abs(tpr - fpr)))
return ks
Gini系数是20世纪初意大利学者科拉多·基尼根据劳伦茨曲线所定义的判断年收入分配公平程度的指标。在模型评价中,Gini统计值衡量坏账户数在好账户数上的的累积分布与随机分布曲线之间的面积,好账户与坏账户分布之间的差异越大,GINI指标越高,表明模型的风险区分能力越强。
纵坐标是tpr,在信用评分模型中就是坏用户率,横坐标是(tp+fp)/(tp+fp+tn+fn) ,总样本中预测为正例的占比。中间的对角线表示样本模型的随机分布,也可以称之为绝对公平线。曲线(洛伦兹曲线)是使用模型的真实累积分布情况,阈值越低,预测值中正例占比越高,tpr也越大。
G i n i = A A + B = 2 A Gini=\frac{A}{A+B}=2A Gini=A+BA=2A
Gini系数的计算
当正样本占比很小的时候,tp和fn可忽略不计,图形的横坐标变为fpr,洛伦兹曲线接近于ROC曲线,auc = A + 0.5,gini=2*AUC-1成立
当样本分布均衡的时候,用高数的积分计算
python代码计算ks
def gini_(y_predproab, y_true):
'''
params:
y_predproab:预测值概率/正样本分组
y_true:真实值/正负样本标记label
return:
gini系数
'''
a = np.asarray(np.c_[y_true, y_predproab, np.arange(len(y_true))], dtype=np.float)
a = a[np.lexsort((a[:,2],-1*a[:,1]))]
#根据等高梯形求曲线面积
totalLosses = a[:,0].sum()
giniSum = a[:,0].cumsum().sum()/totalLosses
#计算阴影面积
giniSum -= (len(y_true)+1)/2.
return giniSum/len(y_true)
def calc_gini(y_predproab, y_true):
'''
params:
y_predproab:预测值概率/正样本分组
y_true:真实值/正负样本标记label
return:
gini:按照预测值排序gini系数
ginimax:按照真实值排序给gini系数
gini/ginimax
'''
gini = gini_(y_predproab,y_true)
ginimax = gini_(y_true,y_true)
return format_4(gini),format_4(ginimax),format_4(gini/ginimax)
Lift曲线的衡量的是模型通过某个阈值划定预测结果的命中率,对比不用模型随机划定结果的命中率的提升度。简单来说,就是相较于不用这个模型,用了模型后,效果提升了多少。
L i f t = T P T P + F P T P + F N T P + T N + F P + F N Lift= \frac{\frac{TP}{TP+FP}}{\frac{TP+FN}{TP+TN+FP+FN}} Lift=TP+TN+FP+FNTP+FNTP+FPTP
不使用模型positive的占比:正样本占总样本的占比,作为模型的baseline。代表不使用模型,自然分类的效果。
使用后模型的占比:预测为positive的样本中分类正确的占比
Gain与Lift 相当类似。Lift chart是不同阈值下Lift和Depth(样本中预测为正例的占比,也是图中数据的百分位,data sets)的轨迹,Gain chart是不同阈值下PV+和Depth的轨迹,而PV+=lift*pi1= tp/(tp+fp),所以它们显而易见的区别就在于纵轴刻度的不同:
python代码绘制lift/gain曲线
def plot_lift(y_predproab, y_true):
'''
params:
y_predproab:预测值概率/正样本分组
y_true:真实值/正负样本标记label
result:
绘制lifi曲线
'''
result = pd.DataFrame([y_true,y_predproab]).T
result.columns = ['target','proba']
result = result.sort_values(['proba','target'],ascending=False).reset_index()
del result['index']
result.set_index((result.index+1)/result.shape[0],inplace=True)
result['bad_sum'] = result['target'].cumsum()
result['count_sum'] = [i+1 for i in range(result.shape[0])]
result['rate'] = result['bad_sum']/result['count_sum']
result['lift'] = result['rate']/(result['target'].sum()/result.shape[0])
fig = plt.figure(figsize=(12,6))
ax1 = fig.add_subplot(1,2,1)
ax1.grid(True,linestyle='-.')
ax1.plot(result['rate'],color='red',label='Lift model')
ax1.plot(result.index,[result['target'].sum()/result.shape[0]]*result.shape[0],color='blue',label='Lift random')
ax1.set_title('Lift Chart',fontsize=25)
ax1.set_ylabel('tp/(tp+fp)',fontsize=20)
ax1.set_xlabel('data sets',fontsize=20)
ax1.set_xticks([i/10 for i in range(11)])
plt.legend(loc='best')
ax2 = fig.add_subplot(1,2,2)
ax2.plot(result['lift'],color='darkorange')
ax2.grid(True,linestyle='-.')
ax2.set_title('Cumulative Lift Chart',fontsize=25)
ax2.set_ylabel('lift',fontsize=20)
ax2.set_xlabel('data sets',fontsize=20)
ax2.set_xticks([i/10 for i in range(11)])
plt.show()
PSI(Population Stability Index) 群体稳定性指标
P S I = ∑ i n ( 实 际 占 比 − 预 期 占 比 ) ∗ l n ( 实 际 占 比 / 预 期 占 比 ) PSI = \sum_i^n(实际占比-预期占比)*ln(实际占比/预期占比) PSI=i∑n(实际占比−预期占比)∗ln(实际占比/预期占比)
PSI表示样本在分组后,针对不同样本或者不同时间样本,population是否发生了变化,即看各个分数区间内人数占总人数的占比是否有显著变化。
例如,在建模前,对于时间跨度大的样本,对用户分组,按照时间区间将第一个样本时间作为期望值,可衡量样本量是否稳定。
最常用的还是衡量测试样本及模型开发样本评分的的分布差异。按分数分档后,针对不同样本,或者不同时间的样本,看人数占比是否明显。
PSI小于0.1时候模型稳定性很高,0.1-0.2一般,需要进一步研究,大于0.2模型稳定性差,建议修复。
计算步骤