【譯文】Python實現(xiàn)機器學(xué)習(xí)特征選擇的4種方法

原文標(biāo)題: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

注:
本文節(jié)選自Ankit Dixit所著的《集成機器學(xué)習(xí)》(Ensemble Machine Learning)一書。這本書組合強大的機器學(xué)習(xí)算法來建立優(yōu)化模型,可以作為初學(xué)者的指南。

我們將研究從數(shù)據(jù)集中選擇特征的不同方法;同時通過使用Python中Scikit-learn (sklearn) 庫的實現(xiàn)討論特征選擇算法的類型:

1.單變量選擇
2.遞歸特征消除(RFE)
3.主成分分析(PCA)
4.選擇重要特征(特征重要度)

本文簡要介紹了前三種算法及其實現(xiàn),然后詳細(xì)討論了在數(shù)據(jù)科學(xué)社區(qū)中廣泛使用的選擇重要特征(特性重要度)部分的內(nèi)容。

單變量選擇

統(tǒng)計測試可用于選擇那些與輸出變量關(guān)系最強的特征。

scikit-learn庫提供了SelectKBest類,它可以與一組不同的統(tǒng)計測試一起使用,以選擇特定數(shù)量的特征。

下面的例子使用chi2非負(fù)性特征的統(tǒng)計測試,從皮馬印第安人糖尿病發(fā)病數(shù)據(jù)集中選擇了四個最好的特征:

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,:])

你可以看到每個參數(shù)的得分,以及所選擇的四個參數(shù)(得分最高的):plas、test、mass和age。

每個特征的分?jǐn)?shù)為:
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的工作方式是遞歸地刪除參數(shù)并在保留的參數(shù)上構(gòu)建模型。它使用模型精度來判斷哪些屬性(以及屬性的組合)對預(yù)測目標(biāo)參數(shù)貢獻(xiàn)最大。你可以在scikit-learn的文檔中了解更多關(guān)于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_)

執(zhí)行完上述代碼后,我們可以得到:

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_數(shù)組中被標(biāo)記為True,在ranking_數(shù)組中被標(biāo)記為首選(標(biāo)記為1)。

主成分分析

PCA使用線性代數(shù)將數(shù)據(jù)集轉(zhuǎn)換為壓縮格式。通常,它被認(rèn)為是一種數(shù)據(jù)約簡技術(shù)。PCA的一個屬性是,你可以選擇轉(zhuǎn)換結(jié)果中的維數(shù)或主成分的數(shù)量。

在接下來的例子中,我們使用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>轉(zhuǎn)換后的數(shù)據(jù)集(三個主成分)與源數(shù)據(jù)幾乎沒有相似之處:

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]]

選擇重要特征(特性重要度)

特征重要度是一種利用訓(xùn)練好的有監(jiān)督分類器來選擇特征的技術(shù)。當(dāng)我們訓(xùn)練分類器(如決策樹)時,我們計算每個參數(shù)以創(chuàng)建分割;我們可以使用這個度量作為特征選擇器。讓我們來詳細(xì)了解一下。

隨機森林由于其相對較好的準(zhǔn)確性、魯棒性和易用性而成為最受歡迎的機器學(xué)習(xí)方法之一。它們還提供了兩種簡單易行的特征選擇方法——均值降低雜質(zhì)和均值降低準(zhǔn)確度。

隨機森林由許多決策樹組成。決策樹中的每個節(jié)點都是一個基于單個特征的條件,其設(shè)計目的是將數(shù)據(jù)集分割成兩個,以便相似的響應(yīng)值最終出現(xiàn)在相同的集合中。選擇(局部)最優(yōu)條件的度量叫做雜質(zhì)。對于分類問題,它通常是基尼雜質(zhì)或信息增益/熵,而對于回歸樹,它是方差。因此,當(dāng)訓(xùn)練一棵樹時,可以通過每個特征減少的樹中加權(quán)雜質(zhì)的多少來計算。對于森林,可以對每個特征的雜質(zhì)減少量進(jìn)行平均,并根據(jù)該方法對特征進(jìn)行排序。

讓我們看一下如何使用隨機森林分類器來進(jìn)行特征選擇,并評估特征選擇前后分類器的準(zhǔn)確性。我們將使用Otto數(shù)據(jù)集。該數(shù)據(jù)集可從kaggle免費獲得(你需要注冊kaggle才能下載該數(shù)據(jù)集)。你可以從https://www.kaggle.com/c/otto-group-product- classifics-challenge/data 下載訓(xùn)練集train.csv.zip,然后將解壓縮的train.csv文件放在你的工作目錄中。

這個數(shù)據(jù)集描述了超過61,000個產(chǎn)品的93個模糊細(xì)節(jié),這些產(chǎn)品被分成10個產(chǎn)品類別(例如,時尚類、電子產(chǎn)品類等)。輸入?yún)?shù)是某種類型的不同事件的計數(shù)。

