目录
L1正则化问题的求解——近端梯度下降(Proximal Gradient Descent, PGD)
其核心思想是:利用“泰勒展开”将目标函数的求解问题,变为一个“二次函数的求解问题”。
11.1 子集搜索与评价
对一个学习任务来说,给定属性集,其中有些属性可能很关键、很有用,另一些属性则可能没什么用.我们将属性称为"特征" (feature) ,对当前学习任务有用的属性称为"相关特征" (relevant feature) 、没什么用的属性称为"无关特征" (irrelevant feature). 从给远的特征集合中选择出相关特征于集的过程,称为"特征选择" (feature selection)。
我们不能直接用排列组合进行遍历所有可能子集,这样会遭遇组合爆炸。所以我们选择产生一个“候选子集”,评价它的好坏,然后根据评价结果产生下一个候选特征子集,再进行评价,持续进行直到无法找到一个更好的子集为止。
将特征子集搜索机制和子集评价机制相结合,即可得到特征选择方法。
11.2 过滤式选择(Relief)
过滤式方法是一种将特征选择与学习器训练相分离的特征选择技术,即首先将相关特征挑选出来,再使用选择出的数据子集来训练学习器。Relief是其中著名的代表性算法,它使用一个“相关统计量”来度量特征的重要性,该统计量是一个向量,其中每个分量代表着相应特征的重要性,因此我们最终可以根据这个统计量各个分量的大小来选择出合适的特征子集。
Relief算法的关键是如何确定相关统计量。对于数据集中的每个样例xi,Relief首先找出与xi同类别的最近邻与不同类别的最近邻,分别称为猜中近邻(near-hit)与猜错近邻(near-miss),接着便可以分别计算出相关统计量中的每个分量。对于j分量:
\(\delta^j=\sum_i-\mathrm{diff}(x_i^j,x_{i,\mathrm{nh}}^j)^2+\mathrm{diff}(x_i^j,x_{i,\mathrm{nm}}^j)^2\)
直观上理解:对于猜中近邻,两者j属性的距离越小越好,对于猜错近邻,j属性距离越大越好。更一般地,若xi为离散属性,diff取海明距离,即相同取0,不同取1;若xi为连续属性,则diff为曼哈顿距离,即取差的绝对值。分别计算每个分量,最终取平均便得到了整个相关统计量。
标准的Relief算法只用于二分类问题,后续产生的拓展变体Relief-F则解决了多分类问题。对于j分量,新的计算公式如下:
\(\delta^{j}=\sum_{i}-\mathrm{diff}(x_{i}^{j},x_{i,\mathrm{nh}}^{j})^{2}+\sum_{l\neq k}\left(p_{l}\times\mathrm{diff}(x_{i}^{j},x_{i,l,\mathrm{nm}}^{j})^{2}\right)\)
其中\(p_l\)表示第\(l\)类样本在数据集中所占的比例,易知两者的不同之处在于:标准Relief 只有一个猜错近邻,而Relief-F有多个猜错近邻。
11.3 包裹式选择(LVW)
与过滤式选择不同的是,包裹式选择将后续的学习器也考虑进来作为特征选择的评价准则。因此包裹式选择可以看作是为某种学习器量身定做的特征选择方法,由于在每一轮迭代中,包裹式选择都需要训练学习器,因此在获得较好性能的同时也产生了较大的开销。
LVW(Las Vegas Wrapper),它在拉斯维加斯框架下使用随机策略来进行特征子集的搜索,并以最终分类器的误差为特征子集评价准则。
调用LVW函数,传入鸢尾花数据集的特征和目标变量。打印最佳分数和最佳特征子集。
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.feature_selection import SelectKBest, f_classif
from itertools import combinations
import numpy as np
# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target
# 定义LVW函数
def LVW(X, y, max_iter=100, threshold=0.01, learning_alg=LogisticRegression()):
best_score = 0.0
best_features = None
best_estimator = None
# 初始化特征全集
full_features = np.arange(X.shape[1])
for i in range(max_iter):
# 随机选择特征子集
random_features = np.random.choice(full_features, size=int(np.sqrt(X.shape[1])), replace=False)
X_subset = X[:, random_features]
# 评估特征子集
estimator = learning_alg.fit(X_subset, y)
scores = cross_val_score(estimator, X_subset, y, cv=5)
mean_score = np.mean(scores)
# 记录并比较性能
if mean_score - best_score > threshold:
best_score = mean_score
best_features = random_features
best_estimator = estimator
return best_score, best_features, best_estimator
# 运行LVW算法
score, features, estimator = LVW(X, y)
print(f"Best score: {score:.4f}")
print(f"Best features: {features}")
Best score表示通过LVW算法找到的最佳模型性能分数为0.9600。Best features表示通过LVW算法找到的最佳特征子集包含索引为2和3的特征。这意味着,在鸢尾花数据集的四个特征中,算法认为索引为2和3的特征组合能够给出最佳的模型性能。
11.4 嵌入式选择与正则化
将特征选择过程与学习器训练过程融为一体,两者在同一个优化过程中完成,即在学习器训练过程中自动进行了特征选择。
L1 和 L2 正则化都有助于降低过拟合风险,但L1还会带来一个额外的好处:它比L2更易于获得 “稀疏”解,即求得的w会有更少的非零分量(即抹除了更多的特征属性)。
意味着初始的d个特征中仅有对应着w的非零分量的特征才会出现在最终模型中,于是求解L1范数正则化的结果是得到了仅采用一部分初始特征的模型,即基于L1正则化的学习方法就是一种嵌入式特征选择方法。
L1正则化问题的求解——近端梯度下降(Proximal Gradient Descent, PGD)
其核心思想是:利用“泰勒展开”将目标函数的求解问题,变为一个“二次函数的求解问题”。
11.5 稀疏表示与字典学习
当样本数据是一个稀疏矩阵时,对学习任务来说会有不少的好处,例如很多问题变得线性可分,储存更为高效等。这便是稀疏表示与字典学习的基本出发点。稀疏矩阵即矩阵的每一行/列中都包含了大量的零元素,且这些零元素没有出现在同一行/列,对于一个给定的稠密矩阵,若我们能通过某种方法找到其合适的稀疏表示,则可以使得学习任务更加简单高效,我们称之为稀疏编码(sparse coding)或字典学习(dictionary learning)。
11.6 压缩感知
关注的是如何利用信号本身所具有的稀疏性,从部分观测样本中恢复原信号,通常压缩感知分为:
- 感知测量(关注如何对原始信号进行处理以获得稀疏样本表示)
- 重构恢复(关注的是如何基于稀疏性从少量观测中恢复原信号,通常压缩感知指的是这部分)两个阶段。
鸢尾花数据集分类任务的特征选择
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn import datasets
from sklearn.feature_selection import SelectKBest, chi2, SelectFromModel
from sklearn.svm import LinearSVC
if __name__ == '__main__':
# 加载数据
iris = datasets.load_iris()
# 使用样本的所有特征(150, 4)
x = iris.data
y = iris.target
label_dict = iris.target_names
feature_dict = iris.feature_names
# 数据预处理 - 单变量特征选择, k=2选择最好的两个特征
x_best = SelectKBest(chi2, k=2).fit_transform(x, y)
print('特征选择后的维数', x_best.shape) # (150, 2)
# 基于 L1 的特征选取;在 SVM 和逻辑回归中,参数 C 是用来控制稀疏性的:小的 C 会导致少的特征被选择
lsvc = LinearSVC(C=0.01, penalty="l1", dual=False, max_iter=2000).fit(x, y)
model = SelectFromModel(lsvc, prefit=True)
x_model = model.transform(x)
print('特征选择后的维数', x_model.shape) # (150, 3)
# 单变量特征选择的数据散点图
for label, marker, color in zip(range(0, 3), ('*', 's', 'o'), ('blue', 'red', 'green')):
plt.scatter(x=x_best[y == label][:, 0],
y=x_best[y == label][:, 1],
marker=marker,
color=color,
alpha=0.5,
label='label_{}'.format(label))
plt.title('Iris feature selection')
plt.xlabel('xr', fontsize=14)
plt.ylabel('yr', fontsize=14)
plt.legend(loc='upper right', fancybox=True)
plt.tick_params(labelsize=10)
# plt.show()
# SelectFromModel 选取特征特征绘图
fig = plt.figure()
ax3d = Axes3D(fig, rect=[0, 0, 1, 1], elev=20, azim=20)
ax3d.scatter(x_model[:, 0], x_model[:, 1], x_model[:, 2], c=y, cmap='brg')
plt.show()
单变量特征选择和使用 SelectFromModel 选取特征的标准是不一样的,除了一个坐标轴刻度相同外,其他坐标轴数据不同。即:SelectFromModel 选择的特征不是“最好”的(SelectKBest)