当前位置:   article > 正文

Lasso回归和岭回归的底层实现_lasso loss

lasso loss

目录

一、前言

二、基本信息

 三、基本思路

四、Lasso回归

1、数据处理

2、选择模型

3、计算风险函数

4、优化

5、重复以上步骤,直到收敛

五、Ridge回归

六、总结

七、源码展示


一、前言

近日,实践了lasso回归和岭回归的底层实现,这是一个课程作业,也是初次尝试,问题很多,就是记录一下。

二、基本信息

基本原理:

数据集:本次数据集是一个预测房价的数据集,包括编号、交易日期、房龄、到最近地铁站距离、便利店数量、经度和纬度七个属性,预测值为每平米的价格。为了专注于实现线性回归,已经为大家处理好的数据,删除了编号信息,六个属性和预测值存于numpy数组中保存在了/data/exp02目录下,命名分别为X_train.npy和y_train.npy。测试时调用read_data函数得到特征矩阵和标签向量

岭回归:

岭回归(Ridge Regression)是一种线性回归的扩展形式,它通过在损失函数中添加L2正则化项来解决线性回归中的过拟合问题。L2正则化项会使得模型的权重参数向零收缩,从而降低模型的复杂度,避免过拟合。

在岭回归中,我们优化的目标函数为:

其中,$X$是输入特征矩阵,$y$是对应的标签,$w$是模型的权重参数,$\alpha$是正则化强度超参数。该目标函数包括两个部分,第一个部分是平方误差损失函数,它用来衡量模型的预测值与真实值之间的误差;第二个部分是L2正则化项,它用来限制模型的复杂度。

与普通的线性回归相比,岭回归在解析式中增加了一个偏置项,也就是模型权重的平方和,同时加上一个超参数 $\alpha$ 控制模型复杂度和惩罚力度,通过调整这个超参数可以得到不同的模型表现。

Lasso回归(Lasso Regression)是一种线性回归方法,它通过加入正则化项(L1正则化)来惩罚模型中的大型系数,以避免过拟合问题。Lasso回归在高维数据集中非常有用,因为它可以自动选择最相关的特征,从而简化模型。

Lasso回归的优化目标是最小化以下损失函数:

其中,$X$是输入特征矩阵,$y$是对应的标签,$w$是模型的权重参数,$\alpha$是正则化强度超参数。该目标函数包括两个部分,第一个部分是平方误差损失函数,它用来衡量模型的预测值与真实值之间的误差;第二个部分是L1正则化项,它用来限制模型的复杂度。

Lasso回归的优点是可以自动选择最相关的特征,从而降低模型的复杂度,并且可以处理具有高度相关特征的数据集。缺点是当特征数量非常大时,计算量可能会很大。

要求:只能使用numpy,禁止使用sklearnpytorchtensorflow等第三方库

 三、基本思路

  1. 数据处理
  2. 选择模型
  3. 计算风险函数
  4. 优化
  5. 重复以上步骤,直到收敛

四、Lasso回归

1、数据处理

在机器学习中,对数据进行预处理是很重要的一步。数据预处理可以帮助我们清洗数据,去除噪声和异常值,提高模型的准确性和可靠性。

数据预处理通常包括以下几个步骤:

  1. 数据清洗:去除重复数据、缺失值和异常值,以提高数据的质量。
  2. 数据转换:将数据转换为适合机器学习算法处理的格式。例如,可以对分类变量进行独热编码(One-hot Encoding)处理,将其转化为虚拟变量。
  3. 数据规范化:将数据缩放到一个特定的范围内,以便于不同特征之间的比较。例如,可以使用最大最小值归一化(Min-Max Normalization)或标准化(Standardization)方法对数据进行规范化。

通过对数据进行预处理,我们可以提高模型的准确性和可靠性,从而更好地解决实际问题。

在这个实现里面,因为数据集是已经处理好的,所以这个环节只进行了数据规范化。常用的数据规范化方法有以下几种

1、最大最小值归一化(Min-Max Normalization):这种方法通过将数据缩放到一个特定的范围内(通常是0到1之间)来实现规范化。具体来说,对于每个数据点,我们可以使用下面的公式进行归一化:

                                        x' = (x - min) / (max - min)

其中,x表示原始数据点,x'表示归一化后的数据点,minmax分别表示数据集中的最小值和最大值。

