1. 背景:

演算法:

分類演算法:gbdt

平衡樣本演算法:smote、smoteenn

特徵篩選演算法:RandomizedLogisticRegression

調參演算法:GridSearchCV

from sklearn.ensemble import GradientBoostingClassifier
from sklearn.linear_model import RandomizedLogisticRegression
from sklearn.model_selection import GridSearchCV
from imblearn.over_sampling import SMOTE
from imblearn.combine import SMOTEENN

實驗數據:

特徵:信用卡信息、用戶基本信息與徵信信息;

目標:貸後表現;

df = pd.read_csv(r.mod.csv,delimiter=,,encoding=gb18030)
X, y = df.drop(target,1),df[[target]]
X.fillna(-9)
train_X,test_X, train_y, test_y = train_test_split(X,
y,
test_size = 0.3,random_state = 42)
print(len(train_X.columns))
print(X.target.value_counts())

724
0 15314
1 1544

我們可以觀察到數據,共有724個特徵,16858條觀測樣本,目標佔比9.158%;


2. 為什麼要做特徵選擇

  • 在機器學習的實際應用中,特徵數量往往較多,其中可能存在不相關的特徵,特徵之間也可能存在相互依賴,容易導致:
    • 特徵個數越多,分析特徵、訓練模型所需的時間也就越長
    • 特徵個數越多,容易引起「維度災難」,模型也會越複雜,其泛化能力會下降。
  • 特徵選擇能剔除不相關(irrelevant)或亢余(redundant)的特徵,從而達到減少特徵個數,提高模型精確度,減少運行時間的目的。另一方面,選取出真正相關的特徵簡化了模型,是研究人員易於理解數據產生的過程。

3. 特徵選擇如何影響建模

我們在不做特徵選擇的情況下訓練模型,並且使用c值和ks值評價模型,經過貪婪搜索和網格搜索調參後,得到相對最優模型:

mod1=GradientBoostingClassifier(
learning_rate=0.01,n_estimators=573,subsample=0.77,
max_features=49,max_depth=3,min_samples_split=586,min_samples_leaf=254,max_leaf_nodes=586,
random_state=10
)
mod1.fit(train_X,train_y)

data_list1=[[train_X,train_y],[test_X,test_y]]
judge_mod(mod1,data_list1) #自定義函數,使用c值和ks值對模型評價

#訓練集 ks值: 0.5864842454394693
#訓練集 c值: 0.8730838861249308
#測試集 ks值: 0.29599608935192834
#測試集 c值: 0.7091145872427305

我們發現,在不經過特徵選擇的情況下:

訓練集評價遠好於測試集,說明過擬合了。

過擬合原因分析:輸入維度過多,數據中有過多噪音,使得模型不能專註在有效的特徵上。因此需要對特徵進行篩選,避免過擬合。

再次嘗試特徵選擇之後,訓練模型,並且使用c值和ks值評價模型:

#特徵評分
names=train_X.columns
rlasso = RandomizedLogisticRegression(C=1,random_state=41)
rlasso.fit(train_X, train_y)
m0=sorted(zip(map(lambda x: round(x, 8), rlasso.scores_),names), reverse=True)
#選擇特徵
m0=pd.DataFrame(m0)
n0=m0[m0[0]>0.1]
n0=list(n0[1])
print(原樣本特徵個數:,len(X.columns))
print(現樣本特徵個數:,len(n0))

#原樣本特徵個數: 724
#現樣本特徵個數: 22

mod2=GradientBoostingClassifier(
learning_rate=0.005,n_estimators=891,subsample=0.79,
max_features=3,max_depth=3,min_samples_split=512,min_samples_leaf=52,max_leaf_nodes=586,
random_state=10
)
mod2.fit(train_X[n0],train_y)
data_list=[[train_X[n0],train_y],[test_X,test_y]]
judge_mod(mod2,data_list)#自定義函數,使用c值和ks值對模型評價

#訓練集 ks值: 0.3739669707020454
#訓練集 c值: 0.7580598742399116
#測試集 ks值: 0.30142108147058383
#測試集 c值: 0.698249590920691

經過特徵篩選之後,保留下22個特徵;

使用22個特徵對模型進行訓練,發現:

a.訓練集c值與ks值迅速下降;

b.測試集c值和ks值表現穩定;

c.模型過擬合得到有效抑制;


4.樣本不平衡下的特徵選擇猜想與驗證

疑惑:

剔除的724-22=702個特徵是否真的對樣本分類沒有幫助?能不能篩選更多的有效特徵出來?

猜想:

在樣本不平衡的情況下,部分特徵對目標(少量)樣本描述較少,導致其貢獻度低,並不代表該類特徵無效。

ex:

某場景發生概率很低(因此缺失值很高),但是一旦發生,對客戶信用產生決定性影響。

驗證:

樣本不平衡情況下,部分特徵貢獻度低,無法進入模型。因此需要先平衡樣本,再進行特徵篩選。

names=train_X.columns
os= SMOTEENN(random_state=5)
X_a,y_a=os.fit_sample(train_X.values,train_y.values.ravel())
y_a = pd.DataFrame(data=y_a,columns=[TARGET])
X_a = pd.DataFrame(data=X_a,columns=names)
#特徵評分
rlasso = RandomizedLogisticRegression(C=1,random_state=41)
rlasso.fit(X_a, y_a)
m0=sorted(zip(map(lambda x: round(x, 8), rlasso.scores_),names), reverse=True)
#選擇特徵
m1=pd.DataFrame(m0)
n1=m1[m1[1]>0.5]
n1=list(n1[1])
print(原樣本特徵個數:,len(X.columns))
print(現樣本特徵個數:,len(n1))

#原樣本特徵個數: 724
#現樣本特徵個數: 26

mod3=GradientBoostingClassifier(
learning_rate=0.005,n_estimators=891,subsample=0.79,
max_features=3,max_depth=3,min_samples_split=512,min_samples_leaf=52,max_leaf_nodes=586,
random_state=10
)
mod2.fit(train_X[n1],train_y)

data_list3=[[train_X[n1],train_y],[test_X,test_y]]
judge_mod(mod3,data_list3)#自定義函數,使用c值和ks值對模型評價

#訓練集 ks值: 0.3991915422885572
#訓練集 c值: 0.7675084646213378
#測試集 ks值: 0.31727384294356953
#測試集 c值: 0.7085319307042168

我們發現:

a) 隨著樣本平衡,特徵的評分得到極大提高。原本選取特徵評分大於0.1的,選取到22個特徵。現在選取特徵評分大於0.5,選取到26個特徵。

b) 使用新篩選的特徵訓練模型,測試集ks提高0.016,c值提高0.01;


5.總結

特徵篩選可以有效避免模型過擬合

樣本不平衡的情況下,先平衡樣本再篩選特徵,可以幫助篩選出更多的有效特徵。


6.參考

結合Scikit-learn介紹幾種常用的特徵選擇方法 - CSDN博客?

blog.csdn.net圖標Python:SMOTE演算法?

www.jianshu.com
圖標
帳號登錄?

blog.csdn.net


推薦閱讀:

相关文章