【译文】Python实现机器学习特征选择的4种方法

原文标题:4 ways to implement feature selection in Python for machine learning
原文链接:https://hub.packtpub.com/4-ways-implement-feature-selection-python-machine-learning/

作者:Sugandha Lahoti

注:
本文节选自Ankit Dixit所著的《集成机器学习》(Ensemble Machine Learning)一书。这本书组合强大的机器学习算法来建立优化模型,可以作为初学者的指南。

我们将研究从数据集中选择特征的不同方法;同时通过使用Python中Scikit-learn (sklearn) 库的实现讨论特征选择算法的类型:

1.单变量选择
2.递归特征消除(RFE)
3.主成分分析(PCA)
4.选择重要特征(特征重要度)

本文简要介绍了前三种算法及其实现,然后详细讨论了在数据科学社区中广泛使用的选择重要特征(特性重要度)部分的内容。

单变量选择

统计测试可用于选择那些与输出变量关系最强的特征。

scikit-learn库提供了SelectKBest类,它可以与一组不同的统计测试一起使用,以选择特定数量的特征。

下面的例子使用chi²非负性特征的统计测试,从皮马印第安人糖尿病发病数据集中选择了四个最好的特征:

1. #Feature Extraction with Univariate Statistical Tests (Chi-squared for classification)
2. #Import the required packages
3. #Import pandas to read csv import pandas
4. #Import numpy for array related operations import numpy
5. #Import sklearn's feature selection algorithm
6. from sklearn.feature_selection import SelectKBest
7. #Import chi2 for performing chi square test from sklearn.feature_selection import chi2
8. #URL for loading the dataset
9. url ="https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians diabetes/pima-indians-diabetes.data"
10. #Define the attribute names
11. names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
12. #Create pandas data frame by loading the data from URL
13. dataframe = pandas.read_csv(url, names=names
14. #Create array from data values
15. array = dataframe.values
16. #Split the data into input and target
17. X = array[:, 0:8]
18. Y = array[:,8]
19. #We will select the features using chi square
20. test = SelectKBest(score_func=chi2, k=4)
21. #Fit the function for ranking the features by score
22. fit = test.fit(X, Y)
23. #Summarize scores numpy.set_printoptions(precision=3) ``print(fit.scores_)
24. #Apply the transformation on to dataset
25. features = fit.transform(X)
26. #Summarize selected features print(features[0:5,:])

你可以看到每个参数的得分,以及所选择的四个参数(得分最高的):plas、test、mass和age。

每个特征的分数为:
1. [111.52 1411.887 17.605 53.108 2175.565 127.669 5.393
2. 181.304]

被选出的特征是:
1. [[148. 0. 33.6 50. ]
2. [85. 0. 26.6 31. ]
3. [183. 0. 23.3 32. ]
4. [89. 94. 28.1 21. ]
5. [137. 168. 43.1 33. ]]

递归特征消除(RFE)

RFE的工作方式是递归地删除参数并在保留的参数上构建模型。它使用模型精度来判断哪些属性(以及属性的组合)对预测目标参数贡献最大。你可以在scikit-learn的文档中了解更多关于RFE类的信息。

下面的示例使用RFE和logistic回归算法来选出前三个特征。算法的选择并不重要,只需要熟练并且一致:

1. #Import the required packages
2. #Import pandas to read csv import pandas
3. #Import numpy for array related operations import numpy
4. #Import sklearn's feature selection algorithm from ``sklearn.feature_selection import RFE
5. #Import LogisticRegression for performing chi square test ``from sklearn.linear_model import LogisticRegression
6. #URL for loading the dataset
7. url =
8. "https://archive.ics.uci.edu/ml/machine-learning-``databases/pima-indians-dia betes/pima-indians-diabetes.data"
9. #Define the attribute names
10. names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', ``'age', 'class']
11. #Create pandas data frame by loading the data from URL
12. dataframe = pandas.read_csv(url, names=names)
13.
14. #Create array from data values
15. array = dataframe.values
16.
17. #Split the data into input and target
18. X = array[:,:8]
19. Y = array[:,8]
20. #Feature extraction
21. model = LogisticRegression() rfe = RFE(model, 3)
22. fit = rfe.fit(X, Y)
23. print("Num Features: %d"% fit.n_features_) print("Selected ``Features: %s"% fit.support_)
24. print("Feature Ranking: %s"% fit.ranking_)

执行完上述代码后,我们可以得到:

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

你可以看到RFE选择了前三个特性,即preg、mass和pedi。这些在support_数组中被标记为True,在ranking_数组中被标记为首选(标记为1)。

主成分分析

PCA使用线性代数将数据集转换为压缩格式。通常,它被认为是一种数据约简技术。PCA的一个属性是,你可以选择转换结果中的维数或主成分的数量。

在接下来的例子中,我们使用PCA并选择了三个主成分:

1. #Import the required packages
2. #Import pandas to read csv import pandas
3. #Import numpy for array related operations import numpy
4. #Import sklearn's PCA algorithm
5. from sklearn.decomposition import PCA
6. #URL for loading the dataset
7. url =
8. "https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians diabetes/pima-indians-diabetes.data"
9. #Define the attribute names
10. names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
11. dataframe = pandas.read_csv(url, names=names)
12. #Create array from data values
13. array = dataframe.values
14. #Split the data into input and target
15. X = array[:,0:8]
16. Y = array[:,8]
17. #Feature extraction
18. pca = PCA(n_components=3) fit = pca.fit(X)
19. #Summarize components
20. print("Explained Variance: %s") % ``fit.explained_variance_ratio_
21. print(fit.components_)

你可以看到<u>,</u>转换后的数据集(三个主成分)与源数据几乎没有相似之处:

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

选择重要特征(特性重要度)

特征重要度是一种利用训练好的有监督分类器来选择特征的技术。当我们训练分类器(如决策树)时,我们计算每个参数以创建分割;我们可以使用这个度量作为特征选择器。让我们来详细了解一下。

随机森林由于其相对较好的准确性、鲁棒性和易用性而成为最受欢迎的机器学习方法之一。它们还提供了两种简单易行的特征选择方法——均值降低杂质和均值降低准确度。

随机森林由许多决策树组成。决策树中的每个节点都是一个基于单个特征的条件,其设计目的是将数据集分割成两个,以便相似的响应值最终出现在相同的集合中。选择(局部)最优条件的度量叫做杂质。对于分类问题,它通常是基尼杂质或信息增益/熵,而对于回归树,它是方差。因此,当训练一棵树时,可以通过每个特征减少的树中加权杂质的多少来计算。对于森林,可以对每个特征的杂质减少量进行平均,并根据该方法对特征进行排序。

让我们看一下如何使用随机森林分类器来进行特征选择,并评估特征选择前后分类器的准确性。我们将使用Otto数据集。该数据集可从kaggle免费获得(你需要注册kaggle才能下载该数据集)。你可以从https://www.kaggle.com/c/otto-group-product- classifics-challenge/data 下载训练集train.csv.zip,然后将解压缩的train.csv文件放在你的工作目录中。

这个数据集描述了超过61,000个产品的93个模糊细节,这些产品被分成10个产品类别(例如,时尚类、电子产品类等)。输入参数是某种类型的不同事件的计数。

训练目标是对新产品作为10个类别中每一个类别的概率数组做出预测,并使用多级对数损失(也称为交叉熵)对模型进行评估。

我们将从导入所有库开始:

1. #Import the supporting libraries
2. #Import pandas to load the dataset from csv file
3. from pandas import read_csv
4. #Import numpy for array based operations and calculations
5. import numpy as np
6. #Import Random Forest classifier class from sklearn
7. from sklearn.ensemble import RandomForestClassifier
8. #Import feature selector class select model of sklearn
9. from sklearn.feature_selection
10. import SelectFromModel
11. np.random.seed(1)

定义一个方法用于将我们的数据集分为训练数据和测试数据;我们将在训练数据部分对数据集进行训练,测试数据部分将用于训练模型的评估:

1. #Function to create Train and Test set from the original dataset
2. def getTrainTestData(dataset,split):
3. np.random.seed(0)
4. training = []
5. testing = []
6. np.random.shuffle(dataset) shape = np.shape(dataset)
7. trainlength = np.uint16(np.floor(split*shape[0]))
8. for i in range(trainlength):
9. training.append(dataset[i])
10. for i in range(trainlength,shape[0]):
11. testing.append(dataset[i])
12. training = np.array(training) testing = np.array(testing)
13. return training,testing

还需要添加一个函数来评估模型的准确性;以预测输出和实际输出为输入,计算准确率百分比:

1. #Function to evaluate model performance
2. def getAccuracy(pre,ytest):
3. count = 0
4. for i in range(len(ytest)):
5. if ytest[i]==pre[i]:
6. count+=1
7. acc = float(count)/len(ytest)
8. return acc

现在要导入数据集。我们将导入train.csv文件;该文件包含61,000多个训练实例。我们的示例将使用50000个实例,其中使用35,000个实例来训练分类器,并使用15,000个实例来测试分类器的性能:

1. #Load dataset as pandas data frame
2. data = read_csv('train.csv')
3. #Extract attribute names from the data frame
4. feat = data.keys()
5. feat_labels = feat.get_values()
6. #Extract data values from the data frame
7. dataset = data.values
8. #Shuffle the dataset
9. np.random.shuffle(dataset)
10. #We will select 50000 instances to train the classifier
11. inst = 50000
12.
13. #Extract 50000 instances from the dataset
14. dataset = dataset[0:inst,:]
15.
16. #Create Training and Testing data for performance evaluation
17. train,test = getTrainTestData(dataset, 0.7)
18.
19. #Split data into input and output variable with selected features
20. Xtrain = train[:,0:94] ytrain = train[:,94] shape = np.shape(Xtrain)
21.
22. print("Shape of the dataset ",shape)
23.
24. #Print the size of Data in MBs
25. print("Size of Data set before feature selection: %.2f MB"%(Xtrain.nbytes/1e6))
26.

注意下这里的数据大小;由于我们的数据集包含约35000个训练实例,带有94个参数;我们的数据集非常大。让我们来看一下:

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

如你所见,我们的数据集中有35000行和94列,数据大小超过26MB。

在下一个代码块中,我们将配置我们的随机森林分类器;我们会使用250棵树,最大深度为30,随机特征的数量为7。其他超参数将是sklearn的默认值:

1. #Lets select the test data for model evaluation purpose
2. Xtest = test[:,0:94] ytest = test[:,94]
3.
4. #Create a random forest classifier with the following Parameters
5. trees = 250
6. max_feat= 7
7. max_depth = 30
8. min_sample = 2
9. clf = RandomForestClassifier(n_estimators=trees, max_features=max_feat, max_depth=max_depth, min_samples_split= min_sample, random_state=0, n_jobs=-1)
10.
11. #Train the classifier and calculate the training time
12. import time
13. start = time.time()
14. clf.fit(Xtrain, ytrain)
15. end = time.time()
16.
17. #Lets Note down the model training time
18. print("Execution time for building the Tree is: %f"%(float(end)- float(start)))
19. pre = clf.predict(Xtest)
20.
21. #Let's see how much time is required to train the model on the training dataset:
22. Execution time for building the Tree is: 2.913641
23.
24. #Evaluate the model performance for the test data
25. acc = getAccuracy(pre, ytest)
26.
27. print("Accuracy of model before feature selection is %.2f"%(100*acc))

模型的精确度是:

1. Accuracy of model before feature selection is 98.82

正如所看到的,我们获得了非常好的精确度,因为我们将几乎99%的测试数据分类为正确的类别。这意味着我们在15,000个实例中对大概14,823个实例进行了正确的分类。

所以,现在问题是:我们应该进一步改进吗?好吧,为什么不呢?如果可能的话,我们一定需要进行更多的改进;在这里,我们将使用特征重要度来选择特征。如你所知,在树的建造过程中,我们使用杂质度量来选择节点。选择杂质最少的参数值作为树中的节点。我们可以使用类似的标准来选择特征。我们可以给杂质更少的特征更多的重要度,这可以使用sklearn库的feature_importances_函数来实现。让我们来看一下每个特征的重要度:

1. #Once we have trained the model we will rank all the features for feature in zip(feat_labels, clf.feature_importances_):
2. print(feature)
3. ('id', 0.33346650420175183)
4. ('feat_1', 0.0036186958628801214)
5. ('feat_2', 0.0037243050888530957)
6. ('feat_3', 0.011579217472062748)
7. ('feat_4', 0.010297382675187445)
8. ('feat_5', 0.0010359139416194116)
9. ('feat_6', 0.00038171336038056165)
10. ('feat_7', 0.0024867672489765021)
11. ('feat_8', 0.0096689721610546085)
12. ('feat_9', 0.007906150362995093)
13. ('feat_10', 0.0022342480802130366)
14.

正如你看到的,每个特征都有不同的重要度,这取决于它对最终预测的贡献值。

我们将使用这些重要度评分来对我们的特征进行排序;在接下来的部分中,我们将选取特征重要度大于0.01的特征进行模型训练:

1. #Select features which have higher contribution in the final prediction
2. sfm = SelectFromModel(clf, threshold=0.01)
3. sfm.fit(Xtrain,ytrain)
4.

这里,我们将根据所选的特征参数转换输入的数据集。在下一个代码块中,我们会转换数据集。然后,我们将检查新数据集的大小和形状:

1. #Transform input dataset
2. Xtrain_1 = sfm.transform(Xtrain)
3. Xtest_1 = sfm.transform(Xtest)
4.
5. #Let's see the size and shape of new dataset
6. print("Size of Data set before feature selection: %.2f MB"%(Xtrain_1.nbytes/1e6))
7. shape = np.shape(Xtrain_1)
8. print("Shape of the dataset ",shape)
9.
10. Size of Data set before feature selection: 5.60 MB
11. Shape of the dataset (35000, 20)
12.

看到数据集的形状了吗?经过特征选择后,我们只剩下20个特征,这使得数据库的大小从26MB减少到了5.60 MB,比原来的数据集减少了80%左右。

在下一个代码块中,我们将使用与前面相同的超参数训练一个新的随机森林分类器,并在测试集上进行了测试。我们来看看修改训练集后得到的精确度是多少:

1. #Model training time
2. start = time.time() clf.fit(Xtrain_1, ytrain) end = time.time()
3. print("Execution time for building the Tree is: %f"%(float(end)- float(start)))
4.
5. #Let's evaluate the model on test data
6. pre = clf.predict(Xtest_1) count = 0
7. acc2 = getAccuracy(pre, ytest)
8. print("Accuracy after feature selection %.2f"%(100*acc2))
9.
10. Execution time for building the Tree is: 1.711518
11. Accuracy after feature selection 99.97
12.

使用修改后的数据集,我们获得了99.97%的准确率,这意味着我们把14,996个实例分到了正确的类别,而之前我们只正确地分类了14,823个实例。

这是我们在特征选择过程中取得的巨大进步;我们可以将所有的结果总结如下表:

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

上表显示了特征选择的实际优势。可以看到我们显著地减少了特征的数量,也就减少了模型的复杂性和数据集的维度。在减小维度后,训练时间显著缩短,最终我们克服了过拟合的问题,获得了比以前更高的精确度。

本文我们共探讨了机器学习中特征选择的4种方法。

如果你发现这篇文章很有用,可以阅读《集成机器学习》一书,了解关于叠加泛化和其他技术的更多信息。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容