sklearn-逻辑回归-特征工程示例
在实际应用场景中,有时候特征的数量会很多,我们出于业务考虑,也出于计算量的考虑,希望对逻辑回归进行特征选择来降维。比如在判断一个人是否会患乳腺癌的时候,医生如果看58个指标来确诊,会比看30多个指标容易得多,因此就挑选58个至关重要的指标来看
高效的嵌入法 embedded 实现降维
由于 L1 正则化会使得部分特征对应的参数变为0, 因此 L1 正则化可以用来做特征选择。结合嵌入法的模块 SelectFromModel,可以很容易筛选出让模型十分高效的特征。此时我们的目的是尽量保留原数据上的信息,让模型在降维后的数据上拟合效果保持十分优秀,因此我们不考虑训练集测试集的问题,把所有的数据都放入模型进行降维。
示例代码看效果
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression as LR
# load_breast_cancer 为乳腺癌数据集
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import cross_val_score
from sklearn.feature_selection import SelectFromModel
# 将数据集实例化,不考虑测试集和训练集的问题,直接把数据集都导入模型中
data = load_breast_cancer()
# 查看数据集结构, 结果如 图1 所示
data.data.shape
# C为0.9, penalty 默认为 L2
LR_ = LR(solver="liblinear", C=0.8, random_state = 420)
# 进行交叉验证,入参依次为 模型、特征矩阵、标签、cv交叉验证次数为10次,mean取平均值,得出结果如 图2 所示
cross_val_score(LR_, data.data, data.target, cv=10).mean()
# 对数据进行降维,并打印最终特征矩阵的结构,如 图3 所示
# 嵌入法 SelectFromModel 的实例化,LR_代表模型,norm_order=1代表使用l1范式,模型会删除所有在 L1 范式下面被判断为无效的特征
# fit_transform 直接输入特征矩阵和标签,得出最终的特征矩阵 x_embedded
x_embedded = SelectFromModel(LR_, norm_order=1).fit_transform(data.data, data.target)
x_embedded.shape
# 使用x_embedded进行交叉验证, 结果如 图4 所示
cross_val_score(LR_, x_embedded, data.target, cv=10).mean()
图1:
图2:
图3:
图4:
调节模型到最佳拟合效果
根据示例代码,使用嵌入法完成降维之后,特征由 30 个减少到了 9个,模型效果由 0.95 下降到 0.93,效果并没有下降太多,模型还是比较的高效。
如果要求比较高,想要让模型的拟合效果更好,可以借助学习曲线来观察
通过 threshold 参数画学习曲线
threshold 参数是一个浮点数,代表特征的重要性低于这个浮点数的都删除。在逻辑回归中就是系数,系数越大,这个参数对逻辑回归的影响性就越大,所以 threshold 参数可以取到的最大值,就是系数的最大值
相关代码
# 查看模型里面所有的系数,系数值越大,代表这个特征对逻辑回归的贡献越大,结果如 图5 所示
LR_.fit(data.data, data.target).coef_
# 完整的特征矩阵结果列表
fullx = []
# 特征选择后的特征矩阵结果列表
fsx = []
# 取从0开始,系数的绝对值最大值结束的,20个数的列表,作为 threshold 的可选入参,进行循环
threshold = np.linspace(0, abs(LR_.fit(data.data, data.target).coef_).max(), 20)
# 打印 threshold 列表,如 图6 所示
print(threshold)
k = 0
for i in threshold:
# threshold从0开始,逐渐靠近系数最大值时,模型的表现变化
X_embedded = SelectFromModel(LR_, threshold = i).fit_transform(data.data, data.target)
# 完整的特征矩阵交叉验证的结果
fullx.append(cross_val_score(LR_, data.data, data.target, cv=5).mean())
# 特征选择后的特征矩阵交叉验证结果
fsx.append(cross_val_score(LR_, X_embedded, data.target, cv=10).mean())
# 打印 threshold 里面取到的每一个值 和 降维后的特征矩阵含有多少个特征,如 图7 所示
print((threshold[k], X_embedded.shape[1]))
k +=1
plt.figure(figsize=(20, 5))
plt.plot(threshold, fullx, label="full")
plt.plot(threshold, fsx, label="feature selection")
plt.xticks(threshold)
plt.legend()
# 打印学习曲线图,如 图8 所示
plt.show()
图5:
图6:
图7:
图8:
由图7和图8可见,threshold 从 0 到 0.1 的时候,特征个数删减的最多,从30个特征删减到了17个特征,后面 threshold 的变动,特征个数的变动都比较小,最后5个取值特征个数都稳定在1个。学习效果从0.95下降到0.93左右,此后随着threshold逐渐变大,学习效果也在降低。可见 threshold 的取值设置区间过大,没有参考价值。我们要找的是降维之后,存在着能够让模型效果保持优异的情况。 可以取0到0.101之间的范围,再次查看特征个数和学习曲线是如何波动的,结果如 图9 所示
图9:
由图9可见,threshold 在0.0215之前,模型学习效果和全特征学习效果差别不大,当 threshold 大于 0.0215的后,模型学习效果开始下降。由此,最少的特征量取24、25个合适。相较于30个,降维并不明显,可见该方法不适用于乳腺癌数据集。
通过画C的学习曲线
第二种方式是直接调整逻辑回归的类 LR 本身,通过画 C 的学习曲线来实现。
相关代码
# 完整的特征矩阵结果列表
fullx = []
# 特征选择后的特征矩阵结果列表
fsx = []
# 一般 C 取值范围是 0 到 1,这个模型可以试验一下,取 0 到 10 比较好
# 以 0.01 为开头,10.01 为结尾,每隔 0.5 取一个数
C = np.arange(0.01, 10.01, 0.5)
for i in C:
# 根据不同的C,构建不同的模型
LR_C = LR(solver="liblinear", C=i, random_state=420)
# 完整的特征矩阵交叉验证的结果
fullx.append(cross_val_score(LR_C, data.data, data.target, cv=10).mean())
X_embedded = SelectFromModel(LR_C,norm_order=1).fit_transform(data.data, data.target)
# 特征选择后的特征矩阵交叉验证结果
fsx.append(cross_val_score(LR_C, X_embedded, data.target, cv=10).mean())
# 打印特征选择后特征矩阵模型交叉验证分数列表里的最高的值,以及对应的 C 值
print(max(fsx), C[fsx.index(max(fsx))])
plt.figure(figsize=(20, 5))
plt.plot(C, fullx, label="full")
plt.plot(C, fsx, label="feature selection")
plt.xticks(C)
plt.legend()
# 打印学习曲线图,如 图10 所示
plt.show()
图10:
由图10可见,C为 8.51 的时候,模型的学习效果达到最优 0.956,并且要比蓝色的全量特征的分值还高。在这条学习曲线中,C的取值范围比较大,一般来讲,C的取值范围在0到1之间,我们可以将C范围划定在 8.01 到 9.01 ,以0.005为间隔画C的学习曲线,如图11所示
图11:
由图11可见,C位8.025000000000002的时候,模型的学习效果最好,为0.9563164376458386,我们可以验证一下,当 C 取该值时,模型降维效果如何
验证模型降维效果
LR_ = LR(solver="liblinear", C=8.025000000000002, random_state=420)
# 打印完整的特征矩阵交叉验证的结果
print("完整的特征矩阵交叉验证的结果:{}".format(cross_val_score(LR_, data.data, data.target, cv=10).mean()))
X_embedded = SelectFromModel(LR_,norm_order=1).fit_transform(data.data, data.target)
# 打印降维后的特征矩阵交叉验证的结果
print("降维后的特征矩阵交叉验证的结果:{}".format(cross_val_score(LR_, X_embedded, data.target, cv=10).mean()))
# 打印降维后的维度
print(X_embedded.shape)
图12:
由图12可见,通过C学习曲线找到的最佳C变量,完成降维后的模型,学习效果达到了 0.956,由30个特征成功降维到9个特征