由于过滤法的特征选择过程与后续的机器学习模型无关,因此过滤法可能导致较差的模型性能。

封装法利用预定义的有监督的机器学习模型来选择最佳功能。但是,由于它们需要在大量可能的特征子集上多次
训练模型,因此尽管它们通常会导致更好的性能,但它们同时也需要较长的处理时间。

嵌入式方法将特征选择过程嵌入到机器学习模型中,即利用机器学习来为每一个特征打分。嵌入式方法在创建模型时即完成了对特征子集的选择。因此,与过滤法相比,它们往往具有更好的性能。与封装方法相比,它们节省了大量的处理时间和计算能力。

三个方法的对比如下:

方面 过滤法 封装法 嵌入法
是否需要模型参与
是否需要交叉验证 可能(可利用交叉验证选择保留的特征数目) 可能(可利用交叉研究保留的特征数目)
处理时间 中等
对参与模型的限制 是(嵌入法使用的模型为线性模型或树类模型)

基于正则化模型的方法

许多机器学习模型在其损失函数中引入了正则项(L1正则或L2正则),以防止过拟合问题。线性模型(例如线性向量支持机,逻辑回归,线性回归)中的L1正则项能够有效地将某些特征的特征系数缩小为零,从而实现解的稀疏。因此,基于带正则项线性模型的特征系数,我们可以为特征打分。系数越高,往往该特征在线性模型中越重要。我们可以使用sklearn SelectFromModel函数删除特征系数低或为零的特征。

套索回归

套索回归(Lasso Regression (Linear Regression with L1 Norm)

  1. import numpy as np
  2. from sklearn.feature_selection import SelectFromModel
  3. from sklearn.linear_model import Lasso # 我们也可以使用带L2正则项的岭回归
  4. # 直接载入数据集
  5. from sklearn.datasets import fetch_california_housing
  6. dataset = fetch_california_housing()
  7. X, y = dataset.data, dataset.target # 利用 california_housing 数据集来演示
  8. # 选择前15000个观测点作为训练集
  9. # 剩下的作为测试集
  10. train_set = X[0:15000,:]
  11. test_set = X[15000:,]
  12. train_y = y[0:15000]
  13. clf = Lasso(normalize=True, alpha = 0.001)
  14. # 在进行线性回归前,我们需要先对变量进行缩放操作,否则回归系数大小无法比较
  15. # alpha控制正则效果的大小,alpha越大,正则效果越强
  16. clf.fit(train_set, train_y) # 在训练集上训练
  17. np.round(clf.coef_ ,3)

输出:array([ 0.346, 0.003, -0. , -0. , -0. , -0. , -0.033, 0. ])

  1. selector = SelectFromModel(clf, prefit=True, threshold=1e-5)
  2. # 阈值被设置为1e-5,因此绝对系数低于1e-5的特征将被删除
  3. # 我们还可以设置max_features参数以选择最重要的前几个特征
  4. transformed_train = selector.transform(train_set) # 转换训练集
  5. transformed_test = selector.transform(test_set) #转换测试集
  6. assert np.array_equal(transformed_train, train_set[:,[0,1,6]])
  7. # 选择第一个,第二个及第七个变量
  8. assert np.array_equal(transformed_test, test_set[:,[0,1,6]])

逻辑回归

逻辑回归(Logistic Regression (with L1 Norm)

import numpy as np
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris  # 利用iris数据作为演示数据集

# 载入数据集
iris = load_iris()
X, y = iris.data, iris.target

# iris 数据集使用前需要被打乱顺序
np.random.seed(1234)
idx = np.random.permutation(len(X))
X = X[idx]
y = y[idx]

# 选择前100个观测点作为训练集
# 剩下的50个观测点作为测试集
train_set = X[0:100,:]
test_set = X[100:,]
train_y = y[0:100]

# 在进行逻辑回归前,我们需要先对变量进行缩放操作,否则回归系数大小无法比较
from sklearn.preprocessing import StandardScaler
model = StandardScaler()
model.fit(train_set) 
standardized_train = model.transform(train_set)
standardized_test = model.transform(test_set)

clf = LogisticRegression(penalty='l1', C = 0.7, 
                         random_state=1234, solver='liblinear') 
# 我们也可以将正则项设置为 'l2'
# C控制正则效果的大小,C越大,正则效果越弱

clf.fit(standardized_train, train_y)
np.round(clf.coef_,3)

输出:
array([[ 0. , 1. , -3.452, -0.159],
[ 0. , -1.201, 0.053, 0. ],
[ 0. , 0. , 1.331, 3.27 ]])

selector = SelectFromModel(clf, prefit=True, threshold=1e-5)
# 阈值被设置为1e-5,因此绝对系数低于1e-5的特征将被删除
# 我们还可以设置max_features参数以选择最重要的前几个特征

transformed_train = selector.transform(train_set) # 转换训练集
transformed_test = selector.transform(test_set) #转换测试集

assert np.array_equal(transformed_train, train_set[:,[1,2,3]]) 
# 选择第2个, 第3个及第4个变量
assert np.array_equal(transformed_test, test_set[:,[1,2,3]])