示例:使用 glmnet 进行二元结果的 LASSO 回归

机器算法验证 r 自习 套索
2022-01-18 23:07:41

我开始涉足使用glmnetLASSO回归,我感兴趣的结果是二分法的。我在下面创建了一个小的模拟数据框:

age     <- c(4, 8, 7, 12, 6, 9, 10, 14, 7) 
gender  <- c(1, 0, 1, 1, 1, 0, 1, 0, 0)
bmi_p   <- c(0.86, 0.45, 0.99, 0.84, 0.85, 0.67, 0.91, 0.29, 0.88)
m_edu   <- c(0, 1, 1, 2, 2, 3, 2, 0, 1)
p_edu   <- c(0, 2, 2, 2, 2, 3, 2, 0, 0)
f_color <- c("blue", "blue", "yellow", "red", "red", "yellow", "yellow", 
             "red", "yellow")
asthma  <- c(1, 1, 0, 1, 0, 0, 0, 1, 1)
# df is a data frame for further use!
df <- data.frame(age, gender, bmi_p, m_edu, p_edu, f_color, asthma)

上述数据集中的列(变量)如下:

  • age(孩子的年龄) - 连续
  • gender- 二进制(1 = 男性;0 = 女性)
  • bmi_p(BMI百分位数) - 连续
  • m_edu(母亲最高教育水平)- 序数(0 = 高中以下;1 = 高中文凭;2 = 学士学位;3 = 学士学位后学位)
  • p_edu(父亲最高学历) - 序数(与 m_edu 相同)
  • f_color(最喜欢的原色)- 标称(“蓝色”、“红色”或“黄色”)
  • asthma(儿童哮喘状态)- 二元(1 = 哮喘;0 = 无哮喘)

此示例的目标是利用 LASSO 从 6 个潜在预测变量(agegenderbmi_pm_edup_eduf_color)的列表中创建预测儿童哮喘状态的模型。显然,这里的样本量是一个问题,但我希望能更深入地了解glmnet当结果是二元(1 = 哮喘)时如何在框架内处理不同类型的变量(即连续、有序、名义和二元) ; 0 = 无哮喘)。

因此,是否有人愿意提供示例R脚本以及使用 LASSO 和上述数据预测哮喘状态的模拟示例的解释?虽然非常基础,但我知道我,可能还有很多其他 CV 上的人,将不胜感激!

3个回答
library(glmnet)

age     <- c(4, 8, 7, 12, 6, 9, 10, 14, 7) 
gender  <- as.factor(c(1, 0, 1, 1, 1, 0, 1, 0, 0))
bmi_p   <- c(0.86, 0.45, 0.99, 0.84, 0.85, 0.67, 0.91, 0.29, 0.88) 
m_edu   <- as.factor(c(0, 1, 1, 2, 2, 3, 2, 0, 1))
p_edu   <- as.factor(c(0, 2, 2, 2, 2, 3, 2, 0, 0))
f_color <- as.factor(c("blue", "blue", "yellow", "red", "red", "yellow", 
                       "yellow", "red", "yellow"))
asthma <- c(1, 1, 0, 1, 0, 0, 0, 1, 1)

xfactors <- model.matrix(asthma ~ gender + m_edu + p_edu + f_color)[, -1]
x        <- as.matrix(data.frame(age, bmi_p, xfactors))

# Note alpha=1 for lasso only and can blend with ridge penalty down to
# alpha=0 ridge only.
glmmod <- glmnet(x, y=as.factor(asthma), alpha=1, family="binomial")

# Plot variable coefficients vs. shrinkage parameter lambda.
plot(glmmod, xvar="lambda")

在此处输入图像描述

分类变量通常首先转换为因子,然后创建预测变量的虚拟变量矩阵,并与连续预测变量一起传递给模型。请记住,glmnet 使用 ridge 和 lasso 惩罚,但可以单独设置为任何一种。

一些结果:

# Model shown for lambda up to first 3 selected variables.
# Lambda can have manual tuning grid for wider range.