2、标准化(Standardization):这种方法通过将数据转换为均值为0,标准差为1的分布来实现规范化。具体来说,对于每个数据点,我们可以使用下面的公式进行标准化:

                                        x' = (x - mean) / std

其中,x表示原始数据点,x'表示标准化后的数据点,meanstd分别表示数据集中的均值和标准差。

3、鲁棒缩放(Robust Scaling):这种方法与最大最小值归一化类似,但是它使用数据集中的中位数和四分位数来代替最小值和最大值。这样可以使得规范化后的数据更加鲁棒,不受异常值的影响。

这里选用了标准化的方法。

  1. #对测试数据进行统一标准化
  2. def standard_st(data):
  3. data_mean = np.mean(data)
  4. # X_var=np.var(X)#方差
  5. data_std = np.std(data)
  6. data = (data - data_mean) / data_std
  7. return data
  8. #对数据进行处理(标准化操作并将构建增广矩阵)
  9. def data_processing_st(X):
  10. X = np.apply_along_axis(standard_st, 1, X)
  11. ones = np.ones((X.shape[0], 1))
  12. X = np.hstack((X, ones))
  13. return X

(基本思路就是先编写一个实现标准化的函数,然后再通过np.apply_along_axis()的方法实现对数据矩阵的每一行做规范化)

在初次尝试的时候犯了一个错误,在对数据进行规范化的时候,是基于对全体数据集进行规范化的(r然后就导致精度一直上不来),这种全局规范化的方法虽然可以确保数据的统一性,但实际上会产生一些问题。首先,全局规范化可能会损失数据中的一些重要信息。例如,如果我们有两个不同的数据子集,它们的数据分布可能不同,全局规范化可能会使它们的特征值相同,导致模型无法区分它们。

其次,全局规范化还可能导致模型过度拟合训练数据。这是因为全局规范化会使数据的分布变得更加集中,从而增加模型在训练数据上的准确性,但同时也可能减少了模型在未知数据上的泛化能力。

还有,在对房价进行预测时,房屋面积和房龄这两个特征的值范围可能相差很大,因此我们需要对它们进行独立的规范化,以确保它们在相同的尺度上。

2、选择模型

本次实践直接指定使用lasso回归,所以不用选择模型。

一般来说,要从具体的问题来选择相对应的模型。本次的机器学习目标是通过进行相关计算来预测房价,常用的模型有线性回归模型、随机森林、岭回归、lasso回归等。

3、计算风险函数

前面lasso回归的损失函数已经给出,即

  1. # 定义损失函数
  2. mse = np.sum(((X @ w )- y.T) @ ((X @ w) - y.T).T)/(np.shape(X)[0])
  3. l1 = alpha * ((np.sum(np.abs(w))))
  4. lassoloss = mse + l1

4、优化

使用梯度下降的方法对学习准则的优化

  1. # 计算梯度
  2. dw = X.T @ ((X @ w) - y.T) + alpha * np.sign(w) # 不是很理解为什么
  3. loss_old = lassoloss#记录上一次的风险损失
  4. # 更新参数
  5. w = w - beta * dw

5、重复以上步骤,直到收敛

这一步直接通过for循环迭代实现就行,在循环里面我们还应该设置一个提前停止的条件,避免无意义的循环迭代。

  1. # 后边损失函数下降十分缓慢,设置提前停止的条件
  2. if (np.abs(min - loss_old) < 0.0001):
  3. print('提前停止!')
  4. break
  5. # 获取最小损失时候的参数w
  6. if (min >= lassoloss):
  7. min = lassoloss
  8. best = w

小结:基本的代码就已经完成了,整个代码我是通过手动的修改超参数,以获取到一个最优的参数(这一步可以使用网格搜索或是随机搜索的方法来进行优化的)。

五、Ridge回归

基本思路:

在岭回归中我的优化目标函数为在岭回归中,我们优化的目标函数为:

因为该函数是凸函数,有解析解。极值点是导数为0的点,所以先对w进行求导,

令偏导等于0 ,然后对等式进行处理,便得到w的方程。代码中只需要找到一个合适的超参数代入该方程,便可以求得我们的目标参数。

  1. alpha=1#2023/4/30
  2. ridgeloss = 2 * (X.T @ X @ w - X.T @ y + alpha * w)
  3. # 对损失函数中w求偏导,令导数为0,求得w
  4. w = np.linalg.inv((X.T @ X + alpha * np.eye(np.shape((X.T @ X))[0]))) @ X.T @ y

六、总结

