Python机器学习04——惩罚回归

本系列所有的代码和数据都可以从陈强老师的个人主页上下载:Python数据程序

参考书目:陈强.机器学习及Python应用. 北京:高等教育出版社, 2021.

本系列基本不讲数学原理,只从代码角度去让读者们利用最简洁的Python代码实现机器学习方法。


惩罚回归介绍

惩罚回归听着很奇特,其实就是普通的最小二乘回归的损失函数后面加了一个惩罚项,从而可以让模型的系数变小,即系数收缩,降低模型的复杂性,防止过拟合。

根据惩罚项的不同,如果惩罚项为一范数的话,就是lasso回归,损失函数如下:

 如果惩罚项是二范数的话,就是计量经济学里面的岭回归。

为什么惩罚回归可以收缩系数,看图:

正方形为1范数罚项,圆圈为2范数罚项。其中\beta估计量为模型普通的最小二乘估计的系数,可以看到,最小化\beta时会让模型系数朝着原点的方向收缩,即系数整体范数变小,甚至有些变量的系数会成为0。因此惩罚回归还具有一定的变量筛选功能。当模型系数变小,变量变少后,模型复杂度自然降低,也不容易过拟合。

惩罚回归Python案例

 导入包,读取数据,展示前五行

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler

from sklearn.linear_model import Ridge
from sklearn.linear_model import RidgeCV
from sklearn.linear_model import Lasso
from sklearn.linear_model import lasso_path
from sklearn.linear_model import LassoCV
from sklearn.linear_model import ElasticNet
from sklearn.linear_model import ElasticNetCV
from sklearn.linear_model import enet_path

prostate = pd.read_csv('prostate.csv')
prostate.head()

数据长这个样子

其中,响应变量y为lpsa,其他都是特征变量x 

取出X和y,进行标准化

X_raw = prostate.iloc[:, :-1]
y = prostate.iloc[:, -1]

scaler = StandardScaler()
X = scaler.fit_transform(X_raw)

首先进行岭回归

model = Ridge()
#拟合模型
model.fit(X, y)
#计算测试集上的拟合优度
model.score(X, y)
#模型截距
model.intercept_
#模型系数
model.coef_
#数据框展示系数
pd.DataFrame(model.coef_, index=X_raw.columns, columns=['Coefficient'])

当惩罚系数大小,即惩罚力度不一样时,模型得到的系数是不一样的,下面画出变量系数随着惩罚力度变化图:

# Plot ridge coefficient path  , fit_intercept=False

alphas = np.logspace(-3, 6, 100)
coefs = []
for alpha in alphas:
    model = Ridge(alpha=alpha)
    model.fit(X, y)
    coefs.append(model.coef_) 

ax = plt.gca()
ax.plot(alphas, coefs)
ax.set_xscale('log')
plt.xlabel('alpha (log scale)')
plt.ylabel('Coefficients')
plt.title('Ridge Cofficient Path')
plt.axhline(0, linestyle='--', linewidth=1, color='k')
plt.legend(X_raw.columns)

 搜索最优惩罚系数

# Refine the search grid
alphas=np.linspace(1, 10, 1000)
model = RidgeCV(alphas=alphas, store_cv_values=True)
model.fit(X, y)
model.alpha_


model.cv_values_.shape
mse = np.mean(model.cv_values_, axis=0)
np.min(mse)

index_min = np.argmin(mse)
print(index_min)

alphas[index_min], mse[index_min]

plt.plot(alphas, mse)
plt.axvline(alphas[index_min], linestyle='--', linewidth=1, color='k')
plt.xlabel('alpha')
plt.ylabel('Mean Squared Error')
plt.title('CV Error for Ridge Regression')
plt.tight_layout()

model.coef_
pd.DataFrame(model.coef_, index=X_raw.columns, columns=['Coefficient'])

 可以看到最优的惩罚系数在6点多左右,此时模型系数为


 lasso回归

### Lasso regression
model = Lasso(alpha=0.1)
model.fit(X, y)
model.score(X, y)