glmmod
# Call:  glmnet(x = x, y = as.factor(asthma), family = "binomial", alpha = 1) 
# 
#        Df    %Dev   Lambda
#   [1,]  0 0.00000 0.273300
#   [2,]  1 0.01955 0.260900
#   [3,]  1 0.03737 0.249000
#   [4,]  1 0.05362 0.237700
#   [5,]  1 0.06847 0.226900
#   [6,]  1 0.08204 0.216600
#   [7,]  1 0.09445 0.206700
#   [8,]  1 0.10580 0.197300
#   [9,]  1 0.11620 0.188400
#  [10,]  3 0.13120 0.179800
#  [11,]  3 0.15390 0.171600
# ...

可以从 glmmod 中提取系数。此处显示选择了 3 个变量。

coef(glmmod)[, 10]
#   (Intercept)           age         bmi_p       gender1        m_edu1 
#    0.59445647    0.00000000    0.00000000   -0.01893607    0.00000000 
#        m_edu2        m_edu3        p_edu2        p_edu3    f_colorred 
#    0.00000000    0.00000000   -0.01882883    0.00000000    0.00000000 
# f_coloryellow 
#   -0.77207831 

最后,交叉验证也可用于选择 lambda。

cv.glmmod <- cv.glmnet(x, y=asthma, alpha=1)
plot(cv.glmmod)

在此处输入图像描述

(best.lambda <- cv.glmmod$lambda.min)
# [1] 0.2732972

我将使用包 enet,因为这是我的首选方法。它更灵活一些。

install.packages('elasticnet')
library(elasticnet)

age <- c(4,8,7,12,6,9,10,14,7) 
gender <- c(1,0,1,1,1,0,1,0,0)
bmi_p <- c(0.86,0.45,0.99,0.84,0.85,0.67,0.91,0.29,0.88)
m_edu <- c(0,1,1,2,2,3,2,0,1)
p_edu <- c(0,2,2,2,2,3,2,0,0)
#f_color <- c("blue", "blue", "yellow", "red", "red", "yellow", "yellow", "red", "yellow")
f_color <- c(0, 0, 1, 2, 2, 1, 1, 2, 1)
asthma <- c(1,1,0,1,0,0,0,1,1)
pred <- cbind(age, gender, bmi_p, m_edu, p_edu, f_color)



enet(x=pred, y=asthma, lambda=0)

只是为了扩展 pat 提供的出色示例。原始问题提出了序数变量(m_edu,p_edu),级别之间具有固有顺序(0 < 1 < 2 < 3)。在 pat 的原始答案中,我认为这些被视为名义分类变量,它们之间没有顺序。我可能错了,但我相信这些变量应该被编码,以便模型尊重它们的固有顺序。如果这些被编码为有序因子(而不是像 pat 的答案中的无序因子),那么 glmnet 给出的结果略有不同......我认为下面的代码正确地将序数变量包含为有序因子,它给出的结果略有不同:

library(glmnet)

age     <- c(4, 8, 7, 12, 6, 9, 10, 14, 7) 
gender  <- as.factor(c(1, 0, 1, 1, 1, 0, 1, 0, 0))
bmi_p   <- c(0.86, 0.45, 0.99, 0.84, 0.85, 0.67, 0.91, 0.29, 0.88) 
m_edu   <- factor(c(0, 1, 1, 2, 2, 3, 2, 0, 1), 
                  ordered = TRUE)
p_edu   <- factor(c(0, 2, 2, 2, 2, 3, 2, 0, 0), 
                  levels = c(0, 1, 2, 3), 
                  ordered = TRUE)
f_color <- as.factor(c("blue", "blue", "yellow", "red", "red", 
                       "yellow", "yellow", "red", "yellow"))
asthma <- c(1, 1, 0, 1, 0, 0, 0, 1, 1)

xfactors <- model.matrix(asthma ~ gender + m_edu + p_edu + f_color)[, -1]
x        <- as.matrix(data.frame(age, bmi_p, xfactors))

# Note alpha=1 for lasso only and can blend with ridge penalty down to
# alpha=0 ridge only.
glmmod <- glmnet(x, y=as.factor(asthma), alpha=1, family="binomial")

# Plot variable coefficients vs. shrinkage parameter lambda.
plot(glmmod, xvar="lambda")

在此处输入图像描述