变量选择详解与源码实现
文章目录
- 1.过滤法变量选择
- 1.1缺失情况变量筛选
- 1.2方差变量筛选
- 1.3预测能力变量筛选
- 1.4业务理解的变量筛选(IV、PSI)
- 1.5相关性指标变量筛选(最大相关最小冗余)
- 2.包装法变量选择
- 3.嵌入法变量选择
- 4.一般变量选择过程
- 1.基于IV值进行初步筛选
- 2.聚类分析
- 3.相关性分析
- 4.逐步回归变量选择(包装法)
- 5.随机森林或 Xgboost 模型变量重要性排序,得到最终的变量筛选结果
- 5.过滤法、包装法、嵌入法源码
- 1.读取数据区分离散变量与连续变量
- 2.对连续变量和离散变量分箱(删除分箱数只有1的)
- 3.对训练数据和测试数据做分箱映射
- 4.训练集和测试集进行WOE编码
- 5.过滤法
- 删除低变量方差
- 相关性分析(计算相关系数矩阵、画图)
- 6.包装法
- 递归消除法:SVR
- 7.嵌入法
- lr、决策树
变量选择是特征工程中非常重要的一部分。特征工程是一个先升维后降维的过程
- 升维的过程是结合业务理解尽可能多地加工特征,是一个非常耗时且需要发散思维的过程
- 变量选择就是降维的过程
因为传统评分卡模型为了保证模型的稳定性与Logisitc回归模型的准确性,往往对入模变量有非常严格的考量,并希望入模变量最好不要超过 20 个,且要与业务强相关。这时变量选择显得尤为重要,特征加工阶段往往可以得到几百维或更高维度的特征,而从诸多特征中只保留最有意义的特征也是重要且耗时的过程。
变量选择的方法很多,常用的方法有过滤法(Filter)、包装法(Wrapper)、嵌入法(Embedding),并且在上述方法中又有单变量选择、多变量选择、有监督选择、无监督选择。注意,在实际应用中,单纯从数据挖掘的角度进行变量选择是不够的,还要结合业务理解对选择后的变量进行回测,以符合业务解释,即变量选择的最终结果还要具有业务解释性,脱离了具体业务而得到的变量选择结果,即使可以达到较好的预测效果,也需要进一步推敲。
评分卡中一般根据行业经验特征最好不要超过20个,因为模型要有可解释性
1.过滤法变量选择
过滤法选择是一种与模型无关的变量选择方法,就是先进行变量选择再进行模型训练
既然与模型无关,那就要尽量从变量的预测能力及对标签的区分能力考虑,因此任何反应或衡量变量预测能力的指标都可以用于变量选择,这样的指标有信息增益、信息增益比、基尼系数、IV值等
- 从数据源角度考虑:
- 缺失值情况和自身方差情况可以进行变量选择
- 从相关性角度考虑:
- 要求最大相关、最小冗余
- 即变量与标签之间要尽可能相关性较高
- 变量与变量之间可能没有相关性,即没有多重共线性的问题
理解多重共线性
如果某一个特征可以被别的特征线性表示正常的是用这些特征(组合一个公式、模型)去表示y的,但是这些特征拟合某个x拟合的很好,这样x和y之间就出现干扰了,可能会带偏模型的参数和拟合的效果。
1.1缺失情况变量筛选
一般缺失值大于 80%就应该将该变量删除
- 对模型训练不会起太大作用
评分卡要求可解释性好,特征一般不超过20个 缺失值本身就是一种不确定性,因此那些缺失情况较多的变量不需要保留
可以对缺失值进行分享或WOE
- 缺失值在评分卡模型中是比较重要的特征
评分卡这里缺失可能不是随机缺失,很大可能是人为的故意缺失, 或者是与人的隐私相关的信息中,不填可能本身就包含某种含义
1.2方差变量筛选
低方差过滤
api: sklearn.feature_selection.VarianceThreshold(threshold = 0.0)
方差体现着波动性, 方差越小波动越小, 对模型的影响越小
1.3预测能力变量筛选
预测能力相关指标有信息增益、信息增益比、基尼系数和卡方值、IV值等。
- 信息增益
- 越大表示不确定性越好、纯度越高,对好坏的分类效果越好
- 分枝前的熵 - 分枝后的熵
- 信息增益率
- 也是越大越好
- 信息增益比 = 信息增益 / 划分前的熵
- 基尼系数
- 分类:基尼系数小好
- 回归:均方差最小
- 基尼指数(基尼不纯度)= 样本被选中的概率 \ 样本被分错的概率
- 卡方值
- 卡方值小相邻区间就合并
- 卡方值越大两个字段的差异就越大
- IV值
- IV越大说明特征越重要
- 0.02
1.4业务理解的变量筛选(IV、PSI)
这里所说的业务理解是一些可量化的客观业务指标,说白了就是可以根据公式计算的
一般可用于变量选择且与评分卡业务紧密相关的指标为 IV 值和 PSI 值
IV越大越好
- 是从类别角度考虑的,坏样本分布和好样本分布
- 超过0.5是不是异常数据
PSI越小越好
- 从时间变化角度,训练集和测试集的分布 差异越小越好,同分布最好
IV 值就是对称化的 K-L 距离,可以衡量类别分布的差异情况,反映输入变量对标签的预测能力
1.5相关性指标变量筛选(最大相关最小冗余)
准则就是最大相关和最小冗余
- 最大相关:
- x和y之间强相关
- 最小冗余
- 特征之间弱相关
皮尔逊相关系数
相关系数是计算连续变量之间的相关性如果计算离散变量与离散变量之间的相关性,则需要用卡方检验的方法或IV值
2.包装法变量选择
包装法是一种与模型相关的变量选择方法
本质就是用模型做选择
- 基本思想:
在特征空间中随机挑选特征子集,然后选择一个模型,用交叉验证测试不同子集在模型上的表现
评估方法如KS值、AR、AUC、FI等指标
- 特征子集的构建:
- 1.前向搜索
即初始随机选取一个特征构造模型,然后再随机 选择一个特征加入前一个特征子集中,构成新的特征子集,并再 建立一个模型,最后比较两个模型性能是否提升,以此来判断特 征子集的优劣
- 2.后向搜索
后向搜索与前向搜索相反,从使用特征全集开始建模,然后 每次剔除一个或多个特征,构造新的特征子集,建立新的模型, 评估两个特征子集下模型的性能,以确定最优的特征子集
- 3.双向搜索
双向搜索是将前向与后向搜索相结合的方法,初始时选择一 个变量建模,然后采用前向算法,随机选择一个变量构成由两个 变量组成的特征子集。在下一步构造特征子集的过程中,采用前 向算法进行增加特征,同时采用后向算法减少特征,直到模型的 性能不再提升,则得到最优的特征子集
3.嵌入法变量选择
与包装法类似,也是模型相关的变量选择方法,本质就是找了一个特殊的模型
常用的嵌入法选择变量方法有:
- 加入L1正则的模型
- 随机森林变量选择
- 构建树模型天然就是构建特征选择的过程
- 在评分卡模型中逻辑回归也可以做特征选择
- 分箱后的WOE编码要单调或近似单调
4.一般变量选择过程
1.基于IV值进行初步筛选
IV值越大特征越重要,也不要太大,常用0.02作为阈值
2.聚类分析
将不同特征进行聚类得到不同的簇
目的是在接下来的变量选择中,在选择剔除变量时要有簇的概念,优先从不同的簇中删除变量
3.相关性分析
最大相关最小冗余
计算变量编码后变量之间的相关性,给定
阈值进行变量剔除,剔除时要注意在不同的簇中进行选择。相关
系数的阈值不能太高,可以选择 0.6 左右。另外,也可以做方差
膨胀因子分析,剔除变量
4.逐步回归变量选择(包装法)
逐步回归是较好的一种变量选择方法,可以通过前向、后向或双向的方法进行变量选择
5.随机森林或 Xgboost 模型变量重要性排序,得到最终的变量筛选结果
也就是前面所说的嵌入法变量选择
注意,随机森林或 Xgboost 模型的变量选择并没
有考虑变量间的相关性问题,所以需要先过相关性或多重共线性
筛选后再进行变量重要性排序。通过累积贡献率的方式,或只选
择 TOP20 的变量即可。当然,也不要忽略不同簇的问题,尽量从
多维度保留入模变量的多样性
5.过滤法、包装法、嵌入法源码
1.读取数据区分离散变量与连续变量
2.对连续变量和离散变量分箱(删除分箱数只有1的)
3.对训练数据和测试数据做分箱映射
4.训练集和测试集进行WOE编码
5.过滤法
删除低变量方差
相关性分析(计算相关系数矩阵、画图)
6.包装法
递归消除法:SVR
7.嵌入法
lr、决策树
课本源码
import os
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
import variable_bin_methods as varbin_meth
import variable_encode as var_encode
import matplotlib
import matplotlib.pyplot as plt# matplotlib.use(arg='Qt5Agg')
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
from sklearn.linear_model import LogisticRegression
from sklearn.feature_selection import VarianceThreshold
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.feature_selection import RFECV
from sklearn.svm import SVR
from sklearn.feature_selection import SelectFromModel
import seaborn as sns
from sklearn.tree import DecisionTreeClassifier
from feature_selector import FeatureSelector
import warningswarnings.filterwarnings("ignore") ##忽略警告##数据读取
def data_read(data_path, file_name):df = pd.read_csv(os.path.join(data_path, file_name), delim_whitespace=True, header=None)##变量重命名columns = ['status_account', 'duration', 'credit_history', 'purpose', 'amount','svaing_account', 'present_emp', 'income_rate', 'personal_status','other_debtors', 'residence_info', 'property', 'age','inst_plans', 'housing', 'num_credits','job', 'dependents', 'telephone', 'foreign_worker', 'target']df.columns = columns##将标签变量由状态1,2转为0,1;0表示好用户,1表示坏用户df.target = df.target - 1##数据分为data_train和 data_test两部分,训练集用于得到编码函数,验证集用已知的编码规则对验证集编码data_train, data_test = train_test_split(df, test_size=0.2, random_state=0, stratify=df.target)return data_train, data_test##离散变量与连续变量区分
def category_continue_separation(df, feature_names):categorical_var = []numerical_var = []if 'target' in feature_names:feature_names.remove('target')##先判断类型,如果是int或float就直接作为连续变量numerical_var = list(df[feature_names].select_dtypes(include=['int', 'float', 'int32', 'float32', 'int64', 'float64']).columns.values)categorical_var = [x for x in feature_names if x not in numerical_var]return categorical_var, numerical_varif __name__ == '__main__':path = r'G:\A_实训前置1\python_workspace\finance_code\chapter7'data_path = os.path.join(path, 'data')file_name = 'german.csv'##读取数据data_train, data_test = data_read(data_path, file_name)sum(data_train.target == 0)data_train.target.sum()##区分离散变量与连续变量feature_names = list(data_train.columns)feature_names.remove('target')categorical_var, numerical_var = category_continue_separation(data_train, feature_names)for s in set(numerical_var):print('变量' + s + '可能取值' + str(len(data_train[s].unique())))if len(data_train[s].unique()) <= 10:categorical_var.append(s)numerical_var.remove(s)##同时将后加的数值变量转为字符串index_1 = data_train[s].isnull()if sum(index_1) > 0:data_train.loc[~index_1, s] = data_train.loc[~index_1, s].astype('str')else:data_train[s] = data_train[s].astype('str')index_2 = data_test[s].isnull()if sum(index_2) > 0:data_test.loc[~index_2, s] = data_test.loc[~index_2, s].astype('str')else:data_test[s] = data_test[s].astype('str')###连续变量分箱dict_cont_bin = {}for i in numerical_var:print(i)dict_cont_bin[i], gain_value_save, gain_rate_save = varbin_meth.cont_var_bin(data_train[i], data_train.target,method=2, mmin=3, mmax=12,bin_rate=0.01, stop_limit=0.05,bin_min_num=20)###离散变量分箱dict_disc_bin = {}del_key = []for i in categorical_var:dict_disc_bin[i], gain_value_save, gain_rate_save, del_key_1 = varbin_meth.disc_var_bin(data_train[i],data_train.target,method=2, mmin=3,mmax=8, stop_limit=0.05,bin_min_num=20)if len(del_key_1) > 0:del_key.extend(del_key_1)###删除分箱数只有1个的变量if len(del_key) > 0:for j in del_key:del dict_disc_bin[j]##训练数据分箱##连续变量分箱映射df_cont_bin_train = pd.DataFrame()for i in dict_cont_bin.keys():df_cont_bin_train = pd.concat([df_cont_bin_train, varbin_meth.cont_var_bin_map(data_train[i], dict_cont_bin[i])], axis=1)##离散变量分箱映射# ss = data_train[list( dict_disc_bin.keys())]df_disc_bin_train = pd.DataFrame()for i in dict_disc_bin.keys():df_disc_bin_train = pd.concat([df_disc_bin_train, varbin_meth.disc_var_bin_map(data_train[i], dict_disc_bin[i])], axis=1)##测试数据分箱##连续变量分箱映射df_cont_bin_test = pd.DataFrame()for i in dict_cont_bin.keys():df_cont_bin_test = pd.concat([df_cont_bin_test, varbin_meth.cont_var_bin_map(data_test[i], dict_cont_bin[i])],axis=1)##离散变量分箱映射# ss = data_test[list( dict_disc_bin.keys())]df_disc_bin_test = pd.DataFrame()for i in dict_disc_bin.keys():df_disc_bin_test = pd.concat([df_disc_bin_test, varbin_meth.disc_var_bin_map(data_test[i], dict_disc_bin[i])],axis=1)###组成分箱后的训练集与测试集df_disc_bin_train['target'] = data_train.targetdata_train_bin = pd.concat([df_cont_bin_train, df_disc_bin_train], axis=1)df_disc_bin_test['target'] = data_test.targetdata_test_bin = pd.concat([df_cont_bin_test, df_disc_bin_test], axis=1)data_train_bin.reset_index(inplace=True, drop=True)data_test_bin.reset_index(inplace=True, drop=True)###WOE编码var_all_bin = list(data_train_bin.columns)var_all_bin.remove('target')##训练集WOE编码df_train_woe, dict_woe_map, dict_iv_values, var_woe_name = var_encode.woe_encode(data_train_bin, data_path,var_all_bin, data_train_bin.target,'dict_woe_map', flag='train')##测试集WOE编码df_test_woe, var_woe_name = var_encode.woe_encode(data_test_bin, data_path, var_all_bin, data_test_bin.target,'dict_woe_map', flag='test')y = np.array(data_train_bin.target)###过滤法特征选择##方差筛选df_train_woe = df_train_woe[var_woe_name]len_1 = df_train_woe.shape[1]select_var = VarianceThreshold(threshold=0.01)select_var_model = select_var.fit(df_train_woe)df_1 = pd.DataFrame(select_var_model.transform(df_train_woe))##保留的索引save_index = select_var.get_support(True)var_columns = [list(df_train_woe.columns)[x] for x in save_index]df_1.columns = var_columns##删除变量的方差select_var.variances_[[x for x in range(len_1) if x not in save_index]][list(df_train_woe.columns)[x] for x in range(len_1) if x not in save_index][select_var.variances_[x] for x in range(len_1) if x not in save_index]##单变量筛选select_uinvar = SelectKBest(score_func=f_classif, k=15)select_uinvar_model = select_uinvar.fit(df_train_woe, y)df_1 = select_uinvar_model.transform(df_train_woe)##看得分len_1 = len(select_uinvar_model.scores_)var_name = [str(x).split('_BIN_woe')[0] for x in list(df_train_woe.columns)]##plt.figure(figsize=(10, 6))fontsize_1 = 14plt.barh(np.arange(0, len_1), select_uinvar_model.scores_, color='c', tick_label=var_name)plt.xticks(fontsize=fontsize_1)plt.yticks(fontsize=fontsize_1)plt.xlabel('得分', fontsize=fontsize_1)plt.show()##分析变量相关性##计算相关矩阵correlations = abs(df_train_woe.corr())##相关性绘图fig = plt.figure(figsize=(10, 6))fontsize_1 = 10sns.heatmap(correlations, cmap=plt.cm.Greys, linewidths=0.05, vmax=1, vmin=0, annot=True,annot_kws={'size': 6, 'weight': 'bold'})plt.xticks(np.arange(20) + 0.5, var_name, fontsize=fontsize_1, rotation=20)plt.yticks(np.arange(20) + 0.5, var_name, fontsize=fontsize_1)plt.title('相关性分析')# plt.xlabel('得分',fontsize=fontsize_1)plt.show()##包装法变量选择:递归消除法##给定学习器estimator = SVR(kernel="linear")##递归消除法select_rfecv = RFECV(estimator, step=1, cv=3)select_rfecv_model = select_rfecv.fit(df_train_woe, y)df_1 = pd.DataFrame(select_rfecv_model.transform(df_train_woe))##查看结果select_rfecv_model.support_select_rfecv_model.n_features_select_rfecv_model.ranking_###嵌入法变量选择##选择学习器lr = LogisticRegression(C=0.1, penalty='l2')##嵌入法变量选择select_lr = SelectFromModel(lr, prefit=False, threshold='mean')select_lr_model = select_lr.fit(df_train_woe, y)df_1 = pd.DataFrame(select_lr_model.transform(df_train_woe))##查看结果select_lr_model.threshold_select_lr_model.get_support(True)##基学习器选择预训练的决策树来进行变量选择##先训练决策树cart_model = DecisionTreeClassifier(criterion='gini', max_depth=3).fit(df_train_woe, y)cart_model.feature_importances_##用预训练模型进行变量选择select_dt_model = SelectFromModel(cart_model, prefit=True)df_1 = pd.DataFrame(select_dt_model.transform(df_train_woe))##查看结果select_dt_model.get_support(True)###集成学习下的变量选择lightgbmfs = FeatureSelector(data=df_train_woe, labels=y)##设置筛选参数fs.identify_all(selection_params={'missing_threshold': 0.9,'correlation_threshold': 0.6,'task': 'classification','eval_metric': 'binary_error','max_depth': 2,'cumulative_importance': 0.90})df_train_woe = fs.remove(methods='all')##查看结果fs.feature_importancesfs.corr_matrixfs.record_low_importance
变量选择详解与源码实现相关推荐
- 详解 Python 源码之对象机制
在Python中,对象就是在堆上申请的结构体,对象不能是被静态初始化的,并且也不能是在栈空间上生存的.唯一的例外就是类型对象(type object),Python中所有的类型对象都是被静态初始化的. ...
- RN FlatList使用详解及源码解析
FlatList使用详解及源码解析 前言 长列表或者无限下拉列表是最常见的应用场景之一.RN 提供的 ListView 组件,在长列表这种数据量大的场景下,性能堪忧.而在最新的 0.43 版本中,提供 ...
- hadoop作业初始化过程详解(源码分析第三篇)
(一)概述 我们在上一篇blog已经详细的分析了一个作业从用户输入提交命令到到达JobTracker之前的各个过程.在作业到达JobTracker之后初始化之前,JobTracker会通过submit ...
- spark RDD详解及源码分析
spark RDD详解及源码分析 @(SPARK)[spark] spark RDD详解及源码分析 一基础 一什么是RDD 二RDD的适用范围 三一些特性 四RDD的创建 1由一个已经存在的scala ...
- spark 调度模块详解及源码分析
spark 调度模块详解及源码分析 @(SPARK)[spark] spark 调度模块详解及源码分析 一概述 一三个主要的类 1class DAGScheduler 2trait TaskSched ...
- okhttp的应用详解与源码解析--http的发展史
乘5G之势,借物联网之风,Android未来亦可期,Android优势在于开放,手机.平板.车载设备.智能家居等都是Android的舞台,Google不倒,Android不灭,本专栏的同步视频教程已经 ...
- Android应用Context详解及源码解析
[工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果] 1 背景 今天突然想起之前在上家公司(做TV与BOX盒子)时有好几个人问过我关于Android ...
- SpringMVC异常处理机制详解[附带源码分析]
SpringMVC异常处理机制详解[附带源码分析] 参考文章: (1)SpringMVC异常处理机制详解[附带源码分析] (2)https://www.cnblogs.com/fangjian0423 ...
- 详解LAMP源码编译安装
实战:LAMP源码编译安装 家住海边喜欢浪:zhang789.blog.51cto.com 目录 详解LAMP源码编译安装 LAMP简介 一.准备工作 二.编译安装 Apache 三.编译安装 MyS ...
- FPGA学习之路—接口(2)—I2C协议详解+Verilog源码分析
FPGA学习之路--I2C协议详解+Verilog源码分析 定义 I2C Bus(Inter-Integrated Circuit Bus) 最早是由Philips半导体(现被NXP收购)开发的两线时 ...
最新文章
- MyEclipse极速优化
- Android Studio的技巧
- SOAMANAGER配置后无法登录问题
- 「转型新范式」第四范式2021发布会全程直播倒计时
- 如何记忆英语的成语、俗语等
- mysql怎么访问用户B_MySQL访问控制和用户管理
- mysql复制的工作原理及主从复制的实现
- android listpreference 自定义,Android中Fragmen首选项使用自定义的ListPreference的方法
- 拉格朗日中值定理ξ怎么求_【实力干货】!!!高中数学教材之外的常用定理和公式!!!...
- educoder软件工程导论结构化分析方法
- java中gc是什么_java什么是gc
- 基于极狐GitLab OpenAPI 开发一个仿dbt的版本管理WebIDE
- 追加安装sticky模块
- Windows 下TSI721驱动软件使用
- 土方量方lisp_时隔3年,再做双倍超立方数的题目,这次用Lisp
- 曾经人见人爱花见花开的zookeeper为啥突然不香了呢
- 【历史上的今天】8 月 5 日:微信 5.0 发布;百度上市;LinkedIn 创始人诞生
- [转]gps中的广义和狭义相对论效应
- 人文素质与企业竞争力
- 求cos(x)的值(java实现)
热门文章
- Java虚拟机(JVM)学习合集
- 漫画:鉴权与安全访问控制的技术血脉
- 2021厦大计算机考研炸了,【图片】一战厦大计算机上岸,经验帖。慢更【考研吧】_百度贴吧...
- codeforces 268E Playlist(数学期望)
- 拼多多推广效果不好,哪里需要改善?
- 第三十二章 三更雪压飞狐城(三之全)
- 有一种冲动:世界那么大
- vsCode自动保存与浏览器自动刷新
- BUG(12) : Configured service account doesn‘t have access. Service account may have been revoked. pod
- 使用Laya引擎开发微信小游戏(上)