Lasso原理与Python实现

Lasso原理与Python实现

  • lasso原理

  • Python实现

Lasso 原理
    在一般的回归情形中,对于数据集 ( x i , y i ) \left(\mathrm{x}^{i}, y^{i}\right) (xi,yi),最小二乘法估计通过计算预测值与真实值之间的最小平方和对数据进行预测,但是数据分析不常满足最小二乘估计,而提升最小二乘估计的两个标准技术:子集选择与岭回归都存在缺陷。子集选择通过从特征中选择部分特征的方法建立模型,但数据中很小的变化就能导致不一样的模型,因此子集选择降低了预测的准确度。而岭回归不把任何系数设置为0,并不提供易于解释的模型。
    针对以上问题,作者提出了Lasso方法,即“最小绝对值收敛和选择算子”,从本质上说,Lasso方法能够收缩系数并将一些系数设置为0,保留了子集选择和岭回归的优点。
    Lasso的公式为:
         min ⁡ β 1 2 ∥ y − ∑ i = 1 n x i β i ∥ 2 2 + λ ∥ β ∥ 1 \min _{\beta} \frac{1}{2}\left\|\mathbf{y}-\sum_{i=1}^{n} \mathbf{x}_{i} \beta_{i}\right\|_{2}^{2}+\lambda\|\beta\|_{1} minβ21yi=1nxiβi22+λβ1
    其中,前一项为最小二乘估计公式,后一项实际为正则化项L1。为计算使得误差最小的beta值,对公式做如下推导:
     f = R S S ( w ) + λ ∥ w 1 ∥ 1 f=R S S(w)+\lambda\left\|w_{1}\right\|_{1} f=RSS(w)+λw11
     = ∑ i = 0 N ( y i − ∑ j = 0 D w j x i j ) 2 + λ ∑ j = 0 D ∣ w j ∣ =\sum_{i=0}^{N}\left(y_{i}-\sum_{j=0}^{D} w_{j} x_{i j}\right)^{2}+\lambda \sum_{j=0}^{D}\left|w_{j}\right| =i=0N(yij=0Dwjxij)2+λj=0Dwj

     ∂ R S S ∂ W j \frac{\partial R S S}{\partial W_{j}} WjRSS = − 2 ∑ i = 0 N x i j ( y i − ∑ j = 0 D w j x i j ) -2 \sum_{i=0}^{N} x_{i j}\left(y_{i}-\sum_{j=0}^{D} w_{j} x_{i j}\right) 2i=0Nxij(yij=0Dwjxij)

     = − 2 ∑ i = 0 N x i j =-2 \sum_{i=0}^{N} x_{i j} =2i=0Nxij ( y i − ∑ k ≠ j w k x i k − W j x i j ) \left(y_{i}-\sum_{k \neq j} w_{k} x_{i k}-W_{j} x_{i j}\right) (yik=jwkxikWjxij)

     = − 2 ∑ i = 0 N x i j =-2 \sum_{i=0}^{N} x_{i j} =2i=0Nxij ( y i − ∑ k ≠ j w k x i k ) \left(y_{i}-\sum_{k \neq j} w_{k} x_{i k}\right) (yik=jwkxik)+2 ∑ i = 0 N w j x i j 2 \sum_{i=0}^{N} w_{j} x_{i j}^{2} i=0Nwjxij2
    令 p j = p_{j}= pj= ∑ i = 0 N x i j \sum_{i=0}^{N} x_{i j} i=0Nxij ( y i − ∑ k ≠ j w k x i k ) \left(y_{i}-\sum_{k \neq j} w_{k} x_{i k}\right) (yik=jwkxik)

     z j = z_{j}= zj= ∑ i = 0 N x i j 2 \sum_{i=0}^{N} x_{i j}^{2} i=0Nxij2

    则有 ∂ R S S ∂ W j = − 2 p j + 2 w j z j \frac{\partial R S S}{\partial W_{j}}=-2 p_{j}+2 w_{j} z_{j} WjRSS=2pj+2wjzj
    此外,对于正则项的求导本质上即为y=|x|的形式,求导结果为:
     { λ , w j > 0 [ − λ , λ ] , w j = 0 − λ , w j < 0 \left\{\begin{array}{c}{\lambda, w_{j}>0} \\ {[-\lambda, \lambda], w_{j}=0} \\ {-\lambda, w_{j}<0}\end{array}\right. λ,wj>0[λ,λ],wj=0λ,wj<0
    因此当 w j > 0 w_{j}>0 wj>0时, ∂ f ∂ w = 2 z j w j − 2 p j − λ \frac{\partial f}{\partial w}=2 z_{j} w_{j}-2 p_{j}-\lambda wf=2zjwj2pjλ ,令其为0解得: w j = ( p j − λ 2 ) / z j w_{j}=\left(p_{j}-\frac{\lambda}{2}\right) / z_{j} wj=(pj2λ)/zj,且 p j > λ 2 {p}_{j}>\frac{\lambda}{2} pj>2λ。同理,当 w j < 0 w_{j}<0 wj<0可解得 w j = ( p j + λ 2 ) / z j w_{j}=\left(p_{j}+\frac{\lambda}{2}\right) / z_{j} wj=(pj+2λ)/zj,且 p j < − λ 2 {p}_{j}<-\frac{\lambda}{2} pj<2λ
    根据解得的 w j w_{j} wj公式,再计算对应的 p j p_{j} pj z j z_{j} zj,即可得到lasso回归的权重矩阵。
    具体实现时, z j z_{j} zj即为向量的内积,只需取出矩阵中的该列,并以内积的形式相乘即可得到 z j z_{j} zj。计算 p j p_{j} pj时,需设置双重循环。
Python实现

import numpy as np
# 计算残差
def rss(X,y,w):
	return (y-X*w).T*(y-X*w)
	
# lasso 回归	
def lassoRegression(X,y,a):
	threshold = 0.1
	# init para
	m,n = X.shape

	w = np.matrix(np.zeros((n,1)))
	r = rss(X,y,w)
	z = [0 for i in range(n)]

	tempw = [0 for i in range(n)]
	# 记录迭代次数
	iteration = 0
	# 迭代以计算参数
	while True:
		iteration += 1
		for k in range(n):
			temp_X = X[:, k].reshape(-1,1)
			z[k] = (temp_X.T*temp_X)[0, 0]
			p = [0 for i in range(n)]
			p_part = [0 for i in range(n)]
			for i in range(m):
				for j in range(n):
					if k != j:
						# print w[j,0]
						p_part[j] = X[i, j]*w[j, 0]
				p[k] += X[i, k] * (y[i, 0] - sum(p_part))
			if p[k] < -a/2:
				tempw[k] = (p[k] + a/2)/z[k]
			elif p[k] > a/2:
				tempw[k] = (p[k] - a/2)/z[k]
			else:
				tempw[k] = 0
			w[k, 0] = tempw[k]
		tempr = rss(X, y, w)
		delta = abs(tempr - r)[0, 0]
		r = tempr

		if delta < threshold:
			print 'iteration', iteration
			print 'delta', delta
			break
	return w
	
def load_data(filename):
	X, Y = [], []
	with open(filename, 'r') as f:
		for line in f:
			splited_line = [float(i) for i in line.split()]
			x, y = splited_line[: -1], splited_line[-1]
			X.append(x)
			Y.append(y)
	X, Y = np.matrix(X), np.matrix(Y).T
	return X, Y
def std(X):
	std_deviation = np.std(X, 0)
	mean = np.mean(X, 0)
	return (X - mean)/std_deviation
if '__main__'==__name__:
	# 使用鲍鱼数据集
	X, y = load_data('abalone.txt')
	X, y = std(X), std(y)
	enum = 30
    w_all = lassoTrace(X, y, enum)

    lambdas = [i-10 for i in range(enum)]

    data = pd.DataFrame({
        'x1': w_all[:, 0],
        'x2': w_all[:, 1],
        'x3': w_all[:, 2],
        'x4': w_all[:, 3],
        'x5': w_all[:, 4],
        'x6': w_all[:, 5],
        'x7': w_all[:, 6],
        'x8': w_all[:, 7],
    })
    plt.figure(12)

    plt.subplot(221)
    data.boxplot()

    plt.subplot(222)
    plt.plot(lambdas, w_all)
    plt.show()

输出各系数随惩罚力度变化的曲线图以及各系数的箱形图。箱型图和

  • 12
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值