一篇就搞定!岭回归、lasso、弹性网络如何用于疾病重要特征选择






一篇就搞定!岭回归、lasso、弹性网络如何用于疾病重要特征选择

大海哥  生信果  2023-07-30 19:01:38

点击蓝字 关注我们


大家好,我还是那个大海哥,今天的学习内容大家应该都听说过,超脱于统计三大回归之外的新兴回归家族——弹性网络。

咦?标题写的不是三个吗?怎么只介绍一个?

其实啊,岭回归和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$targetfit.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的结果说明,是由变量相关性所导致的,单个变量与数据结果没有很强的相关性。


总而言之,特征选择方法有多种,主要取决于大家的数据以及你想要用它做什么。在数据方差很小的情况下,回归岭可以给出非常令人满意的结果。如果您想要选择变量,lasso回归可以成为你的关键工具,并帮助你识别真正重要的变量。而弹性网络可能是在许多情况都能够给出你最佳结果的方法,但它不一定是你最优先考虑到的方法,更重要的是要优先学会使用基本的方法来观察数据,小伙伴们你们觉得呢?(最后推荐一下大海哥新开发的零代码云生信分析工具平台,包含超多零代码小工具,上传数据一件出图,感兴趣的小伙伴欢迎来参观哟,网址:http://www.biocloudservice.com/home.html


点击“阅读原文”进入网址