經過“數據清理”和“特徵變換”後的數據集,已經滿足了數據科學項目中算法對數值的基本要求。但是, 不呢止步於此,數據集的特徵數量、質量會影響計算效率和最終模型的預測、分類效果。所以要對特徵進行選擇,即根據具體的項目選擇適合的特徵。
3.1 特徵選擇簡述
是不是維度越大的數據越好?是不是所有的維度都是必須的?
import pandas as pd
df_wine = pd.read_csv("datasets/wine_data.csv")
df_wine.head()
Class_label | Alcohol | Malic_acid | Ash | Alcalinity_of_ash | Magnesium | Total_phenols | Flavanoids | Nonflavanoid_phenols | Proanthocyanins | Color_intensity | Hue | OD280/OD315_of_diluted_wines | Proline | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 14.23 | 1.71 | 2.43 | 15.6 | 127 | 2.80 | 3.06 | 0.28 | 2.29 | 5.64 | 1.04 | 3.92 | 1065 |
1 | 1 | 13.20 | 1.78 | 2.14 | 11.2 | 100 | 2.65 | 2.76 | 0.26 | 1.28 | 4.38 | 1.05 | 3.40 | 1050 |
2 | 1 | 13.16 | 2.36 | 2.67 | 18.6 | 101 | 2.80 | 3.24 | 0.30 | 2.81 | 5.68 | 1.03 | 3.17 | 1185 |
3 | 1 | 14.37 | 1.95 | 2.50 | 16.8 | 113 | 3.85 | 3.49 | 0.24 | 2.18 | 7.80 | 0.86 | 3.45 | 1480 |
4 | 1 | 13.24 | 2.59 | 2.87 | 21.0 | 118 | 2.80 | 2.69 | 0.39 | 1.82 | 4.32 | 1.04 | 2.93 | 735 |
依據機器學習的一般流程,把數據集劃分爲訓練集和測試集,並且對測試集和訓練集分別實現特徵標準化。
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
X, y = df_wine.iloc[:, 1:], df_wine.iloc[:, 0].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0, stratify=y)
std = StandardScaler()
X_train_std = std.fit_transform(X_train)
X_test_std = std.fit_transform(X_test)
以Class_label爲標籤,建立對數迴歸模型,尋找另外13個特徵與標籤之間的關係。
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(penalty='l1', C=1.0 , solver='liblinear')
lr.fit(X_train_std, y_train)
LogisticRegression(penalty='l1', solver='liblinear')
在創建對數概率迴歸模型時候,使用了參數penalty='l1', C=1.0,這意味着在本模型中遵照此規則增加了懲罰項,其意圖是避免訓練得到的模型過擬合,也正是出於這個原因,模型捨棄了部分特性——表現出來就是係數爲0
lr.coef_
array([[ 1.24568008, 0.18066268, 0.74500129, -1.16270324, 0. ,
0. , 1.16473536, 0. , 0. , 0. ,
0. , 0.55281296, 2.50976773],
[-1.53710813, -0.38760504, -0.99525286, 0.36504305, -0.05948103,
0. , 0.66797894, 0. , 0. , -1.93413502,
1.23360251, 0. , -2.23189735],
[ 0.13448113, 0.16969503, 0.35805173, 0. , 0. ,
0. , -2.43221807, 0. , 0. , 1.56308975,
-0.81943572, -0.49548102, 0. ]])
lr.intercept_
array([-1.26347923, -1.21597948, -2.36926979])
在機器學習中,過擬合是比較常見的現象,通常採用如下避免方法:
- 訓練集和測試集五五開
- 在模型中增加懲罰項,簡化模型
- 儘可能選用參數少的模型
- 降低數據集的維度
特徵選擇,是指去除數據集中的冗餘和無關的特徵,從數據集中找出主要特徵,最終得到得到的是原有特徵的子集。因此,特徵選擇也稱爲“特徵子集選擇”
爲實現特徵選擇,這裏介紹三類方法:封裝器法、過濾器法和嵌入法。
3.2 封裝器法
封裝器法的基本思路是:
- 選用一個特徵子集訓練模型,此處的模型通常是一種機器學習算法,也稱爲目標函數。
- 用驗證數據集對模型進行評估。
- 依據某種搜索方式,對不同的特徵子集進行上述操作,
- 依據評估結果,選出相對最佳的特徵子集。
這種方式屬於貪心搜索算法,計算量較大。針對特徵子集的組合搜索問題,封裝法有下述三種常見的選擇方式。
循序特徵選擇
包括 循環向前(SFS)和循環向後(SBS)
基礎知識
以SFS爲例:
(1)創建一個空的集合X,作爲特徵子集
(2)從原特徵集合中“一次挑選一個”——這就是“循序”的含義,與特徵子集X中的特徵組合,並使得目標函數(選定的某個機器學習模型)結果最佳(模型預測的誤差最小)
(3)將挑選出來的特徵從原特徵中移除,同時將其追加到X中。
(4)重複(2)、(3)步驟,直到集合X的特徵數量達到規定的數量爲止,中止上述循環。
顯然,SFS不是把所有可能都實現一遍,而是找到一種可能最優解即中止尋找,這樣就大大降低了計算量。
mlxtend的第三庫提供了實現包含SFS的多種循環特徵選擇方法
pip install mlxtend
mlxtend中集成了幾個數據集,這裏使用關於葡萄酒的數據。X有13個特徵178個樣本,y是每個樣本的標籤,即每種葡萄酒的等級(共有3級,用0,1,2表示)。其中,X的13特徵依次對應的名稱是:
- Alcohol
- Malic acid
- Ash
- Alcalinity of ash
- Magnesium
- Total phenols
- Flavanoids
- Nonflavanoid phenols
- Proanthocyanins
- Color intensity
- Hue
- OD280/OD315 of diluted wines
- Proline
https://archive.ics.uci.edu/ml/datasets/Wine
from mlxtend.feature_selection import SequentialFeatureSelector as SFS
from sklearn.neighbors import KNeighborsClassifier
from mlxtend.data import wine_data
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
X, y = wine_data()
X.shape
(178, 13)
X_train, X_test, y_train, y_test= train_test_split(X, y,
stratify=y,
test_size=0.3,
random_state=1)
std = StandardScaler() #標準化
X_train_std = std.fit_transform(X_train)
knn = KNeighborsClassifier(n_neighbors=3) # knn作爲SFS的目標函數
sfs = SFS(estimator=knn, # SFS封裝器
k_features=4, # 選擇4個最佳特徵
forward=True,
floating=False,
verbose=2, # 2輸出訓練過程的全部日誌信息
scoring='accuracy',#模型評估方法
cv=0) # 0 表示不進行交叉驗證
sfs.fit(X_train_std, y_train)
[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 1 out of 1 | elapsed: 0.0s remaining: 0.0s
[Parallel(n_jobs=1)]: Done 13 out of 13 | elapsed: 0.0s finished
[2022-06-09 19:28:12] Features: 1/4 -- score: 0.8548387096774194[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 1 out of 1 | elapsed: 0.0s remaining: 0.0s
[Parallel(n_jobs=1)]: Done 12 out of 12 | elapsed: 0.0s finished
[2022-06-09 19:28:12] Features: 2/4 -- score: 0.9596774193548387[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 1 out of 1 | elapsed: 0.0s remaining: 0.0s
[Parallel(n_jobs=1)]: Done 11 out of 11 | elapsed: 0.0s finished
[2022-06-09 19:28:12] Features: 3/4 -- score: 0.9919354838709677[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 1 out of 1 | elapsed: 0.0s remaining: 0.0s
[Parallel(n_jobs=1)]: Done 10 out of 10 | elapsed: 0.0s finished
[2022-06-09 19:28:12] Features: 4/4 -- score: 0.9838709677419355
從輸出的日誌信息可以很明確地看出,當選擇3個特徵的時候,模型knn表現最好
sfs.subsets_
{1: {'feature_idx': (6,),
'cv_scores': array([0.85483871]),
'avg_score': 0.8548387096774194,
'feature_names': ('6',)},
2: {'feature_idx': (6, 9),
'cv_scores': array([0.95967742]),
'avg_score': 0.9596774193548387,
'feature_names': ('6', '9')},
3: {'feature_idx': (6, 9, 11),
'cv_scores': array([0.99193548]),
'avg_score': 0.9919354838709677,
'feature_names': ('6', '9', '11')},
4: {'feature_idx': (6, 8, 9, 11),
'cv_scores': array([0.98387097]),
'avg_score': 0.9838709677419355,
'feature_names': ('6', '8', '9', '11')}}
利用SFS的屬性subsets_得到了每次選擇出來的特徵及其相應的評估分數,feature_names表示特徵名稱。
項目案例
使用隨機森林迴歸作爲目標函數,從房價數據集中,選擇出10佳特徵
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
df = pd.read_csv("datasets/housprice.csv")
cols = list(df.select_dtypes(include=['int64', 'float64']).columns)
data = df[cols]
X_train,X_test,y_train,y_test= train_test_split(
data.drop('SalePrice',axis=1),
data['SalePrice'],
test_size=.2,
random_state=1#隨機數生成器使用的種子
)
X_train.fillna(0, inplace=True) # 用0填充缺失值
sfs3 = SFS(RandomForestRegressor(),
k_features=10,
forward=True,
verbose=0,
cv=5,
n_jobs=-1,
scoring='r2')
sfs3.fit(X_train,y_train)
sfs3.k_feature_names_
('MSSubClass',
'OverallQual',
'OverallCond',
'YearRemodAdd',
'BsmtFinSF1',
'TotalBsmtSF',
'GrLivArea',
'Fireplaces',
'GarageCars',
'3SsnPorch')
窮舉特徵選擇
指封裝器中的搜索算法先將所有特徵組合都實現一遍,然後通過比較各種特徵組合後的模型表現,從中選擇出最佳得到特徵子集。
顯然窮舉特徵選擇必然浪費更大的計算量。
# 對上面SFS練習題中的10個特徵的數據集,對它使用窮舉法,從10佳中選出5強
mini_data = X_train[X_train.columns[list(sfs3.k_feature_idx_)]]
mini_data.shape
(1168, 10)
import numpy as np
from mlxtend.feature_selection import ExhaustiveFeatureSelector as EFS
efs = EFS(RandomForestRegressor(),
min_features=1,
max_features=5,
scoring='r2',
n_jobs=-1)
efs.fit(np.array(mini_data),y_train)
mini_data.columns[list(efs.best_idx_)]
Index(['MSSubClass', 'OverallQual', 'YearRemodAdd', 'BsmtFinSF1', 'GrLivArea'], dtype='object')
很顯然,窮舉特徵選擇也是構建了一個封裝器,在封裝器裏使用了一種機器學習算法作爲目標函數。
遞歸特徵消除
遞歸特徵消除RFE也是封裝器法的一種具體實施,其主要思想是利用訓練集數據生成模型,再根據模型的特徵權重,對特徵進行取捨,消除權重不同的特徵,從而得到數據集的特徵子集。然後,對這個特徵子集重複上述過程,直到特徵數量達到規定值爲止。顯然,這種尋找最優特徵子集的方法依然是貪心搜索算法。
from sklearn.feature_selection import RFE
# 爲避免大規模計算,還是從10佳中選擇5強,
mini_data = X_train[X_train.columns[list(sfs3.k_feature_idx_)]]
rfe = RFE(RandomForestRegressor(), #依舊使用隨機森林迴歸
n_features_to_select=5)
rfe.fit(np.array(mini_data),y_train)
rfe.ranking_
array([4, 1, 3, 2, 1, 1, 1, 5, 1, 6])
對mini_data的各個特徵的權重從高到低排序之後,表示順序的序號,1表示相應索引的特徵權重最靠前,也就是權重最高。
mini_data.columns[rfe.ranking_==1]
Index(['OverallQual', 'BsmtFinSF1', 'TotalBsmtSF', 'GrLivArea', 'GarageCars'], dtype='object')
對比發現,使用不同的方法選出的5強不完全一致,因此不同的特徵方法會訓練出不同效果的模型
3.3 過濾器法
過濾器法不評估子集的預測誤差,而是使用某些統計指標,比如相關係數、互信息等——目標函數不同,根據這些統計指標,對各特徵進行排序,以確定特徵的取捨。
下面用卡方檢驗(皮爾森卡方檢驗)作爲統計指標選擇特徵
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest # 過濾器類
from sklearn.feature_selection import chi2 #引用一個統計指標函數
iris = load_iris()
X, y = iris.data, iris.target
skb = SelectKBest(chi2, k=2) #k爲2表示特徵子集中的特徵數量
result = skb.fit(X, y) # 根據從大到小的排序取2個特徵
print("X^2 is: ", result.scores_)
print("P-values is: ", result.pvalues_)
X^2 is: [ 10.81782088 3.7107283 116.31261309 67.0483602 ]
P-values is: [4.47651499e-03 1.56395980e-01 5.53397228e-26 2.75824965e-15]
- 卡方檢驗是統計學上的假設檢驗方法。值越大,兩個變量之間的偏差越大;反之,偏差越小。
- P值是統計學中用於判斷假設檢驗結果的參數。P值越小,原假設發生的概率就越小。
利用訓練得到的模型對數據集X進行特徵選擇,得到含有兩個特徵的新數據集
X_new = skb.transform(X)
X_new.shape
(150, 2)
顯示數據對應的特徵名稱
import numpy as np
[iris.feature_names[np.where(X[0, :]==i)[0][0]] for i in X_new[0, :]]
['petal length (cm)', 'petal width (cm)']
過濾法中利用統計指標對特徵排序,然後依據特徵排序結果選擇特徵
iris.feature_names
['sepal length (cm)',
'sepal width (cm)',
'petal length (cm)',
'petal width (cm)']
過濾器的實現路徑可以表示爲:
過濾器法和封裝器法對比:
- 過濾器法通常不對數據集執行迭代計算,因此計算速度比封裝器法要快
- 封裝器的目標函數是某個機器學習算法,過濾器的函數則是通用的統計函數,這樣使得過濾器法所得到的特徵更具有通用性,非專門針對某個算法有良好表現
- 利用過濾器法進行特徵選擇時,用戶需要武斷地輸入閾值,這可能會導致一定的選擇成本。
- 如果特徵數量過少,過濾器可能無法找到最佳的特徵子集,而封裝器總能返回特徵子集
- 因爲過濾器所得特徵子集與某種算法無關,所以一般不會出現過擬合現象,而經由封裝器法所得特徵子集訓練的模型,會出現過擬合現象。
在項目中,應依據具體數據和項目要求,確定特徵選擇的實施方法。
3.4 嵌入法
在3.1節中曾用對數概率迴歸模型研究了葡萄酒的等級與特徵的關係。因爲在模型中使用了L1懲罰項,從而得到了特徵係數的稀疏解,某些特徵的係數爲0。如此,可以對係數排序——特徵權重,然後依據某個閾值選擇部分特徵。
這種特性選擇的實現方法顯然不是封裝法,也不是過濾器法,而是在訓練模型的同時,得到了特徵權重,並完成特徵選擇。像這樣將特徵選擇過程與訓練模型融爲一體,在模型訓練過程中自動進行特徵選擇,被稱爲嵌入法特徵選擇。
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
df_wine = pd.read_csv("datasets/wine_data.csv")
X, y = df_wine.iloc[:, 1:], df_wine.iloc[:, 0].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0, stratify=y)
std = StandardScaler()
X_train_std = std.fit_transform(X_train)
X_test_std = std.fit_transform(X_test)
# 創建對數概率迴歸模型,採用L1懲罰項
lr = LogisticRegression(C=1.0, penalty='l1', solver='liblinear')
# 規定選擇特徵的閾值--特徵權重的中位數
# 能夠用的機器學習模型還有隨機森林模型、決策樹模型、LASSO迴歸模型、嶺迴歸模型等
model = SelectFromModel(lr, threshold='median')
X_new = model.fit_transform(X_train_std, y_train)
X_new.shape
(124, 7)
X_train_std.shape
(124, 13)
3.5 綜合練習
import pandas as pd
df = pd.read_csv("datasets/app_small.csv")
df.drop('Unnamed: 0', axis=1, inplace=True) # 刪除第一列
df.shape
(30751, 122)
df.columns
Index(['SK_ID_CURR', 'TARGET', 'NAME_CONTRACT_TYPE', 'CODE_GENDER',
'FLAG_OWN_CAR', 'FLAG_OWN_REALTY', 'CNT_CHILDREN', 'AMT_INCOME_TOTAL',
'AMT_CREDIT', 'AMT_ANNUITY',
...
'FLAG_DOCUMENT_18', 'FLAG_DOCUMENT_19', 'FLAG_DOCUMENT_20',
'FLAG_DOCUMENT_21', 'AMT_REQ_CREDIT_BUREAU_HOUR',
'AMT_REQ_CREDIT_BUREAU_DAY', 'AMT_REQ_CREDIT_BUREAU_WEEK',
'AMT_REQ_CREDIT_BUREAU_MON', 'AMT_REQ_CREDIT_BUREAU_QRT',
'AMT_REQ_CREDIT_BUREAU_YEAR'],
dtype='object', length=122)
共有122個特徵
數字類型的特徵和非數字類型的特徵分別保存到不同的列表中
categorical_list = []
numerical_list = []
for i in df.columns.tolist():
if df[i].dtype=='object':
categorical_list.append(i)
else:
numerical_list.append(i)
print('Number of categorical features:', str(len(categorical_list)))
print('Number of numerical features:', str(len(numerical_list)))
Number of categorical features: 16
Number of numerical features: 106
將數值類型和分類型分別查出來共有16個分類型,106個數值類型
df[numerical_list].isna().any()
SK_ID_CURR False
TARGET False
CNT_CHILDREN False
AMT_INCOME_TOTAL False
AMT_CREDIT False
...
AMT_REQ_CREDIT_BUREAU_DAY True
AMT_REQ_CREDIT_BUREAU_WEEK True
AMT_REQ_CREDIT_BUREAU_MON True
AMT_REQ_CREDIT_BUREAU_QRT True
AMT_REQ_CREDIT_BUREAU_YEAR True
Length: 106, dtype: bool
檢查numerical_list中的特徵是否有缺失值,如果有缺失值,則用中位數填補
from sklearn.impute import SimpleImputer
df[numerical_list] = SimpleImputer(strategy='median').fit_transform(df[numerical_list])
categorical_list中的特徵都是分類型特徵,於是乎進行OneHot編碼(創建虛擬變量)
df = pd.get_dummies(df, drop_first=True)
df.shape
(30751, 228)
df
SK_ID_CURR | TARGET | CNT_CHILDREN | AMT_INCOME_TOTAL | AMT_CREDIT | AMT_ANNUITY | AMT_GOODS_PRICE | REGION_POPULATION_RELATIVE | DAYS_BIRTH | DAYS_EMPLOYED | ... | FONDKAPREMONT_MODE_reg oper spec account | HOUSETYPE_MODE_specific housing | HOUSETYPE_MODE_terraced house | WALLSMATERIAL_MODE_Mixed | WALLSMATERIAL_MODE_Monolithic | WALLSMATERIAL_MODE_Others | WALLSMATERIAL_MODE_Panel | WALLSMATERIAL_MODE_Stone, brick | WALLSMATERIAL_MODE_Wooden | EMERGENCYSTATE_MODE_Yes | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 100003.0 | 0.0 | 0.0 | 270000.000 | 1293502.5 | 35698.5 | 1129500.0 | 0.003541 | -16765.0 | -1188.0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 100015.0 | 0.0 | 0.0 | 38419.155 | 148365.0 | 10678.5 | 135000.0 | 0.015221 | -20417.0 | 365243.0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 100051.0 | 0.0 | 0.0 | 202500.000 | 661702.5 | 48280.5 | 598500.0 | 0.007114 | -9827.0 | -758.0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3 | 100054.0 | 0.0 | 0.0 | 99000.000 | 260640.0 | 26838.0 | 225000.0 | 0.022625 | -20121.0 | -5332.0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4 | 100069.0 | 0.0 | 1.0 | 360000.000 | 640458.0 | 27265.5 | 517500.0 | 0.007330 | -14186.0 | -1743.0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
30746 | 456195.0 | 0.0 | 0.0 | 94500.000 | 270000.0 | 15075.0 | 270000.0 | 0.028663 | -20246.0 | -5452.0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
30747 | 456212.0 | 0.0 | 1.0 | 135000.000 | 808650.0 | 23773.5 | 675000.0 | 0.009657 | -18042.0 | -186.0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
30748 | 456219.0 | 0.0 | 1.0 | 112500.000 | 521280.0 | 31630.5 | 450000.0 | 0.006207 | -13346.0 | -1972.0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
30749 | 456237.0 | 0.0 | 0.0 | 135000.000 | 946764.0 | 37678.5 | 765000.0 | 0.019689 | -17533.0 | -2306.0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
30750 | 456253.0 | 0.0 | 0.0 | 153000.000 | 677664.0 | 29979.0 | 585000.0 | 0.005002 | -14966.0 | -7921.0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
30751 rows × 228 columns
X = df.drop(['SK_ID_CURR', 'TARGET'], axis=1)
y = df['TARGET']
feature_name = X.columns.tolist()
先對X進行特徵規範化操作,而後利用卡方檢驗選擇50個特徵
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
from sklearn.preprocessing import MinMaxScaler
X_norm = MinMaxScaler().fit_transform(X) # MinMax區間化
chi_selector = SelectKBest(chi2, k=50) # 過濾器法
chi_selector.fit(X_norm, y)
SelectKBest(k=50, score_func=<function chi2 at 0x000001C74C48F310>)
chi_support = chi_selector.get_support()
chi_feature = X.loc[:,chi_support].columns.tolist()
使用封裝器,選50個特徵
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
rfe_selector = RFE(estimator=LogisticRegression(penalty="l1",solver='liblinear'), n_features_to_select=50, step=10, verbose=5)
rfe_selector.fit(X_norm, y)
rfe_support = rfe_selector.get_support()
rfe_feature = X.loc[:,rfe_support].columns.tolist()
用嵌入法選擇特徵
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression #使用logistic迴歸模型
embeded_lr_selector = SelectFromModel(LogisticRegression(penalty="l1",solver='liblinear'),threshold= '1.25*median')
embeded_lr_selector.fit(X_norm, y)
embeded_lr_support = embeded_lr_selector.get_support()
embeded_lr_feature = X.loc[:,embeded_lr_support].columns.tolist()
print(str(len(embeded_lr_feature)), 'selected features')
105 selected features
不用對數機率迴歸模型,改爲隨機森林分類
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier #相對上面,模型換了
embeded_rf_selector = SelectFromModel(RandomForestClassifier(n_estimators=50), threshold='1.25*median')
embeded_rf_selector.fit(X, y)
embeded_rf_support = embeded_rf_selector.get_support()
embeded_rf_feature = X.loc[:,embeded_rf_support].columns.tolist()
print(str(len(embeded_rf_feature)), 'selected features')
98 selected features
# 下把特徵按照被選擇的次數從高到低列出來
feature_selection_df = pd.DataFrame({'Feature':feature_name,
'Chi-2':chi_support,
'RFE':rfe_support,
'Logistics':embeded_lr_support,
'Random Forest':embeded_rf_support})
# 每個特徵在不同方式中被選擇的次數總和
feature_selection_df['Total'] = np.sum(feature_selection_df, axis=1)
# 按照次數大小,顯示前50個
feature_selection_df = feature_selection_df.sort_values(['Total','Feature'] , ascending=False)
feature_selection_df.index = range(1, len(feature_selection_df)+1)
feature_selection_df.head(50)
Feature | Chi-2 | RFE | Logistics | Random Forest | Total | |
---|---|---|---|---|---|---|
1 | REGION_RATING_CLIENT_W_CITY | True | True | True | True | 4 |
2 | ORGANIZATION_TYPE_Self-employed | True | True | True | True | 4 |
3 | ORGANIZATION_TYPE_Construction | True | True | True | True | 4 |
4 | ORGANIZATION_TYPE_Business Entity Type 3 | True | True | True | True | 4 |
5 | FLAG_OWN_CAR_Y | True | True | True | True | 4 |
6 | EXT_SOURCE_3 | True | True | True | True | 4 |
7 | EXT_SOURCE_2 | True | True | True | True | 4 |
8 | EXT_SOURCE_1 | True | True | True | True | 4 |
9 | DAYS_ID_PUBLISH | True | True | True | True | 4 |
10 | CODE_GENDER_M | True | True | True | True | 4 |
11 | WALLSMATERIAL_MODE_Monolithic | True | True | True | False | 3 |
12 | ORGANIZATION_TYPE_Transport: type 3 | True | True | True | False | 3 |
13 | ORGANIZATION_TYPE_Police | True | True | True | False | 3 |
14 | ORGANIZATION_TYPE_Military | True | True | True | False | 3 |
15 | ORGANIZATION_TYPE_Industry: type 9 | True | True | True | False | 3 |
16 | OCCUPATION_TYPE_Low-skill Laborers | True | True | True | False | 3 |
17 | OCCUPATION_TYPE_Laborers | True | False | True | True | 3 |
18 | OCCUPATION_TYPE_High skill tech staff | True | True | True | False | 3 |
19 | OCCUPATION_TYPE_Drivers | True | False | True | True | 3 |
20 | NONLIVINGAPARTMENTS_MODE | False | True | True | True | 3 |
21 | NAME_FAMILY_STATUS_Married | True | False | True | True | 3 |
22 | NAME_EDUCATION_TYPE_Higher education | True | False | True | True | 3 |
23 | LIVINGAREA_MEDI | False | True | True | True | 3 |
24 | FLOORSMIN_MEDI | False | True | True | True | 3 |
25 | FLOORSMAX_MODE | False | True | True | True | 3 |
26 | FLAG_WORK_PHONE | True | False | True | True | 3 |
27 | FLAG_DOCUMENT_3 | True | False | True | True | 3 |
28 | ENTRANCES_AVG | False | True | True | True | 3 |
29 | DEF_60_CNT_SOCIAL_CIRCLE | False | True | True | True | 3 |
30 | DEF_30_CNT_SOCIAL_CIRCLE | False | True | True | True | 3 |
31 | BASEMENTAREA_AVG | False | True | True | True | 3 |
32 | APARTMENTS_MEDI | False | True | True | True | 3 |
33 | AMT_REQ_CREDIT_BUREAU_MON | False | True | True | True | 3 |
34 | AMT_GOODS_PRICE | False | True | True | True | 3 |
35 | AMT_CREDIT | False | True | True | True | 3 |
36 | AMT_ANNUITY | False | True | True | True | 3 |
37 | YEARS_BEGINEXPLUATATION_MODE | False | False | True | True | 2 |
38 | YEARS_BEGINEXPLUATATION_MEDI | False | False | True | True | 2 |
39 | WEEKDAY_APPR_PROCESS_START_TUESDAY | False | False | True | True | 2 |
40 | WALLSMATERIAL_MODE_Wooden | False | True | True | False | 2 |
41 | REG_CITY_NOT_WORK_CITY | True | False | False | True | 2 |
42 | REG_CITY_NOT_LIVE_CITY | True | False | False | True | 2 |
43 | REGION_RATING_CLIENT | True | False | False | True | 2 |
44 | ORGANIZATION_TYPE_Transport: type 1 | False | True | True | False | 2 |
45 | ORGANIZATION_TYPE_Realtor | False | True | True | False | 2 |
46 | ORGANIZATION_TYPE_Other | False | False | True | True | 2 |
47 | ORGANIZATION_TYPE_Insurance | False | True | True | False | 2 |
48 | ORGANIZATION_TYPE_Industry: type 3 | False | True | True | False | 2 |
49 | ORGANIZATION_TYPE_Industry: type 2 | False | True | True | False | 2 |
50 | ORGANIZATION_TYPE_Industry: type 12 | False | True | True | False | 2 |