toad
本文主要记录一下toad有关的学习资料,以及操作过程
先把连接放上:
github主页: https://github.com/amphibian-dev/toad
文档:https://toad.readthedocs.io
演示:https://toad.readthedocs.io/en/latest/tutorial.html
whl 下载地址: https://pypi.org/simple/toad/
报错地址:https://github.com/amphibian-dev/toad/issues
中文教程:https://toad.readthedocs.io/en/dev/tutorial_chinese.html
0.0.60更新内容:https://github.com/amphibian-dev/toad/blob/master/CHANGELOG.md
链接: https://pan.baidu.com/s/1rIaQm0XunlBU_5YXt6CXBw 提取码: fma6
操作过程
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# -*- coding: utf-8 -*- """ Created on Thu Aug 5 10:43:34 2021 @author: L """ #%%导入模块 import pandas as pd import numpy as np import toad #%%导入数据 data = pd.read_csv('D:/xxx/toad/train.csv') print('Shape:',data.shape) data.head(10) #%%数据包含2019年5月 - 7月的数据。其中我们将用3月和4月数据用于训练样本,5月、6月、7月数据作为时间外样本(OOT) train = data.loc[data.month.isin(['2019-03','2019-04'])==True,:] OOT = data.loc[data.month.isin(['2019-03','2019-04'])==False,:] print('train size:',train.shape,'\nOOT size:',OOT.shape) ''' train size: (43576, 167) OOT size: (65364, 167) ''' #%%EDA #%%1.描述性统计,可展示数值型也可以展示类别型,类别型的分位数使用频数替代 toad.detect(train) #展示的字段有 toad.detect(train).columns ''' ['type', 'size', 'missing', 'unique', 'mean_or_top1', 'std_or_top2', 'min_or_top3', '1%_or_top4', '10%_or_top5', '50%_or_bottom5', '75%_or_bottom4', '90%_or_bottom3', '99%_or_bottom2', 'max_or_bottom1'] ''' #%%2.计算变量iV , toad.quality ''' toad.quality(dataframe, target=’target’, iv_only=False) 输出每个变量的iv值,gini,entropy,和unique values,结果以iv值排序。”target”为目标列,”iv_only”决定是否只输出iv值。 注意: 1. 对于数据量大或高维度数据,建议使用iv_only=True 2. 要去掉主键,日期等高unique values且不用于建模的特征 ''' to_drop = ['APP_ID_C','month'] # 去掉ID列和month列 toad.quality(data.drop(to_drop,axis=1),'target',iv_only=True)[:15] #%%特征筛选 ''' 3. toad.selection.select(dataframe, target=’target’, empty=0.9, iv=0.02, corr=0.7, return_drop=False, exclude=None): 根据缺失值占比,iv值,和高相关性进行变量筛选,赋值为: (1)empyt=0.9: 若变量的缺失值大于0.9被删除 (2)iv=0.02: 若变量的iv值小于0.02被删除 (3)corr=0.7: 若两个相关性高于0.7时,iv值低的变量被删除 (4)return_drop=False: 若为True,function将返回被删去的变量列 (5)exclude=None: 明确不被删去的列名,输入为list格式 如下面的cell,没有变量由于缺失值高被删除,大量变量因为低iv值被删除,部分相关性高的变量被删除。从165个特征中选出了32个变量。 ''' train_selected, dropped = toad.selection.select(train,target = 'target', empty = 0.5, iv = 0.05, corr = 0.7, return_drop=True, exclude=['APP_ID_C','month']) print(dropped) print(train_selected.shape) #(43576, 34) #%%分箱 ''' toad的分箱功能支持数值型数据和离散型分箱,默认分箱方法使用 卡方分箱。 toad.transform.Combiner 是用来分箱的class,分箱步骤如下: (1) c = toad.transform.Combiner() (2) *训练分箱*: c.fit(dataframe, y = ‘target’, method = ‘chi’, min_samples = None, n_bins = None, empty_separate = False) y: 目标列 method: 分箱方法,支持’chi’ (卡方分箱), ‘dt’ (决策树分箱), ‘kmean’ , ‘quantile’ (等频分箱), ‘step’ (等步长分箱) min_samples: 每箱至少包含样本量,可以是数字或者占比 n_bins: 箱数,若无法分出这么多箱数,则会分出最多的箱数 empty_separate: 是否将空箱单独分开 (3) *查看分箱节点*:c.export() (4) *手动调整分箱*: c.load(dict) (5) *apply分箱结果*: c.transform(dataframe, labels=False): labels: 是否将分箱结果转化成箱标签。False时输出0,1,2…(离散变量根据占比高低排序),True输出(-inf, 0], (0,10], (10, inf)。 注意:1. 注意删去不需要分箱的列,特别是ID列和时间列 ''' c = toad.transform.Combiner() # 使用特征筛选后的数据进行训练:使用稳定的卡方分箱,规定每箱至少有5%数据, 空值将自动被归到最佳箱。 c.fit(train_selected.drop(to_drop, axis=1), y = 'target', method = 'chi', min_samples = 0.05) #empty_separate = False # 为了演示,仅展示部分分箱 # 注意c.export() 的结果是一个字典 print('var_d2:',c.export()['var_d2']) print('var_d5:',c.export()['var_d5']) print('var_d6:',c.export()['var_d6']) #%%观察分箱 #toad.plot的module提供了一部分的可视化功能,帮助调整分箱节点 ''' 1.*时间内观察*: toad.plot.bin_plot(dataframe, x = None, target = ‘target),bar代表了样本量占比,红线代表了正样本占比(e.g. 坏账率) x: 需要观察的特征 target: 目标列 ''' from toad.plot import bin_plot # 看'var_d2'在时间内的分箱 col = 'var_d2' bin_plot(c.transform(train_selected[[col,'target']], labels=True), x=col, target='target') ''' 2. *跨时间观察:* toad.plot.badrate_plot(dataframe, target = ‘target’, x = None, by = None) 输出不同时间段中每箱的正样本占比 - target: 目标列 - x: 时间列, string格式 - by: 需要观察的特征 注意:时间列需要预先分好并设成string,不支持timestampe ''' from toad.plot import badrate_plot col = 'var_d2' # 观察 'var_d2' 分别在时间内和OOT中的稳定性 badrate_plot(c.transform(train[[col,'target','month']], labels=True), target='target', x='month', by=col) badrate_plot(c.transform(OOT[[col,'target','month']], labels=True), target='target', x='month', by=col) badrate_plot(c.transform(data[[col,'target','month']], labels=True), target='target', x='month', by=col) ''' 敞口随时间变化而增大为优,代表了变量在更新的时间区分度更强。线之前没有交叉为优,代表分箱稳定。 ''' # 看'var_d5'在时间内的分箱 col = 'var_d5' #观察单个变量分箱结果时,建议设置'labels = True' bin_plot(c.transform(train_selected[[col,'target']], labels=True), x=col, target='target') #%%调整分箱 c.set_rules(dict) #set_rules 后会更新被修改的箱 # iv值较低,假设我们要 'F' 淡出分出一组来提高iv #设置分组 rule = {'var_d5':[['O', 'nan'],['F'], ['M']]} #调整分箱 c.set_rules(rule) #查看手动分箱稳定性 bin_plot(c.transform(train_selected[['var_d5','target']], labels=True), x='var_d5', target='target') badrate_plot(c.transform(OOT[['var_d5','target','month']], labels=True), target='target', x='month', by='var_d5') #%%WOE转化 ''' WOE转化在分箱调整好之后进行,步骤如下: 1. *用调整好的Combiner转化数据:* c.transform(dataframe, labels=False)只会转化被分箱的变量 2. *初始化woe transer:* transer = toad.transform.WOETransformer() 3. *fit_transform:* transer.fit_transform(dataframe, target, exclude = None) 训练并输出woe转化的数据,用于转化train/时间内数据 target:目标列数据(非列名) exclude: 不需要被WOE转化的列 注意:会转化所有列,包括未被分箱transform的列,通过 ‘exclude’ 删去不要WOE转化的列,特别是target列 4. *根据训练好的transer,转化test/OOT数据:*transer.transform(dataframe) ''' #根据训练好的transer输出woe转化的数据,用于转化test/OOT数据。 # 初始化 transer = toad.transform.WOETransformer() # combiner.transform() & transer.fit_transform() 转化训练数据,并去掉target列 train_woe = transer.fit_transform(c.transform(train_selected), train_selected['target'], exclude=to_drop+['target']) OOT_woe = transer.transform(c.transform(OOT)) print(train_woe.head(3)) #%%逐步回归特征刷选 toad.selection.stepwise(dataframe, target=’target’, estimator=’ols’, direction=’both’, criterion=’aic’, max_iter=None, return_drop=False, exclude=None): * ''' 逐步回归特征筛选,支持向前,向后和双向(推荐) - estimator: 用于拟合的模型,支持'ols', 'lr', 'lasso', 'ridge' - direction: 逐步回归的方向,支持'forward', 'backward', 'both' (推荐) - criterion: 评判标准,支持'aic', 'bic', 'ks', 'auc' - max_iter: 最大循环次数 - return_drop: 是否返回被剔除的列名 - exclude: 不需要被训练的列名,比如ID列和时间列 *tip: 经验证,direction = ‘both’效果最好。 estimator = ‘ols’以及criterion = ‘aic’运行速度快且结果对逻辑回归建模有较好的代表性* ''' # 将woe转化后的数据做逐步回归 final_data = toad.selection.stepwise(train_woe,target = 'target', estimator='ols', direction = 'both', criterion = 'aic', exclude = to_drop) # 将选出的变量应用于test/OOT数据 final_OOT = OOT_woe[final_data.columns] print(final_data.shape) # 逐步回归从31个变量中选出了10个 # 确定建模要用的变量 col = list(final_data.drop(to_drop+['target'],axis=1).columns) #%%计算PSI *toad.metrics.PSI(df_train, df_test):* #输出每列特征的PSI,可以用于检验WOE转化后的特征稳定性 toad.metrics.PSI(final_data[col], final_OOT[col]) #%%常用模型评分标准 toad. metrics. KS, F1, AUC # 用逻辑回归建模 from sklearn.linear_model import LogisticRegression lr = LogisticRegression() lr.fit(final_data[col], final_data['target']) # 预测训练和隔月的OOT pred_train = lr.predict_proba(final_data[col])[:,1] pred_OOT_may =lr.predict_proba(final_OOT.loc[final_OOT.month == '2019-05',col])[:,1] pred_OOT_june =lr.predict_proba(final_OOT.loc[final_OOT.month == '2019-06',col])[:,1] pred_OOT_july =lr.predict_proba(final_OOT.loc[final_OOT.month == '2019-07',col])[:,1] from toad.metrics import KS, AUC print('train KS',KS(pred_train, final_data['target'])) print('train AUC',AUC(pred_train, final_data['target'])) print('OOT结果') print('5月 KS',KS(pred_OOT_may, final_OOT.loc[final_OOT.month == '2019-05','target'])) print('6月 KS',KS(pred_OOT_june, final_OOT.loc[final_OOT.month == '2019-06','target'])) print('7月 KS',KS(pred_OOT_july, final_OOT.loc[final_OOT.month == '2019-07','target'])) ''' train KS 0.37042196076166667 train AUC 0.7506045637676994 OOT结果 5月 KS 0.36857480763524153 6月 KS 0.34764230892681874 7月 KS 0.3786493041720077 ''' #*PSI 同样可以用于验证分数的稳定性* print(toad.metrics.PSI(pred_train,pred_OOT_may)) print(toad.metrics.PSI(pred_train,pred_OOT_june)) print(toad.metrics.PSI(pred_train,pred_OOT_june)) #%%计算ks ''' *toad.metrics.KS_bucket(predicted_proba, y_true, bucket=10, method = ‘quantile’):* KS bucket输出模型预测分箱后评判信息,包括每组的分数区间,样本量,坏账率,KS等 - bucket:分箱的数量 - method:分箱方法,建议用'quantile'(等人数),或'step' (等分数步长) bad\_rate为每组坏账率: (1)组之间的坏账率差距越大越好 (2)可以用于观察是否有跳点 (3)可以用与找最佳切点 (4)可以对比 ''' # 将预测等频分箱,观测每组的区别 toad.metrics.KS_bucket(pred_train, final_data['target'], bucket=10, method = 'quantile') #%%转为评分卡 ''' toad.ScoreCard( combiner = {}, transer = None, pdo = 60, rate = 2, base_odds = 20, base_score = 750, card = None, C=0.1,kwargs): 逻辑回归模型转标准评分卡,支持传入逻辑回归参数,进行调参。 - combiner: 传入训练好的 toad.Combiner 对象 - transer: 传入先前训练的 toad.WOETransformer 对象 - pdo、rate、base_odds、base_score: e.g. pdo=60, rate=2, base_odds=20,base_score=750 实际意义为当比率为1/20,输出基准评分750,当比率为基准比率2倍时,基准分下降60分 - card: 支持传入专家评分卡 - **kwargs: 支持传入逻辑回归参数(参数详见 sklearn.linear_model.LogisticRegression) ''' card = toad.ScoreCard( combiner = c, transer = transer, #class_weight = 'balanced', #C=0.1, #base_score = 600, #base_odds = 35 , #pdo = 60, #rate = 2 ) card.fit(final_data[col], final_data['target']) #评分卡在 fit 时使用 WOE 转换后的数据来计算最终的分数,分数一旦计算完成,便无需 WOE 值,可以直接使用 原始数据 进行评分。 # 直接使用原始数据进行评分 card.predict(train) #输出标准评分卡 card.export()