[R] Machine Learning---Logistic Regression / 逻辑斯回归
这篇要记录逻辑斯回归分析(Logistic Regression Analysis),
一种延伸线性回归分析(Linear Regression Analysis)的概念,
※※※线性回归分析的概念※※※
从我们有兴趣的目标群体收集变数, 包含 反应变数(Response Variable)与预测变数(Predictive Variable),
用符号来表示, Y就是反应变数, {X1,...,XP} 就是预测变数. 我们希望了解, Y的数值表现是不是与X有关?
也就是想要知道, 是否存在某一个函数f, 可以把Y与X的关系建立起来:
Y=f(X)
或者更简单一点说, Y的数值变化是不是能用X的线性组合来描述? 就像是下面所示:
Y=b0+b1*X1+b2*X2+...+bP*XP
上式很清楚表达了, X1变动1个单位, Y会变动 b1个单位. (因为 Y=b1*1, 其他相对而言都是常数, 不会变动)
当然, 这样的线性组合无法合理解释真实世界呈现的风貌, 所以 就给他加了随机误差在等式的右边. 变成了
Y=b0+b1*X1+b2*X2+...+bP*XP+E
这个E是随机误差的意思, 条件松一点来说, 我们要求 E 的平均数是0就好了, 而标准教科书通常会假设E会服从常态分配!!
举个最简单例子: 身高能够预测体重吗?
通常, 身高较高的人体重较重, 可是总有人是天生竹竿身材,
因此, 这个随机误差就是要用来描述 虚胖/结实/苗条/过瘦 情况, 也就是:
就算一样是175公分的人(X=175.0), 体重不一定会相同(可能是y=80.0公斤, 或者 y=70.0公斤)
用个虚拟的数据化个图来看看,
可以看到, 身高越高, 体重会缓缓上升, 而整体趋势就是用最小平方法求出来的估计的回归线:
Weight=16.9588+0.3195*Height
也就是我们可以用这条估计出来的回归线, 猜测身高170公分的人的体重.
16.9588+0.3195*170=71.2738
大概是71公斤!!!
※※※线性回归分析应注意事项※※※
在进行线性回归分析前, 要注意一些事:
1.反应变数是连续型变数吗? 如果不是连续型变数, 而是Binary data, 上面介绍的回归分析是不恰当的
这一个问题就延伸出 逻辑斯回归分析.
2.通常会假设反应变数是服从常态分配, 不过有分析过实际资料的人都知道, 数据怎么可能是常态麻
虽然这个假设在估计回归系数值不需要, 但在做统计推论时就非常重要.
3.有发现我们关心的变数间是如何被连结起来吗?
我们直接假设体重是身高的直线函数,
Weight=b0+b1*Height+E
也就是我们将身高与体重的关系「直接」连结起来了!
然而, 在现实生活中不可能有这么简单的事发生.
※※※逻辑斯回归分析的概念※※※
现在换个问题:
有什么条件的车主会额外加买保险?
这问题点典型的商业智慧分析应用. 保险公司希望提高客户投保率, 不希望乱枪打鸟的让业务员去拜访客户,
将时间浪费在投保意愿低的客户身上.
这时候一样会去收集数据, 会有反应变数Y与预测变数{X1,...,XP}
不过, 想解决的问题是「会不会加买保险?」, 所以收集的Y最直接就是 买/不买 两种.
在统计上, 习惯用数字来表示这两种购买行为. 1表示 会购买保险, 0表示 不会购买保险.
然后预测变数可能就是 性别/职业/薪水/已购买寿险数量...等等.
线姓回归有办法处理这样的问题吗?
假设现在收集的预测变数是已购买的寿险数(有投保观念的人或许比较有可能额外加保车险).
在线性回归的表示是:
加保车险=b0+b1*已购买的寿险数+E
散布图是
可以看到, 购买不同寿险张数的客户都有加保的意愿
然而我们是无法从这张图看到到底是寿险买多比较有意愿加保, 还是买少的加保意愿强?
如果还是估计线性回归的参数就变成:
是否加保=0.057840+0.025833*已购买的寿险数
现在有个新客户已知他有购买寿险保单2张, 那你要不花点时间推销他加保车险?
应用估计出来的回归式:
0.057840+0.025833*2=0.1095
这.....0.1095我怎么知道他是买不买啊?
这个就是线性回归应用在二元反应变数的问题之一: 预测值不在合理的解释范围/空间中
换个角度想, 我们可以用列连表来看一下购买比例如何
NLI
Purchase 0 1 2 3 4
No 94.12% 95.38% 90.00% 81.82% 62.50%
Yes 5.88% 4.62% 10.00% 18.18% 37.50%
上表的每一行总和都是100%, 因为我的计算方式是: 在相同已购买保单数下, 是否加保车险的比例.
显然, 加保的比例随著原本已购买寿险的张数提高(从5.88%到最后的37.5%), 看来真的是有投保观念的人买车容易再加保啊!!!
这时, 统计学家就想到, 那为什么我们不转个弯, 换不同的方向问问题呢?
「已购买寿险数量是不是会影响加保车险的机率?」
所以目标变成:
加保机率=f(已购买寿险数量)
如果要像线性回归模型一样有合理的统计模型, 首先要考虑的两件事就是
●f这个数值可能范围只能在0到1之间, 因为机率值最大就是100%, 最小就是0%.
●模仿线性回归模型, 我们希望b0+b1*X1+b2*X2+...+bP*XP的取值是从负无穷到正无穷.
如此一来, 在做数值分析求估计值时, 不收敛问题会少一点.
为了要做到这两件事, 不失一般性, 考虑b0+b1*X1就好!!
因为,
负无穷 < b0+b1*X1 < 正无穷 隐含 负无穷 < -(b0+b1*X1) < 正无穷
所以,
0 < exp[-(b0+b1*X1)] < 正无穷, 其中的exp()是自然指数的意思.
再来, 全部加1
1 < 1+exp[-(b0+b1*X1)] < 正无穷
最后, 取倒数
0 < exp(b0+b1*X1)/[1+exp(b0+b1*X1)] < 1
这样就满足上面两条件,
所以, 我们就直接把会加保车险的机率P(X)连结成
P(X1)= exp(b0+b1*X1)/[1+exp(b0+b1*X1)]
其实,上面的等号右边是个逻辑斯函数(Logistic function)
所以, 我们可以合理化问题转成逻辑斯回归:
加保机率=exp(b0+b1*已购买寿险数量)/[1+exp(b0+b1*已购买寿险数量)]
而b0跟b1可以用概似函数估算出来, 估计后带入上式就可以估计会加保车险的机率.
在实际应用上面, 我们可以反求具有什么特点的客户会有够高机会加保车险.
如此, 就可以提高贩售出保险的比例, 不用乱枪打鸟, 白做工.
※※※逻辑斯回归分析的R程式码※※※
延续上面的例子, 我们进入正式数据分析
#载入ISLR资料库, 我们需要的资料在这资料库里面
library(ISLR)
#看一下"Caravan",大型敞篷车投保资料集,的样本数有多少?(5822),收集的变数有几个?(86)
dim(Caravan)
#可以看一下收集的86个变数名称. 注意到最后一个是反应变数Purchase
names(Caravan)
#我们选择其中的ALEVEN变数, 这一个是「购买寿险的数量」, 其中第775笔是购买八张保单的客户
#因为在5822中只有一个买8张保单的客户, 其余客户购买数皆不超过4张, 所以我们先不考虑该客户
attach(Caravan)
ALEVEN<-ALEVEN[-775]
YN<-as.numeric(Purchase[-775])-1
#使用R中的glm函数估计逻辑回归函数, 记得在family指定binomial
fit<-summary(glm(YN~ALEVEN,family=binomial))
fit
Estimate Std. Error z value Pr(>|z|)
(Intercept) -2.78810 0.05711 -48.821 < 2e-16 ***
ALEVEN 0.33485 0.11340 2.953 0.00315 **
所以估计的逻辑斯回归是
加保机率=exp(-2.788+0.3349*已购买寿险数量)/[1+exp(-2.788+0.3349*已购买寿险数量)]
如果求加保机率要超过1成才优先考虑为高机率加保潜在客户, 那我们就可以反求
exp(-2.788+0.3349*已购买寿险数量)/[1+exp(-2.788+0.3349*已购买寿险数量)] > 0.1
==>已购买寿险数量 > [log(0.1/0.9)+2.788]/0.3349 = 1.76
我们发现, 如果购买寿险保单达2张, 那该客户就有高达1成以上机率会加购车险,
所以, 具有已购买两张或以上的寿险客户是优先推销加保车险客户!!!
※※※逻辑斯回归分析的R程式码与机器学习※※※
与KNN使用相同资料, 所以以下某些陈述也与KNN演算法相同, 对KNN演算法有兴趣读者请自行连结过去
#载入ISLR资料库, 我们需要的资料在这资料库里面
library(ISLR)
#看一下"Caravan",大型敞篷车投保资料集,的样本数有多少?(5822),收集的变数有几个?(86)
dim(Caravan)
#可以看一下收集的86个变数名称. 注意到最后一个是反应变数Purchase
names(Caravan)
#先看一下变数的叙述统计量
summary(Caravan)
#计算会购买保险的比例是多少?(5.977%)
table(Caravan$Purchase)/dim(Caravan)[1]
使用训练与测试82法则, 则取训练笔数:测试笔数=4650:1172
#进行资料整理与分割
Purchase.01<-as.numeric(Caravan[,"Purchase"])-1
train.index<-1:4650
train.X<-Caravan[train.index,-86]
train.Y<-Purchase.01[train.index]
test.X<-Caravan[-train.index,-86]
test.Y<-Purchase.01[-train.index]
train.D<-data.frame(train.X,train.Y)
#进行逻辑斯回归估计
logistic<-glm(train.Y~.,data=train.D,family=binomial)
summary(logistic)
#将测试集的预测机率估计出来
pred<-predict(logistic,newdata=test.X,type="response")
pred[1:10]
#设定会加保车险的机率超过10%就是潜在会加保的客户,把这些人识别出来
Index<-which(pred>=0.1)
predict.01<-rep(0,length(test.Y))
predict.01[Index]<-1
#建立混淆矩阵
Confusion.matrix<-table(Truth=test.Y,Prediction=predict.01)
#我们真正关心的是, 在我们预测会加保的客户中, 实际上真的有购买的比例是多少? 答案是18.37%
Confusion.matrix[2,2]/sum(Confusion.matrix[,2])
#我们可以试著找找看, 预测的机率值超过多少当作值得拜访客户的门槛值?
#最后, 发现只要新进客户的预测加保机率估计值超过5%就值得去推销拜访
Pro<-seq(0.01,0.9,0.01)
Success.Rate<-numeric(length(Pro))
for(i in 1:length(Pro))
{
Index<-which(pred>=Pro[i])
predict.01<-rep(0,length(test.Y))
predict.01[Index]<-1
Confusion.matrix<-table(Truth=test.Y,Prediction=predict.01)
Success.Rate[i]<-Confusion.matrix[2,2]/sum(Confusion.matrix[,2])
print(c(i,Success.Rate[i]))
}
Pro[min(which(Success.Rate>=0.05977*2))]
#以图形展现不同门槛值对预测成功率的变化
plot(Pro,Success.Rate,pch=19,lwd=3,ylab="针对测试集的成功预测机率值",xlab="值得拜访的机率门槛值")
lines(Pro,Success.Rate,lwd=1,lty=2,col=4)
abline(h=0.05977,col=2)
abline(h=0.05977*2,col=2,lwd=2,lty=2)
text(0.2,0.07,"随机拜访成功率5.977%")
text(0.2,0.13,"比随机拜访成功率多2倍,11.954%")
abline(v=0.05,col=6,lwd=2,lty=2)