特征工程(三)特征选择
经过“数据清理”和“特征变换”后的数据集,已经满足了数据科学项目中算法对数值的基本要求。但是, 不呢止步于此,数据集的特征数量、质量会影响计算效率和最终模型的预测、分类效果。所以要对特征进行选择,即根据具体的项目选择适合的特征。
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 |