看了很多用python画的校准曲线,基本都是按照sklearn的做法分bin画点的。
感觉不好看,而且总要调bin数很麻烦,bin数取不好了画出来校准曲线歪的很。
R语言Rms包的画法
然后尝试学习R语言的画法。
看到了这篇文章:
R语言手动绘制连续线条的校准曲线(Calibration curve)(4)
才知道rms包做的校准曲线之所以好看,是因为加了lowess平滑。
# 下述代码段来自https://mp.weixin.qq.com/s/LqeqziJJh0KmImRskvh04w
# 手动画法
fit<-glm(low~ age +lwt + race +smoke + ptl +ht + ui +ftv,
family = binomial("logit"),data =bc_train)
options(digits = 3, scipen=999)
predicted <- predict(fit,type = c("response"))
p <- sort(predicted)
p<-as.numeric(p)
predy <- seq(p[5], p[nrow(bc_train) - 4], length = 50)
# 最关键的一步,使用lowess平滑校准曲线
smo <- lowess(predicted, as.numeric(fit$y), iter = 0)
plot(smo, asp = 1, xlim = c(0, 1), ylim = c(0, 1))
Python中的复现
然后在python中进行复现
from statsmodels.nonparametric.smoothers_lowess import lowess
import matplotlib.pyplot as plt
import seaborn as sns
def better_CCcurve(yyP,yy):
# yyP为模型预测值
# yy为真实label
# 对P值排序并对预测值抽取序列
p = yyP
q = yy# .tolist()
p1 = np.sort(p)
# predy = np.linspace(p1[5], p1[-5], num=50)
# 对预测的X和Y进行lowess回归拟合
smo = lowess(q, p, frac=2/3, it=0, delta = 0.01 * (np.max(p) - np.min(p)))
fig = plt.figure(figsize=(5, 5), dpi = 150)
ax = fig.add_subplot()
sns.lineplot(x=smo[:, 0], y=smo[:, 1], color='blue')
plt.plot([0, 1], [0, 1], color='black', linestyle='--')
plt.title('Lowess smoothing')
plt.xlabel('Predicted Probability')
plt.ylabel('Observed')
plt.xlim(-0.1, 1.1)
plt.ylim(-0.1, 1.1)
ax.set_aspect('equal', adjustable='box')
plt.show()
结果对比
上图为Rms包的原始结果
此图为手动拟合生成的数据点
此图为python中复现的结果
此图为二者的叠加,可见手动拟合的代码拟合的是apparent这条线。
然后再将python画的图叠在上面,发现曲线基本上一致。
又换了一个数据集来跑,效果还是一致的。
R语言logistic回归:训练集、验证集的校正曲线calibration curve的绘制及优化调整
最后
大体上拟合的很完美,但是发现Rms包做的曲线比手动拟合的要短一截,两端分别丢掉了几个点。
回头有时间了研究一下为什么要丢掉这几个点。