# 特征选取之单变量统计、基于模型选择、迭代选择SelectKBest特征选取

SelectKBest特征选取

随机森林

迭代选择

## 单变量统计

### 代码实现

``````from sklearn.feature_selection import SelectPercentile
select=SelectPercentile(percentile=50)    #选取50%的特征
select.fit(X_train,y_train)
X_train_selected=select.transform(X_train)
print(X_train.shape)
print(X_train_selected.shape)

``````

``````import numpy as np
from sklearn.feature_selection import SelectPercentile    #SelectPercentile选择百分比，SelectKBest选择个数
from sklearn.model_selection import train_test_split

#使用sklearn自带的数据集

#向数据中添加噪声特征，前30个特征来自原数据集，后50个是噪声
rng=np.random.RandomState(42)
#构造噪声特征
noise=rng.normal(size=(len(cancer.data),50))
X_w_noise=np.hstack([cancer.data,noise])

#分割数据集用于测试和训练
X_train,X_test,y_train,y_test=train_test_split(X_w_noise,cancer.target,random_state=0,test_size=.5)

#特征选取
select=SelectPercentile(percentile=50)    #选取50%的特征
select.fit(X_train,y_train)
X_train_selected=select.transform(X_train)
print(X_train.shape)
print(X_train_selected.shape)

``````

``````#查看哪些特征被选中
import matplotlib.pyplot as plt
plt.xlabel('sample index')
plt.show()

``````

### SelectKBest特征选取

``````import pandas as pd
import numpy as np
# 分类常用的
from sklearn.feature_selection import SelectKBest,f_classif,chi2,mutual_info_classif
# 分别是卡方检验，计算非负特征和类之间的卡方统计 chi
# 样本方差F值，f_classif
# 离散类别交互信息， mutual_info_classif
# 回归常用的
from sklearn.feature_selection import f_regression,mutual_info_regression``````
``````selector= SelectKBest(score_func= chi2,k=len(X.columns))
selector.fit(X,y)
score=-np.log10(selector.pvalues_)
# print(score)
score_index=np.argsort(score)[::-1]
for i in range(len(score)):
print("%0.2f %s"%(score[score_index[i]],X.columns[score_index[i]]))``````

``````from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from  scipy.stats import chi2_contingency
import numpy as np

model = SelectKBest(chi2, k=8)#选择k个最佳特征
X_new = model.fit_transform(X, y)
#feature_data是特征数据，label_data是标签数据，该函数可以选择出k个特征

print("model shape: ",X_new.shape)

scores = model.scores_
print('model scores:', scores)  # 得分越高，特征越重要

p_values = model.pvalues_
print('model p-values', p_values)  # p-values 越小，置信度越高，特征越重要

# 按重要性排序，选出最重要的 k 个
indices = np.argsort(scores)[::-1]
k_best_features = list(X.columns.values[indices[0:8]])

print('k best features are:n ',k_best_features)

print(k_best_features)``````

### 递归特征消除(RFE)

sklearn官方解释：对特征含有权重的预测模型(例如，线性模型对应参数coefficients)，RFE通过递归减少考察的特征集规模来选择特征。首先，预测模型在原始特征上训练，每个特征指定一个权重。之后，那些拥有最小绝对值权重的特征被踢出特征集。如此往复递归，直至剩余的特征数量达到所需的特征数量。

RFE 通过交叉验证的方式执行RFE，以此来选择最佳数量的特征：对于一个数量为d的feature的集合，他的所有的子集的个数是2的d次方减1(包含空集)。指定一个外部的学习算法，比如SVM之类的。通过该算法计算所有子集的validation error。选择error最小的那个子集作为所挑选的特征。

``````"""

"""
from sklearn import datasets
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression

model = LogisticRegression()
rfe = RFE(model, 3)
rfe = rfe.fit(X, y)
print(X.columns[rfe.support_])
print(rfe.support_)
print(rfe.ranking_)``````

RFE的稳定性很大程度上取决于迭代时，底层用的哪种模型。比如RFE采用的是普通的回归（LR），没有经过正则化的回归是不稳定的，那么RFE就是不稳定的。假如采用的Lasso/Ridge，正则化的回归是稳定的，那么RFE就是稳定的。

### 皮尔逊系数（相关系数）

``````# 查看其他指标和income的相关性，并对其相关性系数排序
# 正相关与负相关，越接近1说明该变量值越大目标标签的值越容易分类为1
df.corr()[["n23"]].sort_values(by="n23",ascending=False)``````
``````# 可以根据相关性的值进行取值带入模型（特征选取与筛选）第一次选取
corr=df.corr()[["n23"]].sort_values(by="n23",ascending=False).iloc[1:10].index.values.astype("U")
corr_name=corr.tolist()
corr_name``````

利用该方法还可以绘制热力图:sns.clustermap(df.corr())

Pearson相关系数的一个明显缺陷是，作为特征排序机制，他只对线性关系敏感。如果关系是非线性的，即便两个变量具有一一对应的关系，Pearson相关性也可能会接近0。

## 基于树模型的特征选择

### 轻量级的高效梯度树

``````from sklearn.model_selection import train_test_split,cross_val_score #拆分训练集和测试集
import lightgbm as lgbm #轻量级的高效梯度提升树
X_name=df.corr()[["n23"]].sort_values(by="n23",ascending=False).iloc[1:].index.values.astype("U")
X=df.loc[:,X_name.tolist()]
y=df.loc[:,['n23']]
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2,stratify=y,random_state=1)
lgbm_reg = lgbm.LGBMRegressor(objective='regression',max_depth=6,num_leaves=25,learning_rate=0.005,n_estimators=1000,min_child_samples=80, subsample=0.8,colsample_bytree=1,reg_alpha=0,reg_lambda=0)
lgbm_reg.fit(X_train, y_train)
#选择最重要的20个特征，绘制他们的重要性排序图
lgbm.plot_importance(lgbm_reg, max_num_features=20)

##也可以不使用自带的plot_importance函数，手动获取特征重要性和特征名，然后绘图
feature_weight = lgbm_reg.feature_importances_
feature_name = lgbm_reg.feature_name_
feature_sort = pd.Series(data = feature_weight ,index = feature_name)
feature_sort = feature_sort.sort_values(ascending = False)
# plt.figure(figsize=(10,8))
# sns.barplot(feature_sort.values,feature_sort.index, orient='h')
lgbm_name=feature_sort.index[:15].tolist()
lgbm_name``````

### 随机森林

``````from sklearn import metrics
import warnings
warnings.filterwarnings("ignore")

from sklearn.ensemble import RandomForestClassifier
import matplotlib.pyplot as plt

selected_feat_names=set()
for i in range(10):                           #这里我们进行十次循环取交集
tmp = set()
rfc = RandomForestClassifier(n_jobs=-1)
rfc.fit(X, y)

#print("training finished")

importances = rfc.feature_importances_
indices = np.argsort(importances)[::-1]   # 降序排列
S={}
for f in range(X.shape[1]):
if  importances[indices[f]] >=0.0001:
S[X.columns[indices[f]]]=importances[indices[f]]
#print("%2d) %-*s %f" % (f + 1, 30, X.columns[indices[f]], importances[indices[f]]))
selected_feat_names |= tmp
imp_fea=pd.Series(S)

plt.figure(figsize=(10,8))

sns.barplot(imp_fea.values,imp_fea.index, orient='h')
print(imp_fea)
print(len(selected_feat_names), "features are selected")``````

THE END