訓(xùn)練目標(biāo)是對新產(chǎn)品作為10個類別中每一個類別的概率數(shù)組做出預(yù)測,并使用多級對數(shù)損失(也稱為交叉熵)對模型進(jìn)行評估。

我們將從導(dǎo)入所有庫開始:

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)

定義一個方法用于將我們的數(shù)據(jù)集分為訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù);我們將在訓(xùn)練數(shù)據(jù)部分對數(shù)據(jù)集進(jìn)行訓(xùn)練,測試數(shù)據(jù)部分將用于訓(xùn)練模型的評估:

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

還需要添加一個函數(shù)來評估模型的準(zhǔn)確性;以預(yù)測輸出和實際輸出為輸入,計算準(zhǔn)確率百分比:

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

現(xiàn)在要導(dǎo)入數(shù)據(jù)集。我們將導(dǎo)入train.csv文件;該文件包含61,000多個訓(xùn)練實例。我們的示例將使用50000個實例,其中使用35,000個實例來訓(xùn)練分類器,并使用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.

注意下這里的數(shù)據(jù)大小;由于我們的數(shù)據(jù)集包含約35000個訓(xùn)練實例,帶有94個參數(shù);我們的數(shù)據(jù)集非常大。讓我們來看一下:

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

如你所見,我們的數(shù)據(jù)集中有35000行和94列,數(shù)據(jù)大小超過26MB。

在下一個代碼塊中,我們將配置我們的隨機森林分類器;我們會使用250棵樹,最大深度為30,隨機特征的數(shù)量為7。其他超參數(shù)將是sklearn的默認(rèn)值:

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%的測試數(shù)據(jù)分類為正確的類別。這意味著我們在15,000個實例中對大概14,823個實例進(jìn)行了正確的分類。

所以,現(xiàn)在問題是:我們應(yīng)該進(jìn)一步改進(jìn)嗎?好吧,為什么不呢?如果可能的話,我們一定需要進(jìn)行更多的改進(jìn);在這里,我們將使用特征重要度來選擇特征。如你所知,在樹的建造過程中,我們使用雜質(zhì)度量來選擇節(jié)點。選擇雜質(zhì)最少的參數(shù)值作為樹中的節(jié)點。我們可以使用類似的標(biāo)準(zhǔn)來選擇特征。我們可以給雜質(zhì)更少的特征更多的重要度,這可以使用sklearn庫的feature_importances_函數(shù)來實現(xiàn)。讓我們來看一下每個特征的重要度:

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.

正如你看到的,每個特征都有不同的重要度,這取決于它對最終預(yù)測的貢獻(xiàn)值。

我們將使用這些重要度評分來對我們的特征進(jìn)行排序;在接下來的部分中,我們將選取特征重要度大于0.01的特征進(jìn)行模型訓(xùn)練:

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

這里,我們將根據(jù)所選的特征參數(shù)轉(zhuǎn)換輸入的數(shù)據(jù)集。在下一個代碼塊中,我們會轉(zhuǎn)換數(shù)據(jù)集。然后,我們將檢查新數(shù)據(jù)集的大小和形狀:

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.

看到數(shù)據(jù)集的形狀了嗎?經(jīng)過特征選擇后,我們只剩下20個特征,這使得數(shù)據(jù)庫的大小從26MB減少到了5.60 MB,比原來的數(shù)據(jù)集減少了80%左右。

在下一個代碼塊中,我們將使用與前面相同的超參數(shù)訓(xùn)練一個新的隨機森林分類器,并在測試集上進(jìn)行了測試。我們來看看修改訓(xùn)練集后得到的精確度是多少:

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.

使用修改后的數(shù)據(jù)集,我們獲得了99.97%的準(zhǔn)確率,這意味著我們把14,996個實例分到了正確的類別,而之前我們只正確地分類了14,823個實例。

這是我們在特征選擇過程中取得的巨大進(jìn)步;我們可以將所有的結(jié)果總結(jié)如下表:

評估標(biāo)準(zhǔn) 特征選擇前 特征選擇后
特征數(shù)量 94 20
數(shù)據(jù)集大小 26.32MB 5.60MB
訓(xùn)練時間 2.91 s 1.71 s
精確度 98.82% 99.97%

上表顯示了特征選擇的實際優(yōu)勢??梢钥吹轿覀冿@著地減少了特征的數(shù)量,也就減少了模型的復(fù)雜性和數(shù)據(jù)集的維度。在減小維度后,訓(xùn)練時間顯著縮短,最終我們克服了過擬合的問題,獲得了比以前更高的精確度。

本文我們共探討了機器學(xué)習(xí)中特征選擇的4種方法。

如果你發(fā)現(xiàn)這篇文章很有用,可以閱讀《集成機器學(xué)習(xí)》一書,了解關(guān)于疊加泛化和其他技術(shù)的更多信息。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容