京公网安备 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-01-20定量报告的核心价值是传递数据洞察,但密密麻麻的表格、复杂的计算公式、晦涩的数值罗列,往往让读者望而却步,导致核心信息被淹 ...
2026-01-20在CDA(Certified Data Analyst)数据分析师的工作场景中,“精准分类与回归预测”是高频核心需求——比如预测用户是否流失、判 ...
2026-01-20在建筑工程造价工作中,清单汇总分类是核心环节之一,尤其是针对楼梯、楼梯间这类包含多个分项工程(如混凝土浇筑、钢筋制作、扶 ...
2026-01-19数据清洗是数据分析的“前置必修课”,其核心目标是剔除无效信息、修正错误数据,让原始数据具备准确性、一致性与可用性。在实际 ...
2026-01-19在CDA(Certified Data Analyst)数据分析师的日常工作中,常面临“无标签高维数据难以归类、群体规律模糊”的痛点——比如海量 ...
2026-01-19在数据仓库与数据分析体系中,维度表与事实表是构建结构化数据模型的核心组件,二者如同“骨架”与“血肉”,协同支撑起各类业务 ...
2026-01-16在游戏行业“存量竞争”的当下,玩家留存率直接决定游戏的生命周期与商业价值。一款游戏即便拥有出色的画面与玩法,若无法精准识 ...
2026-01-16为配合CDA考试中心的 2025 版 CDA Level III 认证新大纲落地,CDA 网校正式推出新大纲更新后的第一套官方模拟题。该模拟题严格遵 ...
2026-01-16在数据驱动决策的时代,数据分析已成为企业运营、产品优化、业务增长的核心工具。但实际工作中,很多数据分析项目看似流程完整, ...
2026-01-15在CDA(Certified Data Analyst)数据分析师的日常工作中,“高维数据处理”是高频痛点——比如用户画像包含“浏览次数、停留时 ...
2026-01-15在教育测量与评价领域,百分制考试成绩的分布规律是评估教学效果、优化命题设计的核心依据,而正态分布则是其中最具代表性的分布 ...
2026-01-15在用户从“接触产品”到“完成核心目标”的全链路中,流失是必然存在的——电商用户可能“浏览商品却未下单”,APP新用户可能“ ...
2026-01-14在产品增长的核心指标体系中,次日留存率是当之无愧的“入门级关键指标”——它直接反映用户对产品的首次体验反馈,是判断产品是 ...
2026-01-14在CDA(Certified Data Analyst)数据分析师的业务实操中,“分类预测”是高频核心需求——比如“预测用户是否会购买商品”“判 ...
2026-01-14在数字化时代,用户的每一次操作——无论是电商平台的“浏览-加购-下单”、APP的“登录-点击-留存”,还是金融产品的“注册-实名 ...
2026-01-13在数据驱动决策的时代,“数据质量决定分析价值”已成为行业共识。数据库、日志系统、第三方平台等渠道采集的原始数据,往往存在 ...
2026-01-13在CDA(Certified Data Analyst)数据分析师的核心能力体系中,“通过数据建立模型、实现预测与归因”是进阶关键——比如“预测 ...
2026-01-13在企业数字化转型过程中,业务模型与数据模型是两大核心支撑体系:业务模型承载“业务应该如何运转”的逻辑,数据模型解决“数据 ...
2026-01-12当前手游市场进入存量竞争时代,“拉新难、留存更难”成为行业普遍痛点。对于手游产品而言,用户留存率不仅直接决定产品的生命周 ...
2026-01-12