特征選擇是識別和選擇與目標變量最相關的輸入變量子集的過程。
特征選擇最簡單的情況可能是存在數字輸入變量和用于回歸預測建模的數字目標的情況。這是因為可以計算出每個輸入變量與目標之間的關系強度,稱為相關性,并進行相對比較。
本文中我們將展示如何使用數值輸入數據執行特征選擇以進行回歸預測建模。
- 使用相關性和互信息統計來評估數字輸入數據的重要性。
- 在擬合和評估回歸模型時如何為數字輸入數據執行特征選擇。
- 使用網格搜索調整在建模管道中選擇的特征數量。
本文分為四部分:
- 1、回歸數據集
- 2、數值特征選擇
- 2.1、相關特征選擇
- 2.2、相關信息特征選擇
- 3、使用選定特征建模
- 3.1、使用所有特征構建的模型
- 3.2、使用相關特征構建的模型
- 3.3、使用相關信息特征構建的模型
- 4、調整所選特征的數量
一、回歸數據集
我們將使用綜合回歸數據集作為本文的基礎。
回歸問題是我們要預測數值的問題。在這種情況下,我們需要一個具有數字輸入變量的數據集。
scikit-learn庫中的make_regression()函數可用于定義數據集。它提供了對樣本數量,輸入特征數量以及重要的是相關和冗余輸入特征數量的控制。這一點至關重要,因為我們特別希望我們知道的數據集具有一些冗余輸入特征。
在這種情況下,我們將定義一個包含1000個樣本的數據集,每個樣本具有100個輸入特征,其中10個是信息性的,其余90個是冗余的。
# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
希望特征選擇技術可以識別與目標相關的那些特征中的一些或全部,或者至少識別并除去某些冗余輸入特征。
定義后,我們可以將數據分為訓練集和測試集,以便我們擬合和評估學習模型。
我們將使用scikit-learn形式的train_test_split()函數,并將67%的數據用于訓練,并將33%的數據用于測試。
...
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
1
2
3
...
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
將這些特征結合在一起,下面列出了定義,拆分和匯總原始回歸數據集的完整示例。
# load and summarize the dataset
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# summarize
print('Train', X_train.shape, y_train.shape)
print('Test', X_test.shape, y_test.shape)
運行示例將報告訓練和測試集的輸入和輸出特征的大小。
我們可以看到,我們有670個訓練示例和330個測試示例。
現在,我們已經加載并準備了數據集,我們可以探索特征選擇。
二、數值特征選擇
有兩種流行的特征選擇技術,可用于數字輸入數據和數字目標變量。
他們是:
- 相關統計。
- 相互信息統計。
(一)相關特征選擇
相關性是兩個變量如何一起變化的度量。也許最常見的相關度量是Pearson相關,它假設每個變量的高斯分布并報告它們的線性關系。
對于數字預測變量,量化與結果之間的每個關系的經典方法是使用樣本相關性統計量。
線性相關分數通常是介于-1和1之間的值,0表示沒有關系。對于特征選擇,我們通常對正值感興趣,正值越大,關系越大,并且應該更可能選擇特征進行建模。這樣,線性相關可以轉換為僅具有正值的相關統計量。
scikit-learn庫在f_regression()函數中提供了相關統計的實現。此函數可用于特征選擇策略中,例如通過SelectKBest類選擇前k個最相關的特征(最大值)。
例如,我們可以定義SelectKBest類以使用f_regression()函數并選擇所有特征,然后轉換訓練和測試集。
# configure to select all features
fs = SelectKBest(score_func=f_regression, k='all')
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
然后,我們可以輸出每個變量的分數(越大越好),并將每個變量的分數繪制為條形圖,以了解應該選擇多少個特征。
for i in range(len(fs.scores_)):
print('Feature %d: %f' % (i, fs.scores_[i]))
# plot the scores
pyplot.bar([i for i in range(len(fs.scores_))], fs.scores_)
pyplot.show()
將其與上一節中數據集的數據準備一起進行綁定,下面列出了完整的示例。
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_regression
from matplotlib import pyplot
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select all features
fs = SelectKBest(score_func=f_regression, k='all')
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
# load the dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# feature selection
X_train_fs, X_test_fs, fs = select_features(X_train, y_train, X_test)
# what are scores for the features
for i in range(len(fs.scores_)):
print('Feature %d: %f' % (i, fs.scores_[i]))
# plot the scores
pyplot.bar([i for i in range(len(fs.scores_))], fs.scores_)
pyplot.show()
首先運行示例將輸出為每個輸入特征和目標變量計算的分數。
請注意,您的特定結果可能會有所不同。嘗試運行該示例幾次。
我們可以看到,某些變量的分數高于其他變量,而其他變量的分數則大得多,例如Feature 9的分數為101。
為每個輸入特征創建一個特征重要性評分的條形圖。
該圖清楚地表明8至10個特征比其他重要得多。
在配置SelectKBest時,我們可以設置k=10來選擇這些最重要的特征。
輸入特征(x)與關聯特征重要性(y)的條形圖
(二)相關信息特征選擇
來自信息理論領域的相關信息是信息增益(通常用于決策樹的構建)在特征選擇中的應用。
在兩個變量之間計算相關信息,并在給定另一個變量的已知值的情況下測量一個變量的不確定性降低。
考慮兩個離散(分類或有序)變量(例如分類輸入和分類輸出數據)的分布時,相關信息很簡單。盡管如此,它仍可適用于數字輸入和輸出變量。
scikit-learn庫中的common_info_regression()函數通過數字輸入和輸出變量提供了用于信息選擇的相關信息實現。
與f_regression()一樣,它可以用于SelectKBest特征選擇策略(和其他策略)中。
# configure to select all features
fs = SelectKBest(score_func=mutual_info_regression, k='all')
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
我們可以使用數據集上的相關信息來執行特征選擇。
下面列出了使用相關信息進行數字特征選擇的完整示例。
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_regression
from matplotlib import pyplot
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select all features
fs = SelectKBest(score_func=mutual_info_regression, k='all')
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
# load the dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# feature selection
X_train_fs, X_test_fs, fs = select_features(X_train, y_train, X_test)
# what are scores for the features
for i in range(len(fs.scores_)):
print('Feature %d: %f' % (i, fs.scores_[i]))
# plot the scores
pyplot.bar([i for i in range(len(fs.scores_))], fs.scores_)
pyplot.show()
首先運行示例將輸出為每個輸入特征和目標變量計算的分數。
請注意,您的特定結果可能會有所不同。
我們可以看到許多特征的分數為0.0,而這已經確定了許多可能與目標有關的特征。
為每個輸入特征創建一個特征重要性評分的條形圖。
與相關特征選擇方法相比,我們可以清楚地看到更多的特征被標記為相關。這可能是由于我們在其構造中添加到數據集中的統計噪聲。
輸入特征(x)與相關信息特征重要性(y)的條形圖
既然我們知道如何針對回歸預測建模問題對數字輸入數據執行特征選擇,那么我們可以嘗試使用選定的特征開發模型并比較結果。
三、使用選定特征建模
有許多不同的技術可用來對特征評分和根據分數選擇特征。您怎么知道要使用哪個?
一種可靠的方法是使用不同的特征選擇方法(和特征數量)評估模型,然后選擇能夠產生最佳性能的模型的方法。
在本節中,我們將評估具有所有特征的線性回歸模型,并將其與根據相關統計選擇的特征和通過互信息選擇的特征構建的模型進行比較。
線性回歸是測試特征選擇方法的良好模型,因為如果從模型中刪除了不相關的特征,則線性回歸性能會更好。
(一)使用所有特征構建的模型
第一步,我們將使用所有可用特征來評估LinearRegression模型。
該模型適合訓練數據集,并在測試數據集上進行評估。
下面列出了完整的示例。
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
# load the dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# fit the model
model = LinearRegression()
model.fit(X_train, y_train)
# evaluate the model
yhat = model.predict(X_test)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)
運行示例將在訓練數據集上輸出模型的平均絕對誤差(MAE)。
由于學習算法的隨機性,結果可能會有所不同。
在這種情況下,我們可以看到該模型實現了約0.086的誤差。
(二)使用相關特征構建的模型
我們可以使用相關方法對特征進行評分,然后選擇10個最相關的特征。
下面的select_features()函數已更新以實現此目的。
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select a subset of features
fs = SelectKBest(score_func=f_regression, k=10)
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
下面列出了使用此特征選擇方法評估線性回歸模型擬合和對數據進行評估的完整示例。
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_regression
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select a subset of features
fs = SelectKBest(score_func=f_regression, k=10)
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
# load the dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# feature selection
X_train_fs, X_test_fs, fs = select_features(X_train, y_train, X_test)
# fit the model
model = LinearRegression()
model.fit(X_train_fs, y_train)
# evaluate the model
yhat = model.predict(X_test_fs)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)
該示例僅報告了使用相關統計數據選擇的100個輸入特征中的10個的模型性能。
在這種情況下,我們看到該模型實現了約2.7的誤差分,這比使用所有特征并獲得0.086的MAE的基線模型要大得多。
這表明,盡管該方法對選擇哪些特征有很強的想法,但是僅從這些特征構建模型并不能帶來更熟練的模型。這可能是因為對目標很重要的特征被忽略了。
讓我們采用另一種方法,嘗試使用該方法刪除一些冗余特征,而不是所有冗余特征。
為此,我們可以將所選特征的數量設置為一個更大的值(在本例中為88),希望它可以找到并丟棄90個冗余特征中的12個。
下面列出了完整的示例。
該示例報告了使用相關統計量選擇的100個輸入特征中的88個的模型性能。
在本例中,我們可以看到,刪除一些冗余特征使性能有了小幅提升,誤差約為0.085,而基線的誤差約為0.086。
(三)使用相關信息特征構建的模型
下面列出了實現此目的的select_features()函數的更新版本。
def select_features(X_train, y_train, X_test):
# configure to select a subset of features
fs = SelectKBest(score_func=mutual_info_regression, k=88)
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
下面列出了使用相關信息進行特征選擇以擬合線性回歸模型的完整示例。
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_regression
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select a subset of features
fs = SelectKBest(score_func=mutual_info_regression, k=88)
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
# load the dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# feature selection
X_train_fs, X_test_fs, fs = select_features(X_train, y_train, X_test)
# fit the model
model = LinearRegression()
model.fit(X_train_fs, y_train)
# evaluate the model
yhat = model.predict(X_test_fs)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)
運行這個例子符合該模型在前88個選擇使用相關信息特征選擇。
在這種情況下,我們可以看到與相關統計量相比誤差的進一步減少,在這種情況下,相對于上一節的0.085,MAE達到了大約0.084。
四、調整所選特征的數量
在上一個示例中,我們選擇了88個特征,但是如何知道要選擇的特征數量是否是最佳。
無需猜測,我們可以系統地測試一系列不同數量的所選特征,并發現哪種結果會產生最佳性能的模型。這稱為網格搜索,其中可以調整SelectKBest類的k參數。
使用重復分層k-fold cross-validation來評估回歸任務上的模型配置是一種好習慣。我們將通過RepeatedKFold類使用三個重復的10倍交叉驗證。
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
我們可以定義一條通道,以正確準備訓練集上的特征選擇變換,并將其應用于交叉驗證的每一折的訓練集和測試集。
在這種情況下,我們將使用相關信息統計方法來選擇特征。
# define the pipeline to evaluate
model = LinearRegression()
fs = SelectKBest(score_func=mutual_info_regression)
pipeline = Pipeline(steps=[('sel',fs), ('lr', model)])
然后,我們可以定義值的網格以評估為80到100。
請注意,網格是要搜索的參數到值的字典映射,并且假設我們使用的是Pipeline,則可以通過給我們提供的名稱“ sel ”和參數名稱“ k ” 來訪問SelectKBest對象。兩個下劃線或“ sel__k ”。
# define the grid
grid = dict()
grid['sel__k'] = [i for i in range(X.shape[1]-20, X.shape[1]+1)]
然后,我們可以定義并運行搜索。
在這種情況下,我們將使用負平均絕對誤差(neg_mean_absolute_error)評估模型。它是負數,因為scikit-learn需要使分數最大化,因此MAE變為負數,這意味著分數從-infinity到0(最佳)。
# define the grid search
search = GridSearchCV(pipeline, grid, scoring='neg_mean_absolure_error', n_jobs=-1, cv=cv)
# perform the search
results = search.fit(X, y)
下面列出了完整的示例
from sklearn.datasets import make_regression
from sklearn.model_selection import RepeatedKFold
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_regression
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
# define dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# define the evaluation method
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
# define the pipeline to evaluate
model = LinearRegression()
fs = SelectKBest(score_func=mutual_info_regression)
pipeline = Pipeline(steps=[('sel',fs), ('lr', model)])
# define the grid
grid = dict()
grid['sel__k'] = [i for i in range(X.shape[1]-20, X.shape[1]+1)]
# define the grid search
search = GridSearchCV(pipeline, grid, scoring='neg_mean_squared_error', n_jobs=-1, cv=cv)
# perform the search
results = search.fit(X, y)
# summarize best
print('Best MAE: %.3f' % results.best_score_)
print('Best Config: %s' % results.best_params_)
# summarize all
means = results.cv_results_['mean_test_score']
params = results.cv_results_['params']
for mean, param in zip(means, params):
print(">%.3f with: %r" % (mean, param))
運行示例選擇不同數量的網格搜索功能使用相關信息統計,其中每個建模評估通道使用重復交叉驗證。
在這種情況下,我們可以看到,選擇的特征的最佳數量是81,這使得MAE達到大約0.082(忽略符號)。
鑒于學習算法和評估程序的隨機性,您的具體結果可能會有所不同。嘗試運行該示例幾次。
我們可能希望查看所選特征的數量與MAE之間的關系。在這種關系中,我們可以預期到更多的特征會帶來更好的性能。
通過手動評估SelectKBest從81到100 的k的每個配置,收集MAE分數樣本,并使用箱型圖和須狀圖并排繪制結果來探索結果。這些箱形圖的分布和均值將顯示所選特征的數量與管道的MAE之間任何有趣的關系。
請注意,由于k = 80的MAE分數的分布遠大于所考慮的k的所有其他值,因此我們從81而不是80開始了k值的傳播。
下面列出了實現此目的的完整示例。
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_regression
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# define dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# define number of features to evaluate
num_features = [i for i in range(X.shape[1]-19, X.shape[1]+1)]
# enumerate each number of features
results = list()
for k in num_features:
# create pipeline
model = LinearRegression()
fs = SelectKBest(score_func=mutual_info_regression, k=k)
pipeline = Pipeline(steps=[('sel',fs), ('lr', model)])
# evaluate the model
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
scores = cross_val_score(pipeline, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1)
results.Append(scores)
# summarize the results
print('>%d %.3f (%.3f)' % (k, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=num_features, showmeans=True)
pyplot.show()
運行這個示例,顯示了每個選定特征數量的平均值和標準差MAE。
在這種情況下,報告MAE的均值和標準差不是很有趣,除了80的k值比90的k值更好。
并排創建了箱形圖和須狀圖,顯示了k與MAE 的趨勢,其中綠色三角形代表平均值,橙色線代表分布的中值。
總結
在本文中,您發現了如何使用數字輸入數據執行特征選擇以進行回歸預測建模。
- 如何使用相關性和相關信息統計來評估數字輸入數據的重要性。
- 在擬合和評估回歸模型時如何為數字輸入數據執行特征選擇。
- 如何使用網格搜索調整在建模通道中選擇的特征數量。