游乐游手机版
首页/AI热点日报/热点详情

机器学习特征选择的四种实用方法

类型:热点整理2026-07-02
在机器学习项目中,特征选择(Feature Selection)往往容易被忽视,但事实上,它却是决定模型成败的核心环节之一。本文梳理了四种经典的特征选择方法,并附上基于Scikit-learn的实战代码,帮助您快速掌握并应用于实际项目。 注:本文节选自Ankit Dixit所著的《集成机器学习》(E

在机器学习项目中,特征选择(Feature Selection)往往容易被忽视,但事实上,它却是决定模型成败的核心环节之一。本文梳理了四种经典的特征选择方法,并附上基于Scikit-learn的实战代码,帮助您快速掌握并应用于实际项目。

探讨机器学习中特征选择的4种方法

注:本文节选自Ankit Dixit所著的《集成机器学习》(Ensemble Machine Learning)一书。该书专注于讲解如何组合多种强大的机器学习算法来构建优化模型,非常适合作为初学者入门的实践指南。

下面我们详细讨论的方法包括:单变量特征选择、递归特征消除(RFE)、主成分分析(PCA)以及基于特征重要度的筛选。前三种方法将简要介绍,最后一种在数据科学社区中应用最为广泛,因此会展开深入讲解。

单变量特征选择

统计检验可以帮助我们找出与输出变量关联最强的特征。Scikit-learn的SelectKBest类正是为此设计的——你可以搭配不同的统计检验方法,直接指定要保留的特征数量。

下面的示例采用了卡方检验(适用于非负特征),从皮马印第安人糖尿病数据集中选取四个最佳特征:

# Feature Extraction with Univariate Statistical Tests (Chi-squared for classification)
# Import the required packages
import pandas
import numpy
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

url = "https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]

test = SelectKBest(score_func=chi2, k=4)
fit = test.fit(X, Y)
numpy.set_printoptions(precision=3)
print(fit.scores_)

features = fit.transform(X)
print(features[0:5,:])

运行后,你会看到每个特征的得分,以及被选中的四个参数——plas、test、mass和age。具体分数如下:

[111.52 1411.887 17.605 53.108 2175.565 127.669 5.393 181.304]

最终选出的特征矩阵:

[[148.  0.  33.6 50. ]
 [85.  0.  26.6 31. ]
 [183. 0.  23.3 32. ]
 [89.  94. 28.1 21. ]
 [137. 168. 43.1 33. ]]

递归特征消除(RFE)

RFE的思路非常直观:反复删除特征,在剩余特征上训练模型,然后根据模型精度判断哪些特征(或特征组合)对预测目标贡献最大。你可以使用任何稳定的模型,例如逻辑回归。下面的例子借助RFE搭配逻辑回归选出前三个重要特征:

import pandas
import numpy
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression

url = "https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]

model = LogisticRegression()
rfe = RFE(model, 3)
fit = rfe.fit(X, Y)
print("Num Features: %d"% fit.n_features_)
print("Selected Features: %s"% fit.support_)
print("Feature Ranking: %s"% fit.ranking_)

输出结果:

Num Features: 3
Selected Features: [ True False False False False  True  True False]
Feature Ranking: [1 2 3 5 6 1 1 4]

可以看到,RFE最终选出了preg、mass和pedi这三个特征,它们在support_数组中被标记为True,在ranking_中排名第一(标记为1)。

主成分分析(PCA)

PCA通过线性代数将数据压缩为更紧凑的形式,通常被视为一种降维技术。它有一个自然的属性:你可以指定要保留的主成分数量。下面我们使用PCA从原始数据中提取三个主成分:

import pandas
import numpy
from sklearn.decomposition import PCA

url = "https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]

pca = PCA(n_components=3)
fit = pca.fit(X)
print("Explained Variance: %s") % fit.explained_variance_ratio_
print(fit.components_)

转换后的三个主成分虽然与原始特征几乎没有直接可比性,但它们解释了数据中绝大部分方差:

Explained Variance: [ 0.88854663  0.06159078  0.02579012]
[[ -2.02176587e-03   9.78115765e-02   1.60930503e-02   6.07566861e-02
    9.93110844e-01   1.40108085e-02   5.37167919e-04  -3.56474430e-03]
 [ -2.26488861e-02  -9.72210040e-01  -1.41909330e-01   5.78614699e-02
    9.46266913e-02  -4.69729766e-02  -8.16804621e-04  -1.40168181e-01]
 [ -2.24649003e-02   1.43428710e-01  -9.22467192e-01  -3.07013055e-01
    2.09773019e-02  -1.32444542e-01  -6.39983017e-04  -1.25454310e-01]]

基于特征重要度的选择

这种方法思路非常直接:利用训练好的有监督分类器(比如随机森林)来评估每个特征的重要性。当决策树在训练时,每个节点都会选择一个特征来分割数据,而衡量这个分割效果的指标(如基尼系数、信息增益或方差)就可以作为特征重要度的打分依据。随机森林汇集了多棵树的判断,平均后给出每个特征的最终得分。

接下来我们用一个实际案例来演示:使用随机森林做特征选择,并比较选择前后分类器的性能。这里使用Kaggle上的Otto数据集(需要注册下载),该数据集包含超过61000个产品、93个模糊特征,目标是将产品分成10个类别(如时尚、电子等)。评价指标是多类对数损失。

首先导入必要的工具库:

from pandas import read_csv
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import SelectFromModel
np.random.seed(1)

定义拆分训练集和测试集的函数:

def getTrainTestData(dataset, split):
    np.random.seed(0)
    training = []
    testing = []
    np.random.shuffle(dataset)
    shape = np.shape(dataset)
    trainlength = np.uint16(np.floor(split * shape[0]))
    for i in range(trainlength):
        training.append(dataset[i])
    for i in range(trainlength, shape[0]):
        testing.append(dataset[i])
    training = np.array(training)
    testing = np.array(testing)
    return training, testing

定义评估准确率的函数:

def getAccuracy(pre, ytest):
    count = 0
    for i in range(len(ytest)):
        if ytest[i] == pre[i]:
            count += 1
    acc = float(count) / len(ytest)
    return acc

加载数据集,取前50000个实例,其中70%用于训练,30%用于测试:

data = read_csv('train.csv')
feat = data.keys()
feat_labels = feat.get_values()
dataset = data.values
np.random.shuffle(dataset)
inst = 50000
dataset = dataset[0:inst, :]
train, test = getTrainTestData(dataset, 0.7)
Xtrain = train[:, 0:94]
ytrain = train[:, 94]
shape = np.shape(Xtrain)
print("Shape of the dataset ", shape)
print("Size of Data set before feature selection: %.2f MB" % (Xtrain.nbytes / 1e6))

输出:

Shape of the dataset (35000, 94)
Size of Data set before feature selection: 26.32 MB

接下来构建随机森林分类器:250棵树,最大深度30,每次分裂随机选择7个特征,其余参数保持默认。

Xtest = test[:, 0:94]
ytest = test[:, 94]

trees = 250
max_feat = 7
max_depth = 30
min_sample = 2
clf = RandomForestClassifier(n_estimators=trees,
                             max_features=max_feat,
                             max_depth=max_depth,
                             min_samples_split=min_sample,
                             random_state=0,
                             n_jobs=-1)

import time
start = time.time()
clf.fit(Xtrain, ytrain)
end = time.time()
print("Execution time for building the Tree is: %f" % (float(end) - float(start)))

pre = clf.predict(Xtest)
acc = getAccuracy(pre, ytest)
print("Accuracy of model before feature selection is %.2f" % (100 * acc))

输出:

Execution time for building the Tree is: 2.913641
Accuracy of model before feature selection is 98.82

准确率已经高达98.82%,但在特征选择后还能进一步提升。我们来看看每个特征的重要度:

print(feature)
('id', 0.33346650420175183)
('feat_1', 0.0036186958628801214)
('feat_2', 0.0037243050888530957)
('feat_3', 0.011579217472062748)
('feat_4', 0.010297382675187445)
('feat_5', 0.0010359139416194116)
('feat_6', 0.00038171336038056165)
('feat_7', 0.0024867672489765021)
('feat_8', 0.0096689721610546085)
('feat_9', 0.007906150362995093)
('feat_10', 0.0022342480802130366)
...

可以看到,每个特征的重要度差异很大。我们设定阈值0.01,只保留重要度高于该值的特征:

sfm = SelectFromModel(clf, threshold=0.01)
sfm.fit(Xtrain, ytrain)
Xtrain_1 = sfm.transform(Xtrain)
Xtest_1 = sfm.transform(Xtest)

print("Size of Data set before feature selection: %.2f MB" % (Xtrain_1.nbytes / 1e6))
shape = np.shape(Xtrain_1)
print("Shape of the dataset ", shape)

输出:

Size of Data set before feature selection: 5.60 MB
Shape of the dataset (35000, 20)

特征从94个锐减到20个,数据集大小从26.32MB降到5.60MB,缩减了约80%。

接下来用同样的超参数在缩减后的数据集上训练并测试:

start = time.time()
clf.fit(Xtrain_1, ytrain)
end = time.time()
print("Execution time for building the Tree is: %f" % (float(end) - float(start)))

pre = clf.predict(Xtest_1)
acc2 = getAccuracy(pre, ytest)
print("Accuracy after feature selection %.2f" % (100 * acc2))

输出:

Execution time for building the Tree is: 1.711518
Accuracy after feature selection 99.97

结果令人振奋:准确率提升到99.97%,训练时间从2.91秒缩短到1.71秒,模型更轻、更快、更准。

评估标准 特征选择前 特征选择后
特征数量 94 20
数据集大小 26.32MB 5.60MB
训练时间 2.91 s 1.71 s
精确度 98.82% 99.97%

上表直观地展现了特征选择的实际价值:减少特征数量,降低模型复杂度,缩短训练时间,最终还能提升准确率。本文共介绍了四种经典的机器学习特征选择方法,从统计检验到递归消除,从主成分分析到基于模型重要度的筛选,各有适用场景。在实际项目中,具体选择哪种方法取决于数据规模、任务类型以及对可解释性的需求。

来源:https://m.elecfans.com/article/1309512.html

相关热点

继续查看同栏目近期热点。

延伸阅读

补充最近整理过的热点入口。