最优化方法期末大作业 --LASSO算法
引言
LASSO(Least Absolute Shrinkage and Selection Operator)是一种在统计学和机器学习中非常重要的回归分析方法。它由Robert Tibshirani于1996年提出,主要用于解决传统线性回归在处理高维数据时遇到的多重共线性问题,并实现变量选择,从而提高模型的预测能力和解释性。其发展历史可以追溯到统计学和机器学习领域的多位重要人物和概念。例如,费希尔(Ronald Fisher)和皮尔逊(Karl Pearson)在统计学领域的贡献,以及学生氏(William Sealy Gosset)的学生分布等。这些早期的工作为后来的LASSO算法提供了理论和方法论的基础。
LASSO的计算通常使用坐标下降法、梯度下降法或者最小角回归法等算法来实现,这些算法通过迭代优化逐步逼近最优解。LASSO的正则化参数λ是一个关键的超参数,它控制着模型复杂度和特征选择的程度。选择合适的λ值对于实现最佳模型性能至关重要。
在统计学领域,LASSO通过引入L1正则化项,有效地解决了多重共线性问题,并且能够产生稀疏的模型系数,即某些系数可以被压缩至零,从而实现特征选择。这使得LASSO在变量众多的高维数据集上特别有效。在机器学习领域,LASSO因其正则化的特性,被广泛应用于特征选择和模型构建中。例如,在金融风控、生物信息学、经济学等领域,LASSO回归可以帮助筛选出对预测目标影响最大的关键特征,构建简洁且具有解释性的模型。
LASSO 优化问题的各种形式
LASSO优化问题是一种在统计学和机器学习中广泛使用的回归分析技术,其主要目标是在保持模型预测准确性的同时,通过正则化实现变量选择和模型复杂度的降低。以下是LASSO优化问题的一些常见形式:
标准LASSO问题
LASSO问题的标准形式可以表示为一个带L1正则项的最小化问题:
min
β
{
1
2
n
∥
X
β
−
y
∥
2
2
+
λ
∥
β
∥
1
}
\min_{\beta} \left\{ \frac{1}{2n} \|\mathbf{X}\beta - \mathbf{y}\|_2^2 + \lambda \|\beta\|_1 \right\}
βmin{2n1∥Xβ−y∥22+λ∥β∥1}
其中,(\mathbf{X}) 是设计矩阵,(\mathbf{y}) 是观测向量,(\beta) 是回归系数向量,(\lambda) 是正则化参数,控制着正则项的强度,(n) 是样本数量。这个形式通过最小化残差平方和的同时,对系数的绝对值求和进行惩罚,促使一些系数变为零,实现特征选择。
Fused LASSO
Fused LASSO是LASSO的一种变体,它不仅惩罚系数的绝对值之和,还惩罚相邻系数之间的差异,使得系数向量更加平滑。其形式如下:
min
β
{
1
2
n
∥
X
β
−
y
∥
2
2
+
λ
1
∥
β
∥
1
+
λ
2
∑
i
=
2
p
∣
β
i
−
β
i
−
1
∣
}
\min_{\beta} \left\{ \frac{1}{2n} \|\mathbf{X}\beta - \mathbf{y}\|_2^2 + \lambda_1 \|\beta\|_1 + \lambda_2 \sum_{i=2}^p |\beta_i - \beta_{i-1}| \right\}
βmin{2n1∥Xβ−y∥22+λ1∥β∥1+λ2i=2∑p∣βi−βi−1∣}
其中,
λ
1
\lambda_1
λ1 和
λ
2
\lambda_2
λ2是正则化参数,控制L1正则项和系数平滑度。
Elastic Net
Elastic Net结合了LASSO和Ridge回归的特点,通过L1和L2正则项的结合来实现特征选择和模型稳定性的平衡。其优化问题形式为:
min
β
{
1
2
n
∥
X
β
−
y
∥
2
2
+
λ
1
∥
β
∥
1
+
λ
2
2
∥
β
∥
2
2
}
\min_{\beta} \left\{ \frac{1}{2n} \|\mathbf{X}\beta - \mathbf{y}\|_2^2 + \lambda_1 \|\beta\|_1 + \frac{\lambda_2}{2} \|\beta\|_2^2 \right\}
βmin{2n1∥Xβ−y∥22+λ1∥β∥1+2λ2∥β∥22}
其中,
λ
1
\lambda_1
λ1 和
λ
2
\lambda_2
λ2 分别控制L1和L2正则项的强度。
Logistic LASSO
当应用于分类问题时,LASSO可以与逻辑回归结合,形成Logistic LASSO。其目标函数为:
min
β
{
−
ℓ
(
β
)
+
λ
∥
β
∥
1
}
\min_{\beta} \left\{ -\ell(\beta) + \lambda \|\beta\|_1 \right\}
βmin{−ℓ(β)+λ∥β∥1}
其中,
−
ℓ
(
β
)
-\ell(\beta)
−ℓ(β) 是逻辑回归的对数似然函数,
λ
\lambda
λ是正则化参数。
Group LASSO
Group LASSO是另一种LASSO的变体,它允许对变量进行分组,并在组级别上应用正则化。其目标函数为:
min
β
{
1
2
n
∥
X
β
−
y
∥
2
2
+
λ
∑
g
=
1
G
w
g
∥
β
g
∥
2
}
\min_{\beta} \left\{ \frac{1}{2n} \|\mathbf{X}\beta - \mathbf{y}\|_2^2 + \lambda \sum_{g=1}^G w_g \|\beta_g\|_2 \right\}
βmin{2n1∥Xβ−y∥22+λg=1∑Gwg∥βg∥2}
其中,
β
g
\beta_g
βg是属于第(g)组的系数向量,
w
g
w_g
wg是对应组的权重,(G) 是组的总数。
Adaptive LASSO
Adaptive LASSO通过修改标准LASSO中的惩罚项来提高模型的相合性。其形式为:
min
β
{
1
2
n
∥
X
β
−
y
∥
2
2
+
λ
∑
j
=
1
p
∣
β
j
∣
1
−
∣
β
^
j
0
∣
}
\min_{\beta} \left\{ \frac{1}{2n} \|\mathbf{X}\beta - \mathbf{y}\|_2^2 + \lambda \sum_{j=1}^p \frac{|\beta_j|}{1 - |\hat{\beta}_j^0|} \right\}
βmin{2n1∥Xβ−y∥22+λj=1∑p1−∣β^j0∣∣βj∣}
其中,
β
^
j
0
\hat{\beta}_j^0
β^j0是不包含第(j)个变量时的最小二乘估计系数。
优化算法
LASSO优化问题由于其非光滑性(由于L1正则项的存在),需要使用特殊的优化算法来求解。以下是一些常用的优化算法及其优缺点:
坐标下降法(Coordinate Descent
import numpy as np
def lasso_coordinate_descent(X, y, lmbda, max_iter=1000, tol=1e-5):
n_samples, n_features = X.shape
beta = np.zeros(n_features) # 初始化回归系数
for iteration in range(max_iter):
for j in range(n_features): # 对每个特征进行更新
# 计算当前特征的梯度
grad = (X[:, j] @ (X @ beta - y)) / n_samples
# 应用软阈值操作
beta[j] = max(0, beta[j] - lmbda / n_samples) - (grad - lmbda * np.sign(beta[j]) * (beta[j] > 0))
# 检查收敛性
if np.linalg.norm(X @ beta - y, ord=2) < tol:
break
return beta
- 优点:
- 简单易实现。
- 对于每个坐标(变量)可以独立更新,易于并行化。
- 当特征数量远大于样本数量时特别有效。
- 缺点:
- 收敛速度可能较慢,特别是当正则化参数较大时。
- 对于非凸问题,可能收敛到局部最优解。
梯度下降法(Gradient Descent
梯度下降法是一种用于求解LASSO问题的优化算法,但由于LASSO问题包含非光滑的L1正则项,直接使用传统梯度下降法是不可行的。因此,通常使用近端梯度下降(Proximal Gradient Descent)来求解LASSO问题。
import numpy as np
def proximal_operator(z, lambda_, L):
return np.sign(z) * np.maximum(np.abs(z) - lambda_ / L, 0)
def proximal_gradient_descent(X, y, lambda_, L=1.0, tol=1e-4, max_iter=1000):
n_samples, n_features = X.shape
beta = np.zeros(n_features)
for k in range(max_iter):
# 计算梯度
grad = (1 / n_samples) * np.dot(X.T, X @ beta - y)
# 进行近端操作
z = beta - L * grad
beta = proximal_operator(z, lambda_ / L, L)
# 检查收敛性
if np.linalg.norm(beta - proximal_operator(beta, lambda_ / L, L), ord=2) < tol:
break
return beta
- 优点:
- 直观且容易理解。
- 适用于大规模问题。
- 缺点:
- LASSO问题的目标函数不是处处可微的,因此传统梯度下降法不适用。
- 需要对绝对值函数进行平滑近似,这可能影响算法的效率罚函数法(Penalty Function Methods)
罚函数法是一种优化技术,它将带约束的优化问题转化为无约束问题。在LASSO问题中,罚函数法可以用来处理L1正则化项。下面是一个使用罚函数法求解LASSO问题的简单示例代码:
import numpy as np
def lasso_penalty_method(X, y, lambda_, rho, max_iter=1000, tol=1e-5):
n_samples, n_features = X.shape
beta = np.zeros(n_features)
for _ in range(max_iter):
# 计算当前解的梯度
grad = np.dot(X.T, X).dot(beta) - np.dot(X.T, y)
# 应用罚函数
penalty = lambda_ / rho * np.sign(beta)
beta -= (grad + penalty) / (np.dot(X.T, X) + rho / n_samples)
# 检查收敛性
if np.linalg.norm(grad + penalty, ord=2) < tol:
break
return beta
- 优点:
- 将带约束的优化问题转化为无约束问题,可以使用无约束优化技术求解。
- 适用于求解包含复杂约束的优化问题。
- 缺点:
- 需要选择合适的罚函数和调整罚函数参数,这可能需要多次尝试。
- 计算罚函数的导数可能比较复杂。
FISTA(Fast Iterative Shrinkage-Thresholding Algorithm)
FISTA(Fast Iterative Shrinkage-Thresholding Algorithm)是一种加速的迭代阈值算法,用于求解带有L1正则项的优化问题,如LASSO问题。以下是FISTA算法的关键代码示例,这段代码通常用于求解形如
min
x
1
2
∥
A
x
−
b
∥
2
2
+
λ
∥
x
∥
1
\min_x \frac{1}{2} \|Ax - b\|^2_2 + \lambda \|x\|_1 \
xmin21∥Ax−b∥22+λ∥x∥1
import numpy as np
def fista(A, b, lambda_, x0, L0=1.05, eta=1.01, tol=1e-5, max_iter=1000):
m, n = A.shape
x = x0.copy()
y = x0.copy()
t = 1
g = A.T @ (A @ x - b)
L = L0
for k in range(max_iter):
z = y - (1/L) * g # 计算近似问题的解
x = np.sign(z) * np.maximum(np.abs(z) - (lambda_ / L), 0) # 软阈值操作
t_next = (1 + np.sqrt(1 + 4 * t * t)) / 2 # 更新加速因子
y = x + (t - 1) / t_next * (x - x0) # FISTA更新公式
x0 = x.copy() # 更新x0为当前x
t = t_next # 更新加速因子
# 检查收敛性
if np.linalg.norm(x - y, 'fro') < tol:
break
# 步长更新(使用backtracking line search)
L = eta * L
g_new = A.T @ (A @ x - b)
if np.dot(g_new, g_new - g) < -0.5 * L * np.linalg.norm(g_new - g, 'fro') ** 2:
L /= eta # 步长调整
g = g_new # 更新梯度
return x
- 优点:
- 对于某些问题,具有更快的收敛速度。
- 可以应用于更广泛的优化问题,包括LASSO。
- 缺点:
- 实现比简单的坐标下降法复杂。
- 需要选择合适的步长参数。
自适应LASSO
自适应LASSO(Adaptive LASSO)是一种变量选择方法,它通过引入权重来调整LASSO回归中的惩罚项,从而实现对不同变量的不同惩罚力度。这使得自适应LASSO能够更有效地处理具有多重共线性的数据集。在R语言中,可以使用glmnet包来实现自适应LASSO。以下是一个使用glmnet进行自适应LASSO回归的关键代码示例:
# 加载glmnet包
library(glmnet)
# 假设已经有了一个名为data的数据框,其中x是特征矩阵,y是响应变量
x <- as.matrix(data[, -which(names(data) == "y")])
y <- data$y
# 使用交叉验证来选择最佳的lambda值
set.seed(123) # 为了结果可复现,设置随机数种子
cv.model <- cv.glmnet(x, y, alpha = 1, family = "gaussian")
# 检查交叉验证结果,并提取最佳lambda值
print(cv.model)
lambda.min <- cv.model$lambda.min
# 使用最佳的lambda值来拟合自适应LASSO模型
model <- glmnet(x, y, alpha = 1, lambda = lambda.min, family = "gaussian")
# 获取系数
coefficients <- coef(model)
# 查看系数,这里coefficients是一个列表,包含不同的lambda值对应的系数
print(coefficients)
# 可以选择只查看最小lambda值对应的系数
selected.coefficients <- coefficients[sapply(coefficients, length) == min(sapply(coefficients, length))]
print(selected.coefficients)
- 优点:
- 提供了一种改进的变量选择方法,提高了模型的相合性。
- 缺点:
- 实现复杂度较高,需要多次求解最小二乘问题。
实验比较
实验基本设计
-
数据集:选择多个具有不同特征维度和样本数量的数据集,以评估算法在不同数据规模下的表现。
-
问题设置:为每个数据集构建LASSO回归问题,使用相同的正则化参数λ。
-
算法实现:
- 坐标下降法(Coordinate Descent)
- FISTA
- 梯度下降法(Gradient Descent)
- 自适应LASSO(Adaptive LASSO)
- 罚函数法(Penalty Function Method)
-
初始化:为每种算法设置相同的初始解,以保证比较的公平性。
-
参数调整:对于需要调整参数的算法(如学习率、步长等),使用交叉验证来选择最优参数。
-
评价指标:
- 收敛速度:记录每种算法达到预设收敛容忍度所需的迭代次数或时间。
- 目标函数值:比较最终解的目标函数值与全局最优值的差距。
- 系数稀疏性:记录最终解中零系数的个数,评估变量选择的效果。
-
统计分析:对每种算法在不同数据集上的表现进行统计分析,包括平均值、标准差等。
% 构建LASSO问题
clear;
seed = 97006855;
ss = RandStream('mt19937ar','Seed',seed);
RandStream.setGlobalStream(ss);
% 生成随机的矩阵A和向量u以使得b=Au。
m = 512;
n = 1024;
A = randn(m, n);
u = sprandn(n, 1, 0.1);
b = A * u;
% 正则化系数mu。
mu = 1e-3;
% L为A⊤A的最大特征值,用于步长的选取。
L = eigs(A'*A, 1);
% 初始解x0。
x0 = randn(n, 1);
% 具体可视化代码根据实际需求进行编写。
% 可视化优化过程:观察目标函数值随迭代次数的变化。
% 同时展示求解优化问题得到的解各个分量的大小。
% 结果可视化
实验理论分析
-
收敛速度:
- 坐标下降法和FISTA通常具有较快的收敛速度,尤其是当目标函数是凸的且算法参数适当选择时。
- 梯度下降法的收敛速度可能较慢,特别是当学习率需要仔细调整以避免震荡或发散。
- 自适应LASSO和罚函数法的收敛速度取决于罚函数的选择和实现细节。
-
稳定性:
- 坐标下降法和FISTA由于其简单性和迭代更新机制,通常在数值上是稳定的。
- 梯度下降法可能需要使用动量项或自适应学习率来提高稳定性。
- 自适应LASSO通过调整系数的惩罚权重,可能在处理某些特定问题时提供更好的稳定性。
-
复杂度:
- 坐标下降法和FISTA的计算复杂度通常与问题规模成线性关系,但每次迭代可能需要计算整个数据集的梯度或近似。
- 梯度下降法和其变种(如随机梯度下降法)可以并行化,并且每次迭代的计算复杂度较低,但可能需要更多迭代。
- 自适应LASSO和罚函数法的复杂度取决于罚函数的具体实现,可能需要多次求解子问题。
参考文献
- https://blog.csdn.net/FrankieHello/article/details/105839370
- https://blog.csdn.net/DS_agent/article/details/106340777
- https://www.cnblogs.com/bonelee/p/17686365.html
- https://www.cnblogs.com/leezx/p/15719492.html
- https://github.com/Yangyi001/Data_analysis/blob/master/岭回归与LASSO回归模型/基于Python的岭回归与LASSO回归模型介绍及实践.md