1 特征選擇的目的
機器學習中特征選擇是一個重要步驟,以篩選出顯著特征、摒棄非顯著特征。這樣做的作用是:
減少特征(避免維度災難),提高訓練速度,降低運算開銷;
減少干擾噪聲,降低過擬合風險,提升模型效果;
更少的特征,模型可解釋性更好。
2 特征選擇方法
特征選擇方法一般分為三類:
2.1 過濾法--特征選擇
通過計算特征的缺失率、發散性、相關性、信息量、穩定性等指標對各個特征進行評估選擇,常用如缺失情況、單值率、方差驗證、pearson相關系數、chi2卡方檢驗、IV值、信息增益及PSI等方法。
2.1.1 缺失率
通過分析各特征缺失率,并設定閾值對特征進行篩選。閾值可以憑經驗值(如缺失率《0.9)或可觀察樣本各特征整體分布,確定特征分布的異常值作為閾值。
特征缺失率
miss_rate_df = df.isnull().sum().sort_values(ascending=False) / df.shape[0]
2.1.2 發散性
特征無發散性意味著該特征值基本一樣,無區分能力。通過分析特征單個值的最大占比及方差以評估特征發散性情況,并設定閾值對特征進行篩選。閾值可以憑經驗值(如單值率《0.9, 方差》0.001)或可觀察樣本各特征整體分布,以特征分布的異常值作為閾值。
分析方差
var_features = df.var().sort_values()
特征單值率
sigle_rate = {}
for var in df.columns:
sigle_rate[var]=(df[var].value_counts().max()/df.shape[0])
2.1.2 相關性
特征間相關性高會浪費計算資源,影響模型的解釋性。特別對線性模型來說,會導致擬合模型參數的不穩定。常用的分析特征相關性方法如:
方差膨脹因子VIF:
方差膨脹因子也稱為方差膨脹系數(Variance Inflation),用于計算數值特征間的共線性,一般當VIF大于10表示有較高共線性。
from statsmodels.stats.outliers_influence import variance_inflation_factor
截距項
df[‘c’] = 1
name = df.columns
x = np.matrix(df)
VIF_list = [variance_inflation_factor(x,i) for i in range(x.shape[1])]
VIF = pd.DataFrame({‘feature’:name,“VIF”:VIF_list})
person相關系數:
用于計算數值特征兩兩間的相關性,數值范圍[-1,1]。
import seaborn as sns
corr_df=df.corr()
熱力圖
sns.heatmap(corr_df)
剔除相關性系數高于threshold的corr_drop
threshold = 0.9
upper = corr_df.where(np.triu(np.ones(corr_df.shape), k=1).astype(np.bool))
corr_drop = [column for column in upper.columns if any(upper[column].abs() 》 threshold)]
Chi2檢驗
經典的卡方檢驗是檢驗類別型變量對類別型變量的相關性。Sklearn的實現是通過矩陣相乘快速得出所有特征的觀測值和期望值,在計算出各特征的 χ2 值后排序進行選擇。在擴大了 chi2 的在連續型變量適用范圍的同時,也方便了特征選擇。
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
x, y = load_iris(return_X_y=True)
x_new = SelectKBest(chi2, k=2).fit_transform(x, y)
2.1.3 信息量
分類任務中,可以通過計算某個特征對于分類這樣的事件到底有多大信息量貢獻,然后特征選擇信息量貢獻大的特征。常用的方法有計算IV值、信息增益。
信息增益
如目標變量D的信息熵為 H(D),而D在特征A條件下的條件熵為 H(D|A),那么信息增益 G(D , A) 為:
信息增益(互信息)的大小即代表特征A的信息貢獻程度。
from sklearn.feature_selection import mutual_info_classif
from sklearn.datasets import load_iris
x, y = load_iris(return_X_y=True)
mutual_info_classif(x,y)
IV
IV值(Information Value),在風控領域是一個重要的信息量指標,衡量了某個特征(連續型變量需要先離散化)對目標變量的影響程度。其基本思想是根據該特征所命中黑白樣本的比率與總黑白樣本的比率,來對比和計算其關聯程度。【Github代碼鏈接】
2.1.4 穩定性
對大部分數據挖掘場景,特別是風控領域,很關注特征分布的穩定性,其直接影響到模型使用周期的穩定性。常用的是PSI(Population Stability Index,群體穩定性指標)。
PSI
PSI表示的是實際與預期分布的差異,SUM( (實際占比 - 預期占比)* ln(實際占比 / 預期占比) )。
在建模時通常以訓練樣本(In the Sample, INS)作為預期分布,而驗證樣本作為實際分布。驗證樣本一般包括樣本外(Out of Sample,OOS)和跨時間樣本(Out of Time,OOT)【Github代碼鏈接】
2.2 嵌入法--特征選擇
嵌入法是直接使用模型訓練得到特征重要性,在模型訓練同時進行特征選擇。通過模型得到各個特征的權值系數,根據權值系數從大到小來選擇特征。常用如基于L1正則項的邏輯回歸、Lighgbm特征重要性選擇特征。
基于L1正則項的邏輯回歸
L1正則方法具有稀疏解的特性,直觀從二維解空間來看L1-ball 為正方形,在頂點處時(如W2=C, W1=0的稀疏解),更容易達到最優解。可見基于L1正則方法的會趨向于產生少量的特征,而其他的特征都為0。
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
x_new = SelectFromModel(LogisticRegression(penalty=“l1”, C=0.1)).fit_transform(x, y)
基于樹模型的特征排序
基于決策樹的樹模型(隨機森林,Lightgbm,Xgboost等),樹生長過程中也是啟發式搜索特征子集的過程,可以直接用訓練后模型來輸出特征重要性。
import matplotlib.pyplot as plt
from lightgbm import plot_importance
from lightgbm import LGBMClassifier
model = LGBMClassifier()
model.fit(x, y)
plot_importance(model, max_num_features=20, figsize=(10,5),importance_type=‘split’)
plt.show()
feature_importance = pd.DataFrame({
‘feature’: model.booster_.feature_name(),
‘gain’: model.booster_.feature_importance(‘gain’),
‘split’: model.booster_.feature_importance(‘split’)
}).sort_values(‘gain’,ascending=False)
當特征數量多時,對于輸出的特征重要性,通常可以按照重要性的拐點劃定下閾值選擇特征。
2.3 包裝法--特征選擇
包裝法是通過每次選擇部分特征迭代訓練模型,根據模型預測效果評分選擇特征的去留。一般包括產生過程,評價函數,停止準則,驗證過程,這4個部分。
(1) 產生過程( Generation Procedure )是搜索特征子集的過程,首先從特征全集中產生出一個特征子集。搜索方式有完全搜索(如廣度優先搜索、定向搜索)、啟發式搜索(如雙向搜索、后向選擇)、隨機搜索(如隨機子集選擇、模擬退火、遺傳算法)。(2) 評價函數( Evaluation Function ) 是評價一個特征子集好壞程度的一個準則。(3) 停止準則( Stopping Criterion )停止準則是與評價函數相關的,一般是一個閾值,當評價函數值達到這個閾值后就可停止搜索。(4) 驗證過程( Validation Procedure )是在驗證數據集上驗證選出來的特征子集的實際效果。
首先從特征全集中產生出一個特征子集,然后用評價函數對該特征子集進行評價,評價的結果與停止準則進行比較,若評價結果比停止準則好就停止,否則就繼續產生下一組特征子集,繼續進行特征選擇。最后選出來的特征子集一般還要驗證其實際效果。
RFE
RFE遞歸特征消除是常見的特征選擇方法。原理是遞歸地在剩余的特征上構建模型,使用模型判斷各特征的貢獻并排序后做特征選擇。
from sklearn.feature_selection import RFE
rfe = RFE(estimator,n_features_to_select,step)
rfe = rfe.fit(x, y)
print(rfe.support_)
print(rfe.ranking_)
雙向搜索特征選擇
鑒于RFE僅是后向迭代的方法,容易陷入局部最優,而且不支持Lightgbm等模型自動處理缺失值/類別型特征,便基于啟發式雙向搜索及模擬退火算法思想,簡單碼了一個特征選擇的方法【Github代碼鏈接】,如下代碼:
“”“
Author: 公眾號-算法進階
基于啟發式雙向搜索及模擬退火的特征選擇方法。
”“”
import pandas as pd
import random
from sklearn.metrics import precision_score, recall_score, f1_score, accuracy_score, roc_curve, auc
def model_metrics(model, x, y, pos_label=1):
“”“
評價函數
”“”
yhat = model.predict(x)
yprob = model.predict_proba(x)[:,1]
fpr, tpr, _ = roc_curve(y, yprob, pos_label=pos_label)
result = {‘accuracy_score’:accuracy_score(y, yhat),
‘f1_score_macro’: f1_score(y, yhat, average = “macro”),
‘precision’:precision_score(y, yhat,average=“macro”),
‘recall’:recall_score(y, yhat,average=“macro”),
‘auc’:auc(fpr,tpr),
‘ks’: max(abs(tpr-fpr))
}
return result
def bidirectional_selection(model, x_train, y_train, x_test, y_test, annealing=True, anneal_rate=0.1, iters=10,best_metrics=0,
metrics=‘auc’,threshold_in=0.0001, threshold_out=0.0001,early_stop=True,
verbose=True):
“”“
model 選擇的模型
annealing 模擬退火算法
threshold_in 特征入模的》閾值
threshold_out 特征剔除的《閾值
”“”
included = []
best_metrics = best_metrics
for i in range(iters):
# forward step
print(“iters”, i)
changed = False
excluded = list(set(x_train.columns) - set(included))
random.shuffle(excluded)
for new_column in excluded:
model.fit(x_train[included+[new_column]], y_train)
latest_metrics = model_metrics(model, x_test[included+[new_column]], y_test)[metrics]
if latest_metrics - best_metrics 》 threshold_in:
included.append(new_column)
change = True
if verbose:
print (‘Add {} with metrics gain {:.6}’.format(new_column,latest_metrics-best_metrics))
best_metrics = latest_metrics
elif annealing:
if random.randint(0, iters) 《= iters * anneal_rate:
included.append(new_column)
if verbose:
print (‘Annealing Add {} with metrics gain {:.6}’.format(new_column,latest_metrics-best_metrics))
# backward step
random.shuffle(included)
for new_column in included:
included.remove(new_column)
model.fit(x_train[included], y_train)
latest_metrics = model_metrics(model, x_test[included], y_test)[metrics]
if latest_metrics - best_metrics 《 threshold_out:
included.append(new_column)
else:
changed = True
best_metrics= latest_metrics
if verbose:
print(‘Drop{} with metrics gain {:.6}’.format(new_column,latest_metrics-best_metrics))
if not changed and early_stop:
break
return included
#示例
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y)
model = LGBMClassifier()
included = bidirectional_selection(model, x_train, y_train, x_test, y_test, annealing=True, iters=50,best_metrics=0.5,
metrics=‘auc’,threshold_in=0.0001, threshold_out=0,
early_stop=False,verbose=True)
- EOF -
編輯:lyn
-
機器學習
+關注
關注
66文章
8425瀏覽量
132770 -
特征選擇
+關注
關注
0文章
12瀏覽量
7189
原文標題:Python特征選擇(全)
文章出處:【微信號:DBDevs,微信公眾號:數據分析與開發】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論