📜  使用Python从零开始实现 Lasso 回归

📅  最后修改于: 2022-05-13 01:55:21.296000             🧑  作者: Mango

使用Python从零开始实现 Lasso 回归

先决条件:

  1. 线性回归
  2. 梯度下降

介绍:

套索回归也是从线性回归派生的另一个线性模型,它共享相同的预测假设函数。线性回归的成本函数由 J 表示。

\frac{1}{m} \sum_{i=1}^{m}\left(y^{(i)}-h\left(x^{(i)}\right)\right)^{2}
Here, m is the total number of training examples in the dataset.
h(x(i)) represents the hypothetical function for prediction.
y(i) represents the value of target variable for ith training example.

线性回归模型考虑与预测同等相关的所有特征。当数据集中有许多特征,甚至其中一些与预测模型无关时。这使得模型更加复杂,对测试集的预测过于不准确(或过度拟合)。这种具有高方差的模型不能对新数据进行泛化。所以,套索回归来拯救。它在线性回归的成本函数中引入了 L1 惩罚(或等于权重大小的绝对值)。下面给出了 Lasso 回归的修正成本函数。

\frac{1}{m}\left[\sum_{i=1}^{m}\left(y^{(i)}-h\left(x^{(i)}\right)\right)^{2}+\lambda \sum_{j=1}^{n} w_{j}\right]
Here, w(j) represents the weight for jth feature.  
n is the number of features in the dataset.
lambda is the regularization strength.
 

套索回归同时执行变量选择和正则化。

数学直觉:

在梯度下降优化期间,添加 l1 惩罚将权重缩小到接近零或零。那些缩小到零的权重消除了假设函数中存在的特征。因此,不相关的特征不参与预测模型。这种对权重的惩罚使假设更加简单,从而鼓励了稀疏性(模型参数很少)。

如果添加了截距,则它保持不变。

我们可以通过超参数 lambda 来控制正则化的强度。所有权重都减少了相同的因子 lambda。

调整 lambda 值的不同情况。

  1. 如果 lambda 设置为 0,则 Lasso 回归等于线性回归。
  2. 如果 lambda 设置为无穷大,则所有权重都缩小为零。

如果我们增加 lambda,如果我们减少 lambda 方差的增加,偏差就会增加。随着 lambda 的增加,越来越多的权重被缩小到零,并消除了模型中的特征。

执行

此实现中使用的数据集可以从链接下载。

它有 2 列——“ YearsExperience ”和“ Salary ”,用于一家公司的 30 名员工。因此,在此,我们将训练一个 Lasso Regression 模型来学习每个员工的工作年限与他们各自的薪水之间的相关性。一旦模型训练好,我们就可以根据员工多年的经验来预测他的薪水。

代码:

# Importing libraries
  
import numpy as np
  
import pandas as pd
  
from sklearn.model_selection import train_test_split
  
import matplotlib.pyplot as plt
  
# Lasso Regression
  
class LassoRegression() :
      
    def __init__( self, learning_rate, iterations, l1_penality ) :
          
        self.learning_rate = learning_rate
          
        self.iterations = iterations
          
        self.l1_penality = l1_penality
          
    # Function for model training
              
    def fit( self, X, Y ) :
          
        # no_of_training_examples, no_of_features
          
        self.m, self.n = X.shape
          
        # weight initialization
          
        self.W = np.zeros( self.n )
          
        self.b = 0
          
        self.X = X
          
        self.Y = Y
          
        # gradient descent learning
                  
        for i in range( self.iterations ) :
              
            self.update_weights()
              
        return self
      
    # Helper function to update weights in gradient descent
      
    def update_weights( self ) :
             
        Y_pred = self.predict( self.X )
          
        # calculate gradients  
          
        dW = np.zeros( self.n )
          
        for j in range( self.n ) :
              
            if self.W[j] > 0 :
                  
                dW[j] = ( - ( 2 * ( self.X[:, j] ).dot( self.Y - Y_pred ) ) 
                           
                         + self.l1_penality ) / self.m
          
            else :
                  
                dW[j] = ( - ( 2 * ( self.X[:, j] ).dot( self.Y - Y_pred ) ) 
                           
                         - self.l1_penality ) / self.m
  
       
        db = - 2 * np.sum( self.Y - Y_pred ) / self.m 
          
        # update weights
      
        self.W = self.W - self.learning_rate * dW
      
        self.b = self.b - self.learning_rate * db
          
        return self
      
    # Hypothetical function  h( x ) 
      
    def predict( self, X ) :
      
        return X.dot( self.W ) + self.b
      
  
def main() :
      
    # Importing dataset
      
    df = pd.read_csv( "salary_data.csv" )
  
    X = df.iloc[:, :-1].values
  
    Y = df.iloc[:, 1].values
      
    # Splitting dataset into train and test set
  
    X_train, X_test, Y_train, Y_test = train_test_split( X, Y, test_size = 1 / 3, random_state = 0 )
      
    # Model training
      
    model = LassoRegression( iterations = 1000, learning_rate = 0.01, l1_penality = 500 )
  
    model.fit( X_train, Y_train )
      
    # Prediction on test set
  
    Y_pred = model.predict( X_test )
      
    print( "Predicted values ", np.round( Y_pred[:3], 2 ) ) 
      
    print( "Real values      ", Y_test[:3] )
      
    print( "Trained W        ", round( model.W[0], 2 ) )
      
    print( "Trained b        ", round( model.b, 2 ) )
      
    # Visualization on test set 
      
    plt.scatter( X_test, Y_test, color = 'blue' )
      
    plt.plot( X_test, Y_pred, color = 'orange' )
      
    plt.title( 'Salary vs Experience' )
      
    plt.xlabel( 'Years of Experience' )
      
    plt.ylabel( 'Salary' )
      
    plt.show()
      
  
if __name__ == "__main__" : 
      
    main()

输出:

Predicted values  [ 40600.91 123294.39  65033.07]
Real values       [ 37731 122391  57081]
Trained W         9396.99
Trained b         26505.43


可视化

注意:它使模型选择的某些部分自动化,有时称为变量消除器。