由于过滤法的特征选择过程与后续的机器学习模型无关,因此过滤法可能导致较差的模型性能。
封装法利用预定义的有监督的机器学习模型来选择最佳功能。但是,由于它们需要在大量可能的特征子集上多次
训练模型,因此尽管它们通常会导致更好的性能,但它们同时也需要较长的处理时间。
嵌入式方法将特征选择过程嵌入到机器学习模型中,即利用机器学习来为每一个特征打分。嵌入式方法在创建模型时即完成了对特征子集的选择。因此,与过滤法相比,它们往往具有更好的性能。与封装方法相比,它们节省了大量的处理时间和计算能力。
三个方法的对比如下:
方面 | 过滤法 | 封装法 | 嵌入法 |
---|---|---|---|
是否需要模型参与 | 否 | 是 | 是 |
是否需要交叉验证 | 可能(可利用交叉验证选择保留的特征数目) | 是 | 可能(可利用交叉研究保留的特征数目) |
处理时间 | 短 | 长 | 中等 |
对参与模型的限制 | 无 | 无 | 是(嵌入法使用的模型为线性模型或树类模型) |
基于正则化模型的方法
许多机器学习模型在其损失函数中引入了正则项(L1正则或L2正则),以防止过拟合问题。线性模型(例如线性向量支持机,逻辑回归,线性回归)中的L1正则项能够有效地将某些特征的特征系数缩小为零,从而实现解的稀疏。因此,基于带正则项线性模型的特征系数,我们可以为特征打分。系数越高,往往该特征在线性模型中越重要。我们可以使用sklearn SelectFromModel函数删除特征系数低或为零的特征。
套索回归
套索回归(Lasso Regression (Linear Regression with L1 Norm)
import numpy as np
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import Lasso # 我们也可以使用带L2正则项的岭回归
# 直接载入数据集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 数据集来演示
# 选择前15000个观测点作为训练集
# 剩下的作为测试集
train_set = X[0:15000,:]
test_set = X[15000:,]
train_y = y[0:15000]
clf = Lasso(normalize=True, alpha = 0.001)
# 在进行线性回归前,我们需要先对变量进行缩放操作,否则回归系数大小无法比较
# alpha控制正则效果的大小,alpha越大,正则效果越强
clf.fit(train_set, train_y) # 在训练集上训练
np.round(clf.coef_ ,3)
输出:array([ 0.346, 0.003, -0. , -0. , -0. , -0. , -0.033, 0. ])
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[:,[0,1,6]])
# 选择第一个,第二个及第七个变量
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]])