R机器学习:分类算法之logistics回归分类器的原理和实现
一看到logistics回归分类器,第一反应这个不是统计上的logistics回归嘛,其实是一样的,之前也给大家写过logistics回归的做法,今天放在机器学习的框架下再写一次。
logistic regression is a supervised learning method that predicts class membership
何为logistic regression?
logistic分类器是通过概率进行分类的,算法会根据预测变量预测个体属于某一类的概率,然后将这个个体分为概率最大的那一类,当我们的响应变量是二分类的时候我们叫binomial logistic regression,多分类的时候叫multinomial logistic regression。
logistic分类器的分类过程如下图:
上面的概率是如何计算的呢?大家跟着我来用一个实际的例子拆解一遍吧:
假如你是一个文物鉴别专家,现在有一批文物需要你来鉴别他们的真伪,我们只知道文物的铜含量,之前的经验告诉我们铜含量地的文物更容易为假的,你现在想训练一个模型根据铜含量预测文物的真伪(二分类问题)。
我们可以先根据以前的数据将文物真伪和铜含量的关系画出来:
大家仔细看上面的图,我们有一条蓝色的线,这个线是一般线性回归的拟合线,如果我以使得蓝线纵坐标取值为0.5的铜含量为界限,认为0.5以下的是假的文物,0.5以上的是真的文物,那么我这个专家肯定是不合格的(上面3个文物都被分错了),我需要训练一个表现更好的模型。
比如logistic回归分类器,logistic回归分类器对同样的数据拟合情况如下图:
大家再看logistic回归分类器的拟合,此时,如果我以使得蓝线纵坐标取值为0.5的铜含量为界限,认为0.5以下的是假的文物,0.5以上的是真的文物,那么我这个专家就比刚刚那个专家好多了(总共只分错了2个),而且logistic回归分类器把所有的x对应的y的取值都映射到0到1的范围,这个是很切合实际的,刚刚那个线性分类,铜含量过大或者过小都会使得y值超出实际意义的范围。
虽然这个logistic回归分类器的S形的曲线在鉴别文物真伪的任务中表现的蛮好,但是这条线的实际意义是啥呢?
这条S形的曲线就是log odds的值,估计有人一脸懵逼了。接着往下看吧。
接着给大家介绍log odds的概念
不过在这之前还得先写odds,照顾下基础薄弱的同学
看下面的式子:
odds就是阳性的概率比上阴性的概率,在专家判断文物的例子中就是该文物是真的概率比上该文物是假的概率,大家记住:
这个在流行病学中经常见哦,Odds是一个代表某事件发生情况的很重要的指标:
They tell us how much more likely an event is to occur, rather than how likely it is not to occur.
基本上每个小白都明白概率p的意思,但是概率p的取值只能是0到1,但是odds的取值则拓展到了整个正数集。
再回到我们鉴别真伪的例子,我们试着将文物为真的odds和铜含量可视化出来,如下图:
大家可以看到我们的odds确实是取值在0到正无穷的哈,但是铜含量和文物为真的odds的关系是个曲线,这个曲线关系并不好拟合,所以我们就很自然地想到进行变量转换。
告诉我,最常见的变量转换方法是什么?
log转换
太聪明了,已转换不就成了log odds了嘛
于是我们就有了这个转换后的式子(这个就叫做logit函数,就是logistics回归的连接函数):
好,现在我们就来做出经过log转换后的odds与铜含量的关系:
完美拟合的奇迹就出现了,通过上面的整个流程,我们真真切切地将分类问题做成了一般线性回归问题,核心就是logit函数,大家好好体会哈。
转换成线性关系的好处之一就是直观和简单,更重要的是转化为线性关系我们就可以纳入很多别的预测变量啦
Additionally, having a linear relationship means that when we have multiple predictor variables, we can add their contributions to the log odds together to get the overall log odds of a painting being an original, based on the information from all of its predictors.
最后再给大家总结一下,在logistics回归分类器中,我们的思想是从概率p出发,但是p只能在0到1的范围中取值,于是我们由p引出odds的概念,成功的将响应变量的取值拓展到正实数集,再通过多odds的log转换使得预测变量和响应变量之间成线性关系。logistics分类器算法大概就是这么个流程。所以你要明白,我们预测变量的拟合结果其实是logodds,算法会将logodds再逆着上面的流程转化回概率p从而实现预测。
整个流程就是下图啦:
还有几个式子一遍给大家贴上:
logistics分类器实操
光掌握理论不行啊,继续我们的实例操练,现在你手上有泰坦尼克号邮轮的乘客信息,你现在要做的就是根据乘客的特征训练一个logistics分类器预测乘客的生死情况。
我们的数据集大概长这样:
这个数据集总共有12个变量,需要进行一系列的预处理,包括特征提取(Feature extraction),特征再造(Feature creation),特征选择(feature selection),因为数据预处理不是本文的重点所以这儿不展开,经过处理我们得到的数据集如下:
Survived就是乘客的存活情况,是我们的响应变量,其余的都是我们的预测变量。
数据处理好了,通常来讲第一步就是可视化
titanicUntidy <- gather(titanicClean, key = "Variable", value = "Value",
-Survived)
titanicUntidy %>%
filter(Variable != "Pclass" & Variable != "Sex") %>%
ggplot(aes(Survived, as.numeric(Value))) +
facet_wrap(~ Variable, scales = "free_y") +
geom_violin(draw_quantiles = c(0.25, 0.5, 0.75)) +
theme_bw()
titanicUntidy %>%
filter(Variable == "Pclass" | Variable == "Sex") %>%
ggplot(aes(Value, fill = Survived)) +
facet_wrap(~ Variable, scales = "free_x") +
geom_bar(position = "fill") +
theme_bw()
通过上面的单因素可视化,大家可以看到乘客的生存情况和各个预测变量的关系,图很简单,这个就不给大家写解释了。我们直接进入到模型训练部分。
模型训练
模型训练依然分为3步,第一设定任务,第二设定学习器,第三进行训练:
titanicTask <- makeClassifTask(data = imp$data, target = "Survived")#第一步
logReg <- makeLearner("classif.logreg", predict.type = "prob")#第二步
logRegModel <- train(logReg, titanicTask)#第三步
运行上面的代码我们的logistics分类模型logRegModel就训练好了。
然后要做的就是交叉验证。
交叉验证
什么是交叉验证?如果你还问这个问题,请自己转到之前的文章复习一下吧,对于本例我们有一个数据插补的过程,所以为了划分出来的数据集的稳定,每一次抽样我都进行同样的缺失值插补过程
logRegWrapper <- makeImputeWrapper("classif.logreg",
cols = list(Age = imputeMean()))
kFold <- makeResampleDesc(method = "RepCV", folds = 10, reps = 50,
stratify = TRUE)
logRegwithImpute <- resample(logRegWrapper, titanicTask,
resampling = kFold,
measures = list(acc, fpr, fnr))
运行上面的代码即可进行10折验证,得到的结果如下:
可以看到我们的logistics回归分类器的正确率acc.test.mean=0.7965290,假阳性fpr.test.mean=0.2988387,假阴性率为fnr.test.mean=0.1440667。
模型的解释
运行下面的代码我们就可以得到模型的系数,接下来就给大家写写模型系数的解释:
logRegModelData <- getLearnerModel(logRegModel)
coef(logRegModelData)
我们首先有个结局项intercept,这个就表示所有的预测变量都为0的时候我们的乘客存活的log odds为多少,当然了,我们其实更加关系各个预测变量的系数β,这些个系数β表示其他预测变量不变时,某个预测变量增加一个单位,乘客存活的log odds增加β个单位。
但是log odds不好解释啊,所以更为友好的方法是将log odds转化为odds ratio(就是两个风险的比,叫做比值比),那么我们就可以把系数β解释为:这些个系数β表示其他预测变量不变时,某个预测变量增加一个单位,乘客存活的odds相对于参考水平增加e的β次方倍。
For example, if the odds of surviving the Titanic if you’re female are about 7 to 10, and the odds of surviving if you’re male are 2 to 10, then the odds ratio for surviving if you’re female is 3.5. In other words, if you were female, you would have been 3.5 times more likely to survive than if you were male. Odds ratios are a very popular way of interpreting the impact of predictors on an outcome, because they are easily understood.
所以呀,我们当然希望我们的模型也能将odds ratio给输出出来,代码如下:
exp(cbind(Odds_Ratio = coef(logRegModelData), confint(logRegModelData)))
可以看到,很多的比值比都是小于1的,小于1就说明风险降低,举个例子,就看上图的输出嘛,可以看到male的比值比是0.6,我们用1除以0.6=16.7,那么我们就可以解释为:在其余预测变量控制不变的情况下,男性相比女性来说,男性乘客的存活风险是比女性少16.7倍。
大家好好理解上面的文字哦,建议读3遍,思考3分钟。
刚刚写的是0、1预测变量的解释,那么对于连续性的预测变量,其比值比可以解释为:当其余预测变量不变的情况下,变量每增加一个单位,其存活风险相对于这个连续变量的参考水平时的存活风险来说,风险增加e的β次方倍。比如在我们的例子中,famsize的比值比为0.78,1/0.78 = 1.28,我们就可以解释为,乘客家庭成员每增加1个其存活风险减少1.28倍,或者说增加0.78倍,都是一样的哈。
大家好好理解上面的文字哦,建议读3遍,思考3分钟。
对于多分类的因子预测变量,解释通0、1分类,这儿就不给大家细写了。
用模型做预测
大家还是要不忘初心,我们训练模型就是为了让模型给我们做预测的,所以同样的我们接下来看如何用我们刚刚训练好的logistics分类器进行新数据的预测。
新数据依然是在titanic这个包里面哈,预测代码如下:
data(titanic_test, package = "titanic")
titanicNew <- as_tibble(titanic_test)
titanicNewClean <- titanicNew %>%
mutate_at(.vars = c("Sex", "Pclass"), .funs = factor) %>%
mutate(FamSize = SibSp + Parch) %>%
select(Pclass, Sex, Age, Fare, FamSize)
predict(logRegModel, newdata = titanicNewClean)
看图中输出,我们用自己训练的模型输出了每个新数据的存活或者死亡的概率,以及模型预测的存活结局,完美。
今天对logistics分类器的拆解就到这儿,咱们下回见。