正则惩罚解决过拟合(Ridge回归和Lasso回归)
手动反爬虫,禁止转载: 原博地址 https://blog.csdn.net/lys_828/article/details/121460567(CSDN博主:Be_melting)
知识梳理不易,请尊重劳动成果,文章仅发布在CSDN网站上,在其他网站看到该博文均属于未经作者授权的恶意爬取信息
案例五: 正则惩罚解决过拟合(Ridge回归和Lasso回归)
模型过拟合解决的方式一般有三种:增加数据量,减少模型复杂度,正则惩罚。一般情况下,数据量基本上是确定了,模型也是指定的,可以调整的就是最后一种方式。正则惩罚的模式可以有如下三种:
-
L1(Ridge回归对应绝对值):
-
L2(Lasso回归对应平方):
-
Elastic Net(L1和L2的结合):
结合着实际案例进行正则惩罚的使用,数据集来自于kaagle网站,数据获取网址:https://www.kaggle.com/anthonypino/melbourne-housing-market。
3.2.1 模块加载与数据读入
新建一个python3文件,命名为正则惩罚模型.ipynb。数据集中的字段在之前的短租房和房价预测案例分析中基本上都有介绍,然后直接导入模块进行数据读取。
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
dataset = pd.read_csv('./data/Melbourne_housing_FULL.csv')
dataset
输出结果如下。(数据集中共有34857条数据,21个字段)
通过nunique()方法可以快速查看各个字段中的唯一值的数量,用来确定一些分类字段(唯一值较少)和连续字段(唯一值较多)。输出结果如下,其中显然统计数值低于20的字段都可以认定为分类字段,比如房子所在的地区Regionname,而数据超过100的也基本上为数值连续字段。
3.2.2 特征工程
假定通过数据EDA 已经知道了哪些因素是重要数据特征 ,进行数据提取(通过corr()和heatmap()方法进行关联性探究)。本案例中主要探讨的是惩罚项如何使用,对于关联性这里不用再深究,直接提取有关联的字段构建数据集。
cols_to_use = ['Suburb', 'Rooms', 'Type', 'Method', 'SellerG', 'Regionname', 'Propertycount',
'Distance', 'CouncilArea', 'Bedroom2', 'Bathroom', 'Car', 'Landsize', 'BuildingArea', 'Price']
dataset = dataset[cols_to_use]
首先查看数据集中缺失数据情况,输出结果如下。
然后针对与不同类型的数据进行不同方式的缺失值处理,第一类数据直接进行0填充。
cols_to_fill_zero = ['Propertycount', 'Distance', 'Bedroom2', 'Bathroom', 'Car']
dataset[cols_to_fill_zero] = dataset[cols_to_fill_zero].fillna(0)
另一种,使用数据的均值进行填充。
dataset['Landsize'] = dataset['Landsize'].fillna(dataset.Landsize.mean())
dataset['BuildingArea'] = dataset['BuildingArea'].fillna(dataset.BuildingArea.mean())
标签数据一般不进行填充,而是直接进行删除。
dataset.dropna(inplace=True)
处理完毕后,再次核实缺失值数据情况,输出结果如下。
前面使用nunique()方法确定部分字段属于分类数据,而对于分类数据传入数据模型之前需要进行独热编码的处理,处理的方式直接使用get_dummies()方法即可解决。由下面的输出结果可知,构建数据集中原有15个字段扩展为745个字段。
至此,数据集清洗和转化的工作都完成了,下一步再次核实数据集的缺失值情况,没有缺失值后就可以进行模型的创建和应用
3.2.3 模型搭建与应用
(1)构建特征数据与标签数据。
X = dataset.drop('Price', axis=1)
y = dataset['Price']
(2)划分训练集和测试集。按照9:1的比例进行拆分。
from sklearn.model_selection import train_test_split
train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.1, random_state=2)
(3)模型初始化与训练。
from sklearn.linear_model import LinearRegression
reg = LinearRegression().fit(train_X, train_y)
(4)模型评估。
模型在训练集和测试集中的表现的结果输出如下。(很显然和上一个案例创建的模型类似,都是在训练数据上表现的还算可以,但是在测试数据上面得分小于0,存在着过拟合现象)
(5)L1惩罚模型。
导入linear_model模块中的Lasso模型,其中的三个参数,可以调用使用手册查看对应的说明文档,本案例的重点不是对于参数的讲解,而是如何进行正则惩罚的使用,模型创建和训练的代码如下。
from sklearn import linear_model
lasso_reg = linear_model.Lasso(alpha=50, max_iter=100, tol=0.1)
lasso_reg.fit(train_X, train_y)
进一步评估模型在训练集和测试集中的得分,结果如下。(经过L1正则惩罚的模型在训练集和测试集上表现均可,且两者的得分情况相近,解决了过拟合的问题)
(6)L2惩罚模型
使用的方式和L1类似,导入linear_model模块下的Ridge模型,三个参数与L1中的保持一致,创建和训练模型的代码如下。
from sklearn.linear_model import Ridge
ridge_reg= Ridge(alpha=50, max_iter=100, tol=0.1)
ridge_reg.fit(train_X, train_y)
进一步评估模型在训练集和测试集中的得分,结果如下。(经过L2正则惩罚的模型在训练集和测试集上表现均可,且两者的得分情况相近,解决了过拟合的问题。与L1不同的是,L2模型在测试集上的表现要比训练集好,而L1模型却相反)
关于惩罚模型的通俗的理解,以赛车比赛为例:第一名的赛车手要比第二名、第三名快7s,这个概念相当于成绩绝对碾压。而在平时的比赛中,前三名的比分咬的很死,基本上只会存在0.1s,0.2s的差距,7s这个时间差就相当于是老手和新手的之间的对比。为了提高比赛的观赏性,避免出现这种绝对优势的情景,可以在第一名的赛车上增加负重,比如增加100kg配重,此时第一名还是领先3s,那么再加配重到200kg,比赛结果中发现此时的赛车手落后原来的第二名0.3s,这次的调整就解决了比赛选手之间的实力悬殊的问题,保证了观赏性。这个过程就类似惩罚模型的工作原理,辅助对于惩罚模型的理解。
补充(经验之谈):在处理离散数据比较多时后使用L2惩罚模型比较好,处理连续数据模型较多时候使用L1惩罚模型比较好。