一篇就搞定!岭回归、lasso、弹性网络如何用于疾病重要特征选择
点击蓝字 关注我们
大家好,我还是那个大海哥,今天的学习内容大家应该都听说过,超脱于统计三大回归之外的新兴回归家族——弹性网络。
咦?标题写的不是三个吗?怎么只介绍一个?
其实啊,岭回归和lasso回归都是属于弹性网络回归的,说白了,弹性网络就是岭回归和lasso回归的扩展,在损失函数中同时使用L1正则化(与Lasso类似)和L2正则化(与岭回归类似)项,对应的λ1和λ2就是两个正则化的参数,当λ1为0时,弹性网络就变成了岭回归,反之当λ2为0时,就变成了lasso回归,而弹性网络回归则是在λ1和λ2同时非零时,综合了L1和L2正则化的效果。这下小伙伴们明白了吧!那么接下来就用这三种回归来实战一下吧!
今天使用的数据是一个心脏病调查数据,其包含14个属性,分别为患者年龄、性别、胸痛类型等,目标属性是target,包含患病1和非患病0两种。今天我们的目的不是预测样本是否患有心脏病,而是通过这些数据来搭建三种回归模型,进而提取重要特征。
这时候有小伙伴问了,为什么要提取重要特征,直接全部拿来训练不就好了。非也非也!回答之前,大家要先了解偏差和方差,简单来说,模型中的预测因子越多,偏差就会越大,训练的效果就会越好,但那样最终结果会好吗?答案一定是不会,这种低偏差意味着更高的方差,因此预测的准确率就会较差。相反的如果预测因子较少也是不可以的,因为就可能会出现较高的偏差,例如你有几十个变量,你只选用三个变量作为预测因子,那训练的结果一定不是很好,导致预测也不会很好。所以我们需要选择让你摆脱困境的正确变量,那么我们就需要掌握好的特征选择方法,本次大海哥将会教会你三种方法,并且教你什么情况选择哪种方法。话不多说,开始吧!
#首先导入需要用到的R包
library(readr)
library(dplyr)
library(ggplot2)
library(GGally)
library(caret)
library(glmnet)
library(plotmo)
#读取数据
data <- read.csv("heart.csv")
#去除一下空值
df <- na.omit(data)
head(df, 10)
#看一下数据
str(df)
#可以看到有些字段不符合我们的预期,例如性别应该是分类变量,但是是int类型,所以需要做因子化处理
df$sex <- as.factor(df$sex)
df$cp <- as.factor(df$cp)
df$fbs <- as.factor(df$fbs)
df$restecg <- as.factor(df$restecg)
df$exang <- as.factor(df$exang)
df$slope <- as.factor(df$slope)
df$ca <- as.factor(df$ca)
df$thal <- as.factor(df$thal)
df$target <- as.factor(df$target)
#看看数据规模
summary(df)
#可以看到1025名患者中有526名患有心脏病,同时患者平均年龄为54岁,相对年轻,还可以发现男性713名占大多数。
#直接看数据看不出太多潜在的关系,所以需要可视化一下
#我们先看看年龄和结果的关系
# 箱型图
ggplot(df, aes(y = age, x = target, col = target)) +geom_boxplot() + theme_minimal()
#再看看性别以及年龄与结果的区别
ggplot(df, aes(x = target, y = age, fill = sex, col = sex)) +geom_jitter() +theme_minimal()
#可以看到女性60岁以后患病的数量较男性更多
#接下来试试使用回归来观察重要变量吧!
方式一:岭回归
#岭回归需要在线性回归的基础上引入L2正则化,当正则化的lambda参数越大,模型的参数估计就越小,一些无关变量的系数就会趋向于0。
#设置参数
x <- model.matrix(target~., df)[,-1]
y <- df$target
fit.ridge <- glmnet(x, y, family = "binomial", nfolds = 5, alpha = 0, standardize = TRUE)
#看看回归系数的变化
plot_glmnet(fit.ridge, xvar = "rlambda", label = 10)
可以看到随着lambda系数的变小,不同变量的系数也在改变,可以发现CA和CP是最显著的变量,然后我们需要用交叉验证确定构建最小损失模型最合适的lambda值是多少。
lam <- cv.glmnet(x, y, family = "binomial", nfolds = 5, alpha = 0, standardize = TRUE)
plot(lam)
l.min <- lam$lambda.min %>% print()
可以看到lambda为0.0259时,损失函数最小,这个时候搭建的模型分类准确率最高。
方式二:Lasso回归
#lasso与岭回归的最大区别在于,这里系数的值可能会受到L1正则惩罚,以至于它可以为零,所以lasso可以实现剔除某些无关变量达到变量选择的效果。
#构建模型
fit.lasso <- glmnet(x, y, family = "binomial", nfolds = 5, alpha = 1, standardize = TRUE)
plot_glmnet(fit.lasso)
#对比岭回归的结果图可以发现,两者差异相当显著。回归量的重要性可能没有太大改变,但系数的值有很大不同,尤其会受到更多的惩罚。lasso回归显示,That、CA、和CP是更重要的特征,与岭回归结果也类似。
#来看看最优lambda值是多少
lam_lasso <- cv.glmnet(x, y, family = "binomial", nfolds = 5, alpha = 1, standardize = TRUE)
plot(lam_lasso)
print(lam_lasso$lambda.min)
方式三:弹性网络
#回顾前两种方法,lasso的缺陷在于惩罚项太大,而岭回归的模型复杂度太高,弹性网络则可以通过调节lambda1和lambda2这两个正则化参数,控制模型的复杂度和特征选择程度。
#设置弹性网络参数
set.seed(123)
lambda <- seq(-50, 50)
alpha <- seq(-10, 10, length = 20)
searchGrid = expand.grid(.alpha = alpha, .lambda = lambda)
tc <- trainControl(method = "repeatedcv",
number = 5,
repeats = 3)
#训练模型
en.model <- train(target ~ .,
data = df,
method = "glmnet",
tuneGrid = searchGrid,
metric = "Accuracy",
trControl = tc)
plot(en.model)
可以发现当lambda大于0时,惩罚性太大,会导致预测精度下降严重,所以我们需要保持lambda严格小于0。同时我们发现alpha在-10到10之间的变化没有引起模型预测进度变化,结合lasso的结果说明,是由变量相关性所导致的,单个变量与数据结果没有很强的相关性。
点击“阅读原文”进入网址