scikit-learn/sklearn学习|岭回归linear_model.Ridge()函数解读
【1】引言
前序学习进程中,已经对岭回归和岭回归的官方示例进行了解读,但之前侧重于展示岭回归算法对线性系数的影响,因此还有必要进一步追溯这种影响发生的根本原因,这就是本次学习的目的。
【2】linear_model.Ridge()函数
点击下方链接,直达官方linear_model.Ridge()函数的说明页面。
此处我们汇总一下主要内容:
lass sklearn.linear_model.Ridge(
alpha=1.0, 正则化强度
*,强制后续的参数必须通过关键字写入
fit_intercept=True,是否计算模型截距
normalize=False,是否进行归一化
copy_X=True,是否复制X
max_iter=None,共轭梯度求解器的最大迭代次数
tol=0.001, 优化算法的精度
solver=‘auto’,自动选择求解器
random_state=None 随机打乱数据)
在此基础上,我们回头看先前代码:
# X is the 10x10 Hilbert matrix
# 这里包括两个步骤
# 第一步,生成[1,2,...,10]的一维数组,一共10个数,组成一个行向量
# 第二步,生成[0,1,...,9]的一维数组,一共十个数,然后增加一个轴,转化为10行1列的二维矩阵,实际上是一个列向量
# 第三步,加号"+"串联起两个数组,并且数组自动广播,都变成10行10列的二维矩阵
# 二维矩阵相加的结果是,位置为(i,j)的元素实际上是第(i+1,j+1)的元素,比如第一行第一列的元素位置被记录为(0,0)而非(1,1)
# 执行加法计算后,元素位置为(i,j)处的计算结果为(i+1+j)
# 最后获得的X则是对加法计算的矩阵在每个位置再计算倒数后的值
X = 1. / (np.arange(1, 11) + np.arange(0, 10)[:, np.newaxis])
# y是一个纯1矩阵,一共10个数
y = np.ones(10)# #############################################################################
# Compute paths# 定义常数n_alphas = 200
n_alphas = 200
# 定义以10为底数的对数,真数从-10到-2均匀变化,一共输出n_alphas个/200个数
alphas = np.logspace(-10, -2, n_alphas)# 定义一个空列表
coefs = []
for a in alphas:# ridge定义了一个岭回归对象ridge = linear_model.Ridge(alpha=a, fit_intercept=False)# 执行岭回归计算ridge.fit(X, y)# ridge.coef_是岭回归计算出来的系数# 本例中,由于每一行的样本是10个特征,所以有10个系数# 每一行样本都会使用这10个系数coefs.append(ridge.coef_)
这里只用了两个参数:
ridge = linear_model.Ridge(alpha=a, fit_intercept=False)
首先用动态变化的a来改变alpha,然后计算不考虑截距,因为截距对计算结果没有影响。这种设置的目的是让代码聚焦于改变正则化强度因子。
这个时候让我们再看一次代码运行获得的效果图:
这里故意做了坐标轴的逆向,突出了一个内容:当alpha越小,也就是正则化强度越低,得到的线性系数就可能越大。
为了进一步对比,我们不妨在代码中该换一下强度因子定义方式:
# 定义常数n_alphas = 200
n_alphas = 200
# 定义以10为底数的对数,真数从-10到-2均匀变化,一共输出n_alphas个/200个数
alphas0 = np.logspace(-10, -2, n_alphas)
# 用指数函数计算正则化强度
alphas1 = np.exp(-1*np.linspace(0,10,n_alphas))
# 用三角函数来计算正则化强度
alphas2 = 0.5 * (1 + np.sin(np.linspace(-0.5 * np.pi, 0.5 * np.pi, n_alphas)))
# 将正弦序列的值映射到合理的alpha范围(0.001到1之间)
alphas2 = 0.001 + alphas2 * 0.999
之后绘图部分也分成三个小子图:
# 第一个子图 - 对数空间正则化
axes[0].plot(alphas0, coefs0)
axes[0].set_xscale('log')
axes[0].set_xlim(axes[0].get_xlim()[::-1]) # 反转x轴,使正则化强度从大到小
axes[0].set_ylabel('weights')
axes[0].set_title('Log-space regularization')
axes[0].grid(True, alpha=0.3)# 第二个子图 - 指数衰减正则化
axes[1].plot(alphas1, coefs1)
axes[1].set_xscale('log')
axes[1].set_xlim(axes[1].get_xlim()[::-1]) # 反转x轴
axes[1].set_ylabel('weights')
axes[1].set_title('Exponential decay regularization')
axes[1].grid(True, alpha=0.3)# 第三个子图 - 正弦序列正则化
axes[2].plot(alphas2, coefs2)
axes[2].set_xscale('log')
axes[2].set_xlim(axes[2].get_xlim()[::-1]) # 反转x轴
axes[2].set_xlabel('alpha')
axes[2].set_ylabel('weights')
axes[2].set_title('Sinusoidal sequence regularization')
axes[2].grid(True, alpha=0.3)
最后获得的图像为:
可见虽然正则化强度因子不一样,但最后获得的线性系数在高强度因子的作用下取值均趋向于0,符合稳健性的特征。
此时的完整代码为:
# 引入必要模块
import numpy as np
import matplotlib.pyplot as plt
# 引入线性模型
from sklearn import linear_model# X is the 10x10 Hilbert matrix
# 这里包括两个步骤
# 第一步,生成[1,2,...,10]的一维数组,一共10个数,组成一个行向量
# 第二步,生成[0,1,...,9]的一维数组,一共十个数,然后增加一个轴,转化为10行1列的二维矩阵,实际上是一个列向量
# 第三步,加号"+"串联起两个数组,并且数组自动广播,都变成10行10列的二维矩阵
# 二维矩阵相加的结果是,位置为(i,j)的元素实际上是第(i+1,j+1)的元素,比如第一行第一列的元素位置被记录为(0,0)而非(1,1)
# 执行加法计算后,元素位置为(i,j)处的计算结果为(i+1+j)
# 最后获得的X则是对加法计算的矩阵在每个位置再计算倒数后的值
X = 1. / (np.arange(1, 11) + np.arange(0, 10)[:, np.newaxis])
# y是一个纯1矩阵,一共10个数
y = np.ones(10)# #############################################################################
# Compute paths# 定义常数n_alphas = 200
n_alphas = 200
# 定义以10为底数的对数,真数从-10到-2均匀变化,一共输出n_alphas个/200个数
alphas0 = np.logspace(-10, -2, n_alphas)
# 用指数函数计算正则化强度
alphas1 = np.exp(-1*np.linspace(0,10,n_alphas))
# 用三角函数来计算正则化强度
alphas2 = 0.5 * (1 + np.sin(np.linspace(-0.5 * np.pi, 0.5 * np.pi, n_alphas)))
# 将正弦序列的值映射到合理的alpha范围(0.001到1之间)
alphas2 = 0.001 + alphas2 * 0.999
# 定义一个空列表
coefs0 = []
for a in alphas0:# ridge定义了一个岭回归对象ridge = linear_model.Ridge(alpha=a, fit_intercept=False)# 执行岭回归计算ridge.fit(X, y)# ridge.coef_是岭回归计算出来的系数# 本例中,由于每一行的样本是10个特征,所以有10个系数# 每一行样本都会使用这10个系数coefs0.append(ridge.coef_)coefs1 = []
for a in alphas1:# ridge定义了一个岭回归对象ridge = linear_model.Ridge(alpha=a, fit_intercept=False)# 执行岭回归计算ridge.fit(X, y)# ridge.coef_是岭回归计算出来的系数# 本例中,由于每一行的样本是10个特征,所以有10个系数# 每一行样本都会使用这10个系数coefs1.append(ridge.coef_)
# #############################################################################
# Display resultscoefs2 = []
for a in alphas2:# ridge定义了一个岭回归对象ridge = linear_model.Ridge(alpha=a, fit_intercept=False)# 执行岭回归计算ridge.fit(X, y)# ridge.coef_是岭回归计算出来的系数# 本例中,由于每一行的样本是10个特征,所以有10个系数# 每一行样本都会使用这10个系数coefs2.append(ridge.coef_)# 创建3行1列的图像布局
fig, axes = plt.subplots(3, 1, sharex=False)# 第一个子图 - 对数空间正则化
axes[0].plot(alphas0, coefs0)
axes[0].set_xscale('log')
axes[0].set_xlim(axes[0].get_xlim()[::-1]) # 反转x轴,使正则化强度从大到小
axes[0].set_ylabel('weights')
axes[0].set_title('Log-space regularization')
axes[0].grid(True, alpha=0.3)# 第二个子图 - 指数衰减正则化
axes[1].plot(alphas1, coefs1)
axes[1].set_xscale('log')
axes[1].set_xlim(axes[1].get_xlim()[::-1]) # 反转x轴
axes[1].set_ylabel('weights')
axes[1].set_title('Exponential decay regularization')
axes[1].grid(True, alpha=0.3)# 第三个子图 - 正弦序列正则化
axes[2].plot(alphas2, coefs2)
axes[2].set_xscale('log')
axes[2].set_xlim(axes[2].get_xlim()[::-1]) # 反转x轴
axes[2].set_xlabel('alpha')
axes[2].set_ylabel('weights')
axes[2].set_title('Sinusoidal sequence regularization')
axes[2].grid(True, alpha=0.3)# 整体标题
plt.suptitle('Ridge coefficients as a function of different regularization sequences',fontsize=16, y=0.95)plt.tight_layout()
plt.show()
【3】总结
详细解读了岭回归linear_model.Ridge()函数,并且尝试更改了正则化强度因子alpha的定义方式,获得了高强度正则化条件下线性化系数趋向于相同取值的效果。