1、对于本次预测房价的项目中,不适合对数据整体进行规范化,而应该是对每个特征进行规范化。

2、可以使用增广矩阵,将w、b参数合并一起,会方便一点

3、在实现Ridge回归的时候,我使用的规范方法是最大最小值规划化,将其缩放到(0,1)之间,针对这个机器学习的问题,好像这个找到的解更优。

七、源码展示

  1. # 最终在main函数中传入一个维度为6的numpy数组,输出预测值
  2. import os
  3. try:
  4. import numpy as np
  5. except ImportError as e:
  6. os.system("sudo pip3 install numpy")
  7. import numpy as np
  8. #对测试数据进行统一标准化
  9. def standard_st(data):
  10. data_mean = np.mean(data)
  11. # X_var=np.var(X)#方差
  12. data_std = np.std(data)
  13. data = (data - data_mean) / data_std
  14. return data
  15. #对数据进行处理(标准化操作并将构建增广矩阵)
  16. def data_processing_st(X):
  17. X = np.apply_along_axis(standard_st, 1, X)
  18. ones = np.ones((X.shape[0], 1))
  19. X = np.hstack((X, ones))
  20. return X
  21. #使用01规范法处理数据
  22. def data_processing_01(X):
  23. X = np.apply_along_axis(standard_01, 1, X)
  24. ones = np.ones((X.shape[0], 1))
  25. X = np.hstack((X, ones))
  26. return X
  27. #使用01规范法处理数据
  28. def standard_01(data):
  29. min_val = np.min(data)
  30. max_val = np.max(data)
  31. scaled_data = (data - min_val) / (max_val - min_val)
  32. return scaled_data
  33. def ridge(data):
  34. data=standard_01(data)
  35. X, y = read_data()
  36. X = data_processing_01(X)
  37. # 选择模型并初始化参数
  38. w = np.zeros((7, 1))
  39. y_pre = X @ w # 计算预测值
  40. # 定义损失函数
  41. # alpha = 10 # 正则化系数
  42. alpha=1#2023/4/30
  43. ridgeloss = 2 * (X.T @ X @ w - X.T @ y + alpha * w)
  44. # 对损失函数中w求偏导,令导数为0,求得w
  45. w = np.linalg.inv((X.T @ X + alpha * np.eye(np.shape((X.T @ X))[0]))) @ X.T @ y
  46. #获取w和b
  47. b = w[-1]
  48. w = w[:-1]
  49. w = w.reshape(6, 1)
  50. return data@w+b
  51. def lasso(data):
  52. data = standard_st(data)
  53. X, y = read_data()
  54. X = data_processing_st(X)
  55. y=y.reshape(1,404)
  56. # 设置超参数
  57. alpha = 1000 # 正则化系数
  58. beta = 0.00045 # 学习率
  59. # 选择模型并初始化参数
  60. w = np.zeros((7, 1))
  61. best = w
  62. min = 365194055
  63. loss_old = 1 # 记录上一次的损失,如果两个损失变化太小,说明已经趋近最优值,提前停止
  64. # print(X@w)
  65. for i in range(100000):
  66. y_pre = X @ w # 计算预测值
  67. # 定义损失函数
  68. mse = np.sum(((X @ w )- y.T) @ ((X @ w) - y.T).T)/(np.shape(X)[0])
  69. l1 = alpha * ((np.sum(np.abs(w))))
  70. lassoloss = mse + l1
  71. # 计算梯度
  72. dw = X.T @ ((X @ w) - y.T) + alpha * np.sign(w)
  73. loss_old = lassoloss#记录上一次的风险损失
  74. # 更新参数
  75. w = w - beta * dw
  76. # 后边损失函数下降十分缓慢,设置提前停止的条件
  77. if (np.abs(min - loss_old) < 0.0001):
  78. print('提前停止!')
  79. break
  80. # 获取最小损失时候的参数w
  81. if (min >= lassoloss):
  82. min = lassoloss
  83. best = w
  84. # 输出损失函数的值
  85. #print(f'Iteration {i}: Loss = {lassoloss} ')
  86. w =best[0:6,:]
  87. b=best[6,0]
  88. print(data@w+b)
  89. return data@w+b
  90. def read_data(path='./data/exp02/'):
  91. x = np.load(path + 'X_train.npy')
  92. y = np.load(path + 'y_train.npy')
  93. return x, y

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/598913
推荐阅读
  

闽ICP备14008679号