京公网安备 11010802034615号
经营许可证编号:京B2-20210330
变量选择之SCAD算法
本文提出了一种用于同时达到选择变量和预测模型系数的目的的方法——SCAD。这种方法的罚函数是对称且非凹的,并且可处理奇异阵以产生稀疏解。此外,本文提出了一种算法用于优化对应的带惩罚项的似然函数。这种方法具有广泛的适用性,可以应用于广义线性模型,强健的回归模型。借助于波和样条,还可用于非参数模型。更进一步地,本文证明该方法具有Oracle性质。模拟的结果显示该方法相比主流的变量选择模型具有优势。并且,模型的预测误差公式显示,该方法实用性较强。
SCAD的理论理解
在总结了现有模型的一些缺点之后,本文提出构造罚函数的一些目标:
罚函数是奇异的(singular)
连续地压缩系数
对较大的系数产生无偏的估计
SCAD模型的Oracle性质,使得它的预测效果跟真实模型别无二致。
并且,这种方法可以应用于高维非参数建模。
SCAD的目标函数如下:
SCAD的罚函数与$theta$的(近似)关系如下图所示。
可见,罚函数可以用二阶泰勒展开逼近。

Hard Penality,lasso,SCAD的系数压缩情况VS系数真实值的情况如下图所示。
可以看到,lasso压缩系数是始终有偏的,Hard penality是无偏的,但压缩系数不连续。而SCAD既能连续的压缩系数,也能在较大的系数取得渐近无偏的估计。
这使得SCAD具有Oracle性质。
SCAD的缺点
模型形式过于复杂
迭代算法运行速度较慢
在low noise level的情况下表现较优,但在high noise level的情况下表现较差。
SCAD的实现
SCAD迭代公式
SCAD的目标函数如下:
时,罚函数可以用二阶泰勒展开逼近。
从而,有如下迭代公式:

