目录
引言
前期预留的模型评估问题我想我是时候来解决了!
模型评估的指标到底怎么样才算好?
我来对比试试看
一、分类预测客户流失问题
准备数据
# 导入数据
import pandas as pd #砍树木的工具
df = pd.read_excel('客户流失预警.xlsx')
#特征列切片
#重点:两个[[]]切片出来的为DataFrame(好烧火的木柴),一个[]切片出来的为Series(不好烧火的木桩)
#因为sklearn需要的是木柴,所以需要[[]]
#因为这个数据特征列的字数太多了,我不想敲那么多字,我要用更方便的工具
#df.loc用标签名字索引(搜索提取),df.iloc用标签位置索引(搜索提取)且只能用整数,所以我要用iloc
A = df.iloc[:,:-1] #[:,:]怎么理解呢? 逗号左边处理行,逗号右边处理列。从哪到哪输入数字用:隔开,不输入数字隔开就是全选的意思
#比如df.iloc[1:10,2:5]则取的是第一行到第十行且第二列到第五列的数据
#标签列切片
B = df.iloc[:,-1] #为什么是-1?,因为-1在这里表示最后一列,列数太多了我数不过来了。
# 另外 df.iloc[0]、df.iloc[1]、df.iloc[-1] 分别表示第一行、第二行、最后一行
# 同理df.iloc[:,0]、df.iloc[:,1]、df.iloc[:,-1] 分别表示第一列、第二列、最后一列
库的介绍可参照这篇文章:机器学习入门——认识sklearn的LinearRegression-CSDN博客
使用库构建并训练模型
在写代码之前,通俗的解释一下线性回归和逻辑回归的差异。
简单线性回归:
拿特征预测标签,这些都是数字,数字预测数字,不用计算概率。拿我的工龄(数字)预测我的薪资(数字),用高中学的函数就能表示出来啦。还要什么奔驰宝马勒。
逻辑回归:
主要解决分类问题,例如判断邮件是否为垃圾邮件,或者一个患者是否有某种疾病。
假设我的真实标签中,是垃圾邮件为1,不是垃圾邮件为0。我进行预测的结果是它是垃圾邮件的概率,如果概率大于0.5则这个真实标签是垃圾邮件的概率更大,小于0.5则真实标签不是垃圾邮件的概率更大,这个小数(预测的结果)是预测标签。
简单来说就是我在预测我是好人还是坏人的概率!
因为这里使用数字预测文字(我的数据里面标签值是0或1,把文字转换成了数字才能让计算机读懂),预测出来的结果是从0-1连续的0.1、0.2、0.3等等数不清的数字,不能直接表示我是好人还是坏人,因为好人是1坏人是0嘛,所以这里表示的是判断是好人还是坏人的概率。
我想这样大白话应该能解释清楚伐,还有不清楚的地方欢迎评论区评论,虽然我也不一定会哈哈。
# 导入能够进行逻辑回归的工具,这个工具在sklearn工具库里
from sklearn.linear_model import LogisticRegression
# 构建模型,存储在model,内部的计算过程有大哥帮忙处理封装了,已经是个完整的流水线了!
model = LogisticRegression()
# 拟合特征和标签列,特征放左边,标签放右边,老规矩~
model.fit(A,B)
# 右边fit(A,B)训练完以后呢,去找妈妈(model)把钱给妈妈补贴家用,所以训练好的公式存储在model这个变量里面
# 我比较好奇,我想去看我的工资条里面具体有多少钱(模型的参数),那我要print!
print('各个特征前的系数:',model.coef_) #比如一元函数y=ax+b中的x前面的a,但是这里不是一元函数,是好几元!就好比我有不同项目x1、x2、x3等奖金
print('截距:',model.intercept_) #这里就是一元函数y=ax+b中的b,b不管是几元函数都只有一个!就好比我的底薪!
运行结果如下:
各个特征前的系数为: [[ 2.39764416e-05 8.02191243e-03 1.03854099e-02 -2.53650659e-03 -1.08357285e-04]] 截距为: [-1.42693506e-06]
二、模型评估
这里有个称呼的差异
逻辑回归与线性回归的score
逻辑回归model中的score是计算准确率,而线性回归model中的socre是计算决定系数。
准确率我是这么理解的,因为逻辑回归预测出来的结果不是薪资100块、200块这样的数字,而是这个客户是否会流失的概率,这个概率更接近1打上会流失(1)的标签,更接近0打上不会流失(0)的标签,所以和真实标签之间存在的差距要么是0要么是1。
这样计算的话,SSE残差平方和不就是预测错误的次数嘛。
不过这里的计算公式不是用的决定系数的计算公式,我只是把两个地方连接起来,别被我误导了。
准确率还有更专业的计算公式:
这个是啥???我先不学。
SST总平方和可以理解为预测错误的次数与预测错误的次数的和。
决定系数的公式:
R^2=1-SSE/SST ——我减去预测错误的概率后就是我预测正确的概率,即准确率!
决定系数的理解可以参考这篇文章:机器学习入门——sklearn关于LinearRegression模型评估-CSDN博客
# 这里直接引用score(x,y)左特征右标签,计算准确率Accuracy
print("Accuracy:",model.score(A,B))
# 光一个准确率不够,我还要其他的评价指标,从sklearn中导入评价指标metrics的工具
from sklearn.metrics import mean_squared_error,mean_absolute_error #老朋友了
# 新朋友稍后解释
from sklearn.metrics import precision_score, recall_score, f1_score, roc_auc_score
# 标签预测值,预测是否会离职
y_pred=model.predictd(A) #给它打上一个A的特征,预测它是否有离职的概率,有为1无为0
# 接下来的B都是真是标签,y_pred为预测标签
print("Precision:",precision_socre(B,y_pred))
print("recall_score",recall_score(B,y_pred))
print("f1_score",f1_score(B,y_pred))
输出结果如下:
Accuracy: 0.7878744853045577 Precision: 0.6518218623481782 Recall: 0.4307116104868914 F1 Score: 0.5186855670103093
哎呀这么多东西我都不懂nei,Precision是啥玩意、Recall是啥玩意、F1 Score又是啥玩意。
看这里!我先把混淆矩阵弄弄懂
混淆矩阵
实际值(Actual) | |||
预测值 (Predicted) | Positive(会流失1) | Negative(不会流失0) | |
Positive(1) | 预测流失真流失 True Positive | 预测流失真不流失 False Positive | |
Negative(0) | 预测不流失真流失 False Negative | 预测不流失真不流失 True Negative |
以这个案例来解释的话。
True Positive:这个人的特征已经显然的说明他会流失了,那我们以积极的态度去预测判断他会流失(走就走吧,没关系),最终结果也和真实标签匹配,所以我们是正确的积极态度,有机会让新人入坑让我赚钱咯,我很开心。
False Positive:这个人的特征已经显然的说明他会流失了,那我们还是以积极的态度去判断他会流失,最终结果和真实标签不匹配,所以我们是错误的积极态度,他都不会流失,我积极的以为他会流失,那我积极错了。我犯错了我不知道该怎么办。
False Negative:这个人的特征已经显然的说明他不会流失了,那我们以消极的态度(不流失可能不会增加我们的业绩)去判断他不会流失,最终结果和真实标签不匹配,那我们消极错了,他流失了,我们的业绩可能会增加(可能会有更好的客户来替补上流失的位置)。我犯错了我不知道该怎么办。
True Negative:这个人的特征已经显然的说明他会流失了,那我们以消极的态度去判断他不会流失,最终结果和真实标签匹配,所以我们是正确的消极态度,他不流失,但他又不给我们增加业绩,新人没机会来给我增加业绩了,我好难过。但是我能做出正确的举措来让他消费呀,我又开心了。
综上所述,我应该要以明确的目标来进行相应的策略调整让我赚更多的钱,所以,在我能够做出正确的判断的情况下我能够很开心的去做相应的事情来增加我的收入,我想要保持好的心情,需要比较高的正确的判断率。因此,准确率和精确率,是能让我开心的数据,让我做出正确的举措,谁不想每天都开开心心的呢。
准确率(Accuracy)
你是能让我开心的数据,你是所有对的概率和,你很准确,正确的积极以及正确的消极都能让我做出下一步的举措,你太好了。
精确率(Precision)
虽然你也是能让我开心的数据,但是你只计算在积极的情况下预测对的概率。你全被积极光环包裹,那你特别精确,我称呼你为精确率。
召回率(Recall)
你有让我开心的数据(分子),虽然你的母亲(分母)有消极的数据,但是积极更明显,你意识到有错误的消极,你能够被积极感化召回,所以我叫你召回率。
你们都是我的好孩子,那我希望你们的成绩越高越好。加油努力,学习要使劲。
所以准确率和精确率和召回率这三个评价指标分数越高,说明这个模型的效果越好。
接下来还有一个F1_score
这是什么玩意?
F1_score
你也是衡量这个二分类模型(逻辑回归模型)精确度的指标,不过你同时兼顾了这个模型的精确率和召回率,调和精确率和召回率的大哥(调和平均)。两个小弟打架的时候,你出面协调。
看看下面这个表格:
准确率 | 召回率 | |
A | 80% | 90% |
B | 90% | 80% |
这个时候A模型和B模型哪个比较好呢?我判断不出来,F1大哥出面👇
这么算,就好判断了,谢谢大哥
print("F1 Score:", f1_score(B, y_pred))
输出结果如下:
F1 Score: 0.5186855670103093
ROC曲线下的面积
首先我们得知道ROC曲线是什么。
以真阳性率(TPR),我称它为真积极,为纵坐标。
以假阳性率(FPR),我称它为假积极,为横坐标。
作为直角坐标系,进一步来描绘曲线的就是ROC曲线。
真积极和假积极都是我们正常的人体反应,在这个反应下,我们希望它涵盖的对人体的反应概括能够比较全面(曲线下的面积),不要漏掉真积极或者假积极的概率情况。
比如我真积极的概率为1.0,假积极的概率为0.0
也有可能我真积极的概率为0.0,假积极的概率为1.0(当然还需要其他的很多散点)
那么在这种情况下能够构成我这个人的整体,真假积极都是我会干的事情(散点构成的曲线包围住的面积为1)
就说明这个效果很好,能把我概括出来,当然,这个“我”其实就是这个训练好的模型。
反而如果有些情况(真积极或者假积极的概率没有)反应不出来,说明这个模型有缺陷,面积达不到1,构不成完整的好的模型,说明这个模型没那么好。
注:这个地方我是按自己理解讲的,有错误希望批评指出,我讲的也不一定通俗,可以有自己的思考。
# 标签的概率值(未贴标签前的数据)
# 将特征值A喂给predict_proba,得到各个预测类别的概率
# 与predict不同的是,predict返回的是预测的值,有个proba就是预测各个类别的概率
# [:,1]是预测为1的概率,[:,0]是预测为0的概率
y_prob = model.predict_proba(A)[:,1]
print("y_prob:",y_prob)
# B为真实标签,y_prob为预测概率
print("ROC_AUC_Score:", roc_auc_score(B, y_prob))
输出结果如下:
y_prob: [0.33799156 0.11764196 0.50773512 ... 0.13611248 0.63404568 0.15664546] ROC_AUC_Score: 0.813068201442658
roc_auc_score的计算过程已经被大哥封装好,我们把东西喂给它就能出面积。
当然这个函数还有其他的参数,暂时用不上,不详细展开。
调整模型参数
这个模型我不知道它好不好,我可以调整模型参数再进行模型评估指标的计算来进行不同参数训练后的模型对比,是不是就可以发现到底它好不好了。
调整参数是需要对LogisticRegression这个工具进行细致的挖掘的
把LogisticRegression比作机器人,这个机器人脑子好不好用,腿脚利索吗,脑子和腿脚就是参数
# 查看具体参数内容可以用以下代码实现,具体含义可以学习理论知识来了解
# 如果这个看的太累了,可以用百度,csdn也是不错的选择
??LogisticRegression
调参后训练模型
# 为了和先前已经训练过的模型进行区分,将新的模型存储到model1中
# penalty='l1'的意思是利用L1正则化给这个模型添加了惩罚项防止过拟合
# 过拟合的意思就是这个模型是训练型选手,不是考试型选手,过于在乎刷题的细节,不总结做题及技巧
# 正则化可以理解为给这个模型的学习方法加了一个机制,不要太细节,更好的学会捕捉考点。
# 惩罚项是你再纠结细节我就要打你手心眼!
# sovler='liblinear'有很多细节
# solver这个参数是指定求解最优化问题的算法
# 因为前面规定了用L1正则化,所以liblinear是适合处理这个规定的线性分类算法
# 我不让你纠结细节,那我有很多方法让你不纠结细节,配套的方法就是L1正则化+liblinear
# 线性分类算法需要学习数学知识,这里不进行拓展
model1 = LogisticRegression(penalty='l1', solver='liblinear')
# 老样子左特征右标签
model1.fit(A,B)
model1_score=model1.score(A,B)
print("mode11_score:",model1_score)
输出结果如下:
mode11_score: 0.7877325003549623
这个结果好像差别不大nei
做个列表对比一下
# 将模型的结果对比,选择最佳的模型
# 第一个[]是把默认行和改进行框一起
# 第二个[]是得到默认行的具体内容
# 第三个[]是得到改进行的具体内容
# columns是对列标题进行赋值
# 这里的列数都要对其并且个数要相等
pd.DataFrame([['原模型',model.score(A,B),precision_score(B, y_pred),recall_score(B, y_pred),f1_score(B, y_pred),roc_auc_score(B, y_prob)],
["penalty='l1', solver='liblinear'",model1.score(A,B),precision_score(B, model1.predict(A)),recall_score(B, model1.predict(A)),f1_score(B, model1.predict(A)),roc_auc_score(B, model1.predict_proba(A)[:,1])]],
columns=['参数组合','Accuracy','Precision','Recall','F1','AUC'])
输出结果如下:
参数组合 | Accuracy | Precision | Recall | F1 | AUC |
原模型 | 0.787874 | 0.651822 | 0.430712 | 0.518686 | 0.813068 |
penalty='l1',solver='liblinear' | 0.787733 | 0.650322 | 0.432852 | 0.519756 | 0.812546 |
感觉原模型的默认参数组合最终的模型评估效果好一点,所以选择默认参数的model进行后续的预测。虽然这里改进了个寂寞,但是我对比了其他的模型,更有底气的说明了我的原模型good!
也是很有意义的呐
三、模型预测
# 划重点!!!预测数据格式要与原数据格式相同,列数相同列名也得相同
# 我打了好多回车,我这样看感觉会清晰一点
model.predict(pd.DataFrame([[100,2,100,400,0]],
columns=['账户资金(元)',
'最后一次交易距今时间(天)',
'上月交易佣金(元)',
'累计交易佣金(元)',
'本券商使用时长(年)']))
print("model_predict:",model_predict)
输出结果如下:
model_predict: [1]
我还能改进!!欲知后事如何……
注:原始数据可以在文章上方进行下载提取训练。
本文是根据深圳点宽科技有限公司的课程内容进行个人的学习参考,如有侵权可联系删除。