基于统计的特征选择
基于统计的特征选择,可以使用皮尔逊相关系数、假设检验来帮助我们进行特征选择。
1、基于皮尔逊系数
皮尔逊相关系数会测量列和列之间的线性关系,该系数在-1~1之间变化,0代表没有线性关系,-1和1 代表线性关系很强。
注意:
皮尔逊相关系数要求每列是正态分布的,如果数据集很大(超过500阈值),根据中心极限定理,很大程度上也可以忽略这个要求。
"""
基于统计的特征选择
可以使用皮尔逊相关系数、假设检验来帮助我们进行特征选择。
皮尔逊相关系数会测量列和列之间的线性关系,该系数在-1~1之间变化,0代表没有线性关系,-1和1 代表线性关系很强。
注意:
皮尔逊相关系数要求每列是正态分布的,如果数据集很大(超过500阈值),根据中心极限定理,很大程度上也可以忽略这个要求。
"""
import pandas as pd
import numpy as np
# 利用pandas读取信用卡逾期数据集
credit_card_default = pd.read_csv("../data/credit_card_default.csv")
# 相关系数的计算
credit_card_default.corr()
# pandas的corr方法会为所有的列计算相关系数,不过这个矩阵很难读,用热图进行优化
import seaborn as sns
import matplotlib.style as style
style.use('fivethirtyeight')
sns.heatmap(credit_card_default.corr())
# 注意,heatmap会自动选择最相关的特征显示
# 特征和响应的相关性
credit_card_default.corr()['default payment next month']
# 利用pandas过滤出相关系数超过正负0.2的特征
highly_corr_features = credit_card_default.columns[
credit_card_default.corr()['default payment next month'].abs() > 0.2
].drop('default payment next month')
highly_corr_features
# 构建特征矩阵和响应变量
X = credit_card_default.drop('default payment next month', axis=1)
y = credit_card_default['default payment next month']
# 从sklearn中导入网格搜索模块
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeClassifier
# 创建一个函数,用来评估模型
def get_best_model_and_accuracy(model, params, X, y):
grid = GridSearchCV(model, # 要搜索的模型
params, # 要尝试的参数
error_score=0.0 # 如果报错,结果为0
)
# 拟合模型和参数
grid.fit(X, y)
# 经典的性能指标
print('最佳的准确率为:{}'.format(grid.best_score_))
# 得到最佳准确率的最佳参数
print('得到最佳准确率的最佳参数:{}'.format(grid.best_params_))
# 拟合的平均时间
print('拟合的平均时间:{} 秒'.format(round(grid.cv_results_['mean_fit_time'].mean(), 3)))
# 预测的平均时间
print('预测的平均时间:{} 秒'.format(round(grid.cv_results_['mean_score_time'].mean(), 3)))
# 只留下,原始数据集的5个特征,用于预测响应的变量
X_sub = X[highly_corr_features]
# 决策树
tree_params = {
'max_depth':[None, 1, 3, 5, 7]
}
d_tree = DecisionTreeClassifier()
# 决策树
get_best_model_and_accuracy(d_tree, tree_params, X_sub, y)
# 准确率为0.8213 比 之前0.8206高,拟合时间比之前0.154秒低,预测时间比之前0.002秒低。
# 模型只需要5个特征就可以学习整个数据集,而且速度快得多。
自定义一个转换器,来完成上面的逻辑
'''
将特征的相关性选择作为预处理的一部分,自定义一个转换器,来完成上面的逻辑
'''
import pandas as pd
from sklearn.base import TransformerMixin, BaseEstimator
from sklearn.pipeline import Pipeline
# 从sklearn中导入网格搜索模块
from sklearn.model_selection import GridSearchCV
# 创建一个函数,用来评估模型
def get_best_model_and_accuracy(model, params, X, y):
grid = GridSearchCV(model, # 要搜索的模型
params, # 要尝试的参数
error_score=0.0 # 如果报错,结果为0
)
# 拟合模型和参数
grid.fit(X, y)
# 经典的性能指标
print('最佳的准确率为:{}'.format(grid.best_score_))
# 得到最佳准确率的最佳参数
print('得到最佳准确率的最佳参数:{}'.format(grid.best_params_))
# 拟合的平均时间
print('拟合的平均时间:{} 秒'.format(round(grid.cv_results_['mean_fit_time'].mean(), 3)))
# 预测的平均时间
print('预测的平均时间:{} 秒'.format(round(grid.cv_results_['mean_score_time'].mean(), 3)))
class MyCorrFeaturesChooser(TransformerMixin, BaseEstimator):
def __init__(self, response, cols_to_keep=[], threshold=None):
# 保存响应变量
self.response = response
# 保存阈值
self.threshold = threshold
# 初始化一个变量,保存要保留的特征
self.cols_to_keep = cols_to_keep
def transform(self, X):
# 转换会选择合适的列
return X[self.cols_to_keep]
def fit(self, X, *_):
# 创建新的DF,存放特征和响应
df = pd.concat([X, self.response], axis=1)
# 保存高于阈值的列的名称
self.cols_to_keep = df.columns[
df.corr()[df.columns[-1]].abs() > self.threshold
]
# 只保留X,去掉response
self.cols_to_keep = [c for c in self.cols_to_keep if c in X.columns]
return self
'''
在流水线中将一切都组装起来
'''
# 利用pandas读取信用卡逾期数据集
credit_card_default = pd.read_csv("../data/credit_card_default.csv")
# 构建特征矩阵和响应变量
X = credit_card_default.drop('default payment next month', axis=1)
y = credit_card_default['default payment next month']
ccc = MyCorrFeaturesChooser(response=y)
from sklearn.tree import DecisionTreeClassifier
# 决策树
d_tree = DecisionTreeClassifier()
# 流水线
ccc_pipe = Pipeline(
[
('ccc_select', ccc),
('classifier', d_tree)
]
)
# 决策树参数
tree_pipe_params = {
'ccc_select__threshold':[0.0, 0.1, 0.2, 0.3],
'classifier__max_depth':[None, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21]
}
get_best_model_and_accuracy(ccc_pipe, tree_pipe_params, X, y)
'''
特征选择前:
最佳的准确率为:0.8206333333333333
得到最佳准确率的最佳参数:{'max_depth': 3}
拟合的平均时间:0.154 秒
预测的平均时间:0.002 秒
特征选择后:
最佳的准确率为:0.8207333333333333
得到最佳准确率的最佳参数:{'ccc_select__threshold': 0.2, 'classifier__max_depth': 3}
拟合的平均时间:0.105 秒
预测的平均时间:0.002 秒
流水线显示,如果把阈值设置为0.2,就可以消除噪声提高准确性,并且缩短拟合时间
'''
2、基于假设检验
假设检验是一种统计学方法,可以对单个特征进行复杂的统计检验。
p值是介于0到1之间的小数,代表在假设检验下,给定数据偶然出现的概率。p值越低,拒绝零假设的概率越大。
换句话说,p值越低,说明这个特征与响应变量有关联的概率就越大,我们就应该保留这个特征。
"""
基于统计的特征选择
可以使用皮尔逊相关系数、假设检验来帮助我们进行特征选择。
假设检验是一种统计学方法,可以对单个特征进行复杂的统计检验。
p值是介于0到1之间的小数,代表在假设检验下,给定数据偶然出现的概率。p值越低,拒绝零假设的概率越大。
换句话说,p值越低,说明这个特征与响应变量有关联的概率就越大,我们就应该保留这个特征。
"""
# 给定目标函数后,选择K个最高分
from sklearn.feature_selection import SelectKBest
# ANOVA测试
from sklearn.feature_selection import f_classif
# 需要注意的是,f_classif函数在每个特征上单独执行一次ANOVA测试(一种假设检验的类型),并且分配一个p值。
# SelectKBest会将特征按照p值排列(越小越好),只保留我们指定的k个最佳特征
# 实例化一个SelectKBest,设置k=5,代表希望保留5个最佳特征
k_best = SelectKBest(f_classif, k=5)
# 选择最佳特征后的矩阵
k_best.fit_transform(X, y)
# 特征和p值组成df
p_values = pd.DataFrame(
{
'column':X.columns,
'p_value':k_best.pvalues_
}
).sort_values('p_value')
# 前5个特征
p_values.head()
# p值常见的阈值是0.05,意思是可以认为p小于0.05的特征是显著的
# 查看p<0.05的特征
p_values[
p_values['p_value'] < 0.05
]
# 可以看到大部分特征的p值都很低,但不是全部。
# 查看那些列的p值较高
p_values[
p_values['p_value'] >= 0.05
]
在流水线应用SelectBest
import pandas as pd
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif
from sklearn.pipeline import Pipeline
from sklearn.tree import DecisionTreeClassifier
# 从sklearn中导入网格搜索模块
from sklearn.model_selection import GridSearchCV
# 创建一个函数,用来评估模型
def get_best_model_and_accuracy(model, params, X, y):
grid = GridSearchCV(model, # 要搜索的模型
params, # 要尝试的参数
error_score=0.0 # 如果报错,结果为0
)
# 拟合模型和参数
grid.fit(X, y)
# 经典的性能指标
print('最佳的准确率为:{}'.format(grid.best_score_))
# 得到最佳准确率的最佳参数
print('得到最佳准确率的最佳参数:{}'.format(grid.best_params_))
# 拟合的平均时间
print('拟合的平均时间:{} 秒'.format(round(grid.cv_results_['mean_fit_time'].mean(), 3)))
# 预测的平均时间
print('预测的平均时间:{} 秒'.format(round(grid.cv_results_['mean_score_time'].mean(), 3)))
# 利用pandas读取信用卡逾期数据集
credit_card_default = pd.read_csv("../data/credit_card_default.csv")
# 构建特征矩阵和响应变量
X = credit_card_default.drop('default payment next month', axis=1)
y = credit_card_default['default payment next month']
# 决策树
d_tree = DecisionTreeClassifier()
k_best = SelectKBest(f_classif)
# 建立流水线
select_k_pipe = Pipeline(
[
('k_best', k_best),
('classifier', d_tree)
]
)
# 决策树参数
tree_pipe_params = {
'k_best__k':list(range(1, 23)) + ['all'],
'classifier__max_depth':[None, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21]
}
'''
{
'k_best__k': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 'all'],
'classifier__max_depth': [None, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21]
}
'''
get_best_model_and_accuracy(select_k_pipe, tree_pipe_params, X, y)
'''
最佳的准确率为:0.8213333333333332
得到最佳准确率的最佳参数:{'classifier__max_depth': 3, 'k_best__k': 5}
拟合的平均时间:0.101 秒
预测的平均时间:0.002 秒
和自定义的转换器相比,准确率差不多,不够快了一点。
'''