results = pd.DataFrame(model.coef_, index=X_raw.columns, columns=['Coefficient'])
results

 可以看出lasso回归的系数很多都成为了0 ,说明这些变量不重要。得到的是稀疏的解。因为一范数对小系数惩罚性较大,这保证了模型的稀疏性。

下面考察不同的惩罚力度和系数的变化

alphas, coefs, _ = lasso_path(X, y, eps=1e-4)
ax = plt.gca()
ax.plot(alphas, coefs.T)
ax.set_xscale('log')
plt.xlabel('alpha (log scale)')
plt.ylabel('Coefficients')
plt.title('Lasso Cofficient Path')
plt.axhline(0, linestyle='--', linewidth=1, color='k')
plt.legend(X_raw.columns)

 可以看到系数依次变为0,下面使用K折交叉验证收缩最优惩罚系数:

# Choose best Lasso regularization by 10-fold CV
kfold = KFold(n_splits=10, shuffle=True, random_state=1)
alphas=np.logspace(-4, -2, 100)
model = LassoCV(alphas=alphas, cv=kfold)
model.fit(X, y)
model.alpha_   

pd.DataFrame(model.coef_, index=X_raw.columns, columns=['Coefficient'])

最优惩罚系数为 0.00722,此时模型回归的系数为:

使用手工交叉验证,计算最优惩罚系数:

alphas = np.logspace(-4, -2, 100)
scores = []
for alpha in alphas:
    model = Lasso(alpha=alpha)
    kfold = KFold(n_splits=10, shuffle=True, random_state=1)
    scores_val = -cross_val_score(model, X, y, cv=kfold, scoring='neg_mean_squared_error')
    score = np.mean(scores_val)
    scores.append(score)

mse = np.array(scores)
index_min = np.argmin(mse)
alphas[index_min]

 最优系数为0.00722,和上面一样,模型的mse画图如下:

plt.plot(alphas, mse)
plt.axvline(alphas[index_min], linestyle='--', linewidth=1, color='k')
plt.xlabel('alpha')
plt.ylabel('Mean Squared Error')
plt.title('CV Error for Lasso')
plt.tight_layout()


弹性网回归

所谓弹性网回归,就是一范数和二范数都要,损失函数里面都加一点,代码如下

model = ElasticNet(alpha=0.1, l1_ratio=0.5)
model.fit(X, y)
model.score(X, y)

pd.DataFrame(model.coef_, index=X_raw.columns, columns=['Coefficient'])

模型拟合优度为0.6419,系数为如下

 画惩罚系数和变量系数变化图:

# Plot Elastic Net coefficient path
alphas, coefs, _ = enet_path(X, y, eps=1e-4, l1_ratio = 0.5)
ax = plt.gca()
ax.plot(alphas, coefs.T)
ax.set_xscale('log')
plt.xlabel('alpha (log scale)')
plt.ylabel('Coefficients')
plt.title('Elastic Net Cofficient Path (l1_ratio = 0.5)')
plt.axhline(0, linestyle='--', linewidth=1, color='k')
plt.legend(X_raw.columns)

 搜索最优超参数——惩罚系数

# Choose best ElasticNet hyperparameters by 10-fold CV            
alphas = np.logspace(-4, 0, 100)
kfold = KFold(n_splits=10, shuffle=True, random_state=1)
model = ElasticNetCV(cv=kfold, alphas = alphas, l1_ratio=[0.0001, 0.001, 0.01, 0.1, 0.5, 1])
model.fit(X,y)
#最优惩罚系数
model.alpha_
#一范数的比例
model.l1_ratio_
#拟合优度
model.score(X,y)
#变量系数
pd.DataFrame(model.coef_, index=X_raw.columns, columns=['Coefficient'])

划分训练集和测试集 验证模型是否过拟合,和泛化能力

## Use optimal ridge regression for prediction
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
model = RidgeCV(alphas=np.linspace(1, 20, 1000))
model.fit(X_train, y_train)
model.alpha_
#训练集拟合优度
model.score(X_train, y_train)
#测试集拟合优度
model.score(X_test, y_test)

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阡之尘埃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值