根据以上公式,代入迭代步骤,即可实现算法。
SCAD的R实现
##------数据模拟--------
library(MASS)
##mvrnorm()
##定义一个产生多元正态分布的随机向量协方差矩阵
Simu_Multi_Norm<-function(x_len, sd = 1, pho = 0.5){
#初始化协方差矩阵
V <- matrix(data = NA, nrow = x_len, ncol = x_len)
#mean及sd分别为随机向量x的均值和方差
#对协方差矩阵进行赋值pho(i,j) = pho^|i-j|
for(i in 1:x_len){ ##遍历每一行
for(j in 1:x_len){ ##遍历每一列
V[i,j] <- pho^abs(i-j)
}
}
V<-(sd^2) * V
return(V)
}
##产生模拟数值自变量X
set.seed(123)
X<-mvrnorm(n = 200, mu = rep(0,10), Simu_Multi_Norm(x_len = 10,sd = 1, pho = 0.5))
##产生模拟数值:响应变量y
beta<-c(1,2,0,0,3,0,0,0,-2,0)
#alpha<-0
#prob<-exp(alpha + X %*% beta)/(1+exp(alpha + X %*% beta))
prob<-exp( X %*% beta)/(1+exp( X %*% beta))
y<-rbinom(n = 200, size = 1,p = prob)
##产生model matrix
mydata<-data.frame(X = X, y = y)
#X<-model.matrix(y~., data = mydata)
##包含截矩项的系数
#b_real<-c(alpha,beta)
b_real<-beta
########----定义惩罚项相关的函数-----------------
##定义惩罚项
####运行发现,若lambda设置为2,则系数全被压缩为0.
####本程序根据rcvreg用CV选出来的lambda设置一个较为合理的lambda。
p_lambda<-function(theta,lambda = 0.025){
p_lambda<-sapply(theta, function(x){
if(abs(x)< lambda){
return(lambda^2 - (abs(x) - lambda)^2)
}else{
return(lambda^2)
}
}
)
return(p_lambda)
}
##定义惩罚项导数
p_lambda_d<-function(theta,a = 3.7,lambda = 0.025){
if(abs(theta) > lambda){
if(a * lambda > theta){
return((a * lambda - theta)/(a - 1))
}else{
return(0)
}
}else{
return(lambda)
}
}
# ##当beta_j0不等于0,定义惩罚项导数近似
# p_lambda_d_apro<-function(beta_j0,beta_j,a = 3.7, lambda = 2){
# return(beta_j * p_lambda_d(beta = beta_j0,a = a, lambda = lambda)/abs(beta_j0))
# }
#
#
# ##当beta_j0 不等于0,指定近似惩罚项,使用泰勒展开逼近
# p_lambda_apro<-function(beta_j0,beta_j,a = 3.7, lambda = 2){
# if(abs(beta_j0)< 1e-16){
# return(0)
# }else{
# p_lambda<-p_lambda(theta = beta_j0, lambda = lambda) +
# 0.5 * (beta_j^2 - beta_j0^2) * p_lambda_d(theta = beta_j0, a = a, lambda = lambda)/abs(beta_j0)
# }
# }
#define the log-likelihood function
loglikelihood_SCAD<-function(X, y, b){
linear_comb<-as.vector(X %*% b)
ll<-sum(y*linear_comb) + sum(log(1/(1+exp(linear_comb)))) - nrow(X)*sum(p_lambda(theta = b))
return (ll)
}
##初始化系数
#b0<-rep(0,length(b_real))
#b0<- b_real+rnorm(length(b_real), mean = 0, sd = 0.1)
##将无惩罚时的优化结果作为初始值
b.best_GS<-b.best
b0<-b.best_GS
##b1用于记录更新系数
b1<-b0
##b.best用于存放历史最大似然值对应系数
b.best_SCAD<-b0
# the initial value of loglikelihood
ll.old<-loglikelihood_SCAD(X = X,y = y, b = b0)
# initialize the difference between the two steps of theta
diff<-1
#record the number of iterations
iter<-0
#set the threshold to stop iterations
epsi<-1e-10
#the maximum iterations
max_iter<-100000
#初始化一个列表用于存放每一次迭代的系数结果
b_history<-list(data.frame(b0))
#初始化列表用于存放似然值
ll_list<-list(ll.old)
#######-------SCAD迭代---------
while(diff > epsi & iter < max_iter){
for(j in 1:length(b_real)){
if(abs(b0[j]) < 1e-06){
next()
}else{
#线性部分
linear_comb<-as.vector(X %*% b0)
#分子
nominator<-sum(y*X[,j] - X[,j] * exp(linear_comb)/(1+exp(linear_comb))) +
nrow(X)*b0[j]*p_lambda_d(theta = b0[j])/abs(b0[j])
#分母,即二阶导部分
denominator<- -sum(X[,j]^2 * exp(linear_comb)/(1+exp(linear_comb))^2) +
nrow(X)*p_lambda_d(theta = b0[j])/abs(b0[j])
#2-(3) :更新b0[j]
b0[j]<-b0[j] - nominator/denominator
#2-(4)
if(abs(b0[j]) < 1e-06){
b0[j] <- 0
}
# #更新似然值
# ll.new<- loglikelihood_SCAD(X = X, y = y, b = b0)
#
#
#
# #若似然值有所增加,则将当前系数保存
# if(ll.new > ll.old){
# #更新系数
# b.best_SCAD[j]<-b0[j]
# }
#
# #求差异
# diff<- abs((ll.new - ll.old)/ll.old)
# ll.old <- ll.new
# iter<- iter+1
# b_history[[iter]]<-data.frame(b0)
# ll_list[[iter]]<-ll.old
# ##当达到停止条件时,跳出循环
# if(diff < epsi){
# break
# }
#
}
}
#更新似然值
ll.new<- loglikelihood_SCAD(X = X, y = y, b = b0)
#若似然值有所增加,则将当前系数保存
if(ll.new > ll.old){
#更新系数
b.best_SCAD<-b0
}
#求差异
diff<- abs((ll.new - ll.old)/ll.old)
ll.old <- ll.new
iter<- iter+1
b_history[[iter]]<-data.frame(b0)
ll_list[[iter]]<-ll.old
}
b_hist<-do.call(rbind,b_history)
#b_hist
ll_hist<-do.call(rbind,ll_list)
#ll_hist
#
iter
##
ll.best<-max(ll_hist)
ll.best
##
b.best_SCAD
##对比
cbind(coeff_glm,b.best,b.best_SCAD,b_real)
##----------ncvreg验证-----------
library(ncvreg)
my_ncvreg<-ncvreg(X,y,family = c("binomial"),penalty = c("SCAD"),lambda = 2)
my_ncvreg$beta
my_ncvreg<-ncvreg(X,y,family = c("binomial"),penalty = c("SCAD"))
summary(my_ncvreg)
my_ncvreg$beta
###用cv找最优的lambda
scad_cv<-cv.ncvreg(X,y,family = c("binomial"),penalty='SCAD')
scad_cv$lambda.min
mySCAD=ncvreg(X,y,family = c("binomial"),penalty='SCAD',lambda=scad_cv$lambda.min)
summary(mySCAD)
ncv_SCAD<-mySCAD$beta[-1]
##对比
myFinalResults<-cbind(无惩罚项回归=coeff_glm, GS迭代 = b.best,
GS_SCAD迭代 = b.best_SCAD, ncvreg = ncv_SCAD,真实值 = b_real)
save(myFinalResults,file = "myFinalResults.rda")
想深入学习统计学知识,为数据分析筑牢根基?那快来看看统计学极简入门课程!
学习入口:https://edu.cda.cn/goods/show/3386?targetId=5647&preview=0
课程由专业数据分析师打造,完全免费,60 天有效期且随到随学。它用独特思路讲重点,从数据种类到统计学体系,内容通俗易懂。学完它,能让你轻松入门统计学,还能提升数据分析能力。赶紧点击链接开启学习,让自己在数据领域更上一层楼!
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
在机器学习建模与数据分析实战中,特征维度爆炸、冗余信息干扰、模型泛化能力差是高频痛点。面对用户画像、企业经营、医疗检测、 ...
2026-03-26在这个数据无处不在的时代,数据分析能力已不再是数据从业者的专属技能,而是成为了职场人、管理者、创业者乃至个人发展的核心竞 ...
2026-03-26在CDA(Certified Data Analyst)数据分析师的能力体系中,线性回归是连接描述性统计与预测性分析的关键桥梁,也是CDA二级认证的 ...
2026-03-26在数据分析、市场研究、用户画像构建、学术研究等场景中,我们常常会遇到多维度、多指标的数据难题:比如调研用户消费行为时,收 ...
2026-03-25在流量红利见顶、获客成本持续攀升的当下,营销正从“广撒网”的经验主义,转向“精耕细作”的数据驱动主义。数据不再是营销的辅 ...
2026-03-25在CDA(Certified Data Analyst)数据分析师的全流程工作中,无论是前期的数据探索、影响因素排查,还是中期的特征筛选、模型搭 ...
2026-03-25在当下数据驱动决策的职场环境中,A/B测试早已成为互联网产品、运营、营销乃至产品迭代优化的核心手段,小到一个按钮的颜色、文 ...
2026-03-24在统计学数据分析中,尤其是分类数据的分析场景里,卡方检验和显著性检验是两个高频出现的概念,很多初学者甚至有一定统计基础的 ...
2026-03-24在CDA(Certified Data Analyst)数据分析师的日常业务分析与统计建模工作中,多组数据差异对比是高频且核心的分析场景。比如验 ...
2026-03-24日常用Excel做数据管理、台账维护、报表整理时,添加备注列是高频操作——用来标注异常、说明业务背景、记录处理进度、补充关键 ...
2026-03-23作为业内主流的自助式数据可视化工具,Tableau凭借拖拽式操作、强大的数据联动能力、灵活的仪表板搭建,成为数据分析师、业务人 ...
2026-03-23在CDA(Certified Data Analyst)数据分析师的日常工作与认证考核中,分类变量的关联分析是高频核心场景。用户性别是否影响商品 ...
2026-03-23在数据工作的全流程中,数据清洗是最基础、最耗时,同时也是最关键的核心环节,无论后续是做常规数据分析、可视化报表,还是开展 ...
2026-03-20在大数据与数据驱动决策的当下,“数据分析”与“数据挖掘”是高频出现的两个核心概念,也是很多职场人、入门学习者容易混淆的术 ...
2026-03-20在CDA(Certified Data Analyst)数据分析师的全流程工作闭环中,统计制图是连接严谨统计分析与高效业务沟通的关键纽带,更是CDA ...
2026-03-20在MySQL数据库优化中,分区表是处理海量数据的核心手段——通过将大表按分区键(如时间、地域、ID范围)分割为多个独立的小分区 ...
2026-03-19在商业智能与数据可视化领域,同比、环比增长率是分析数据变化趋势的核心指标——同比(YoY)聚焦“长期趋势”,通过当前周期与 ...
2026-03-19在数据分析与建模领域,流传着一句行业共识:“数据决定上限,特征决定下限”。对CDA(Certified Data Analyst)数据分析师而言 ...
2026-03-19机器学习算法工程的核心价值,在于将理论算法转化为可落地、可复用、高可靠的工程化解决方案,解决实际业务中的痛点问题。不同于 ...
2026-03-18在动态系统状态估计与目标跟踪领域,高精度、高鲁棒性的状态感知是机器人导航、自动驾驶、工业控制、目标检测等场景的核心需求。 ...
2026-03-18