运营商建模小结
出差9天,7个工作日,高强度建模,对这次出差建模进行一下小结。
我们最初接触到的数据很原始,分5张表,每张表是客户T-1月到T-4月的数据,5张表大致是用户基础信息画像、用户消费情况画像、用户国际漫游情况、集团客户情况、用户终端情况。首先的任务就是数据清洗,制作变量宽表,因为一笔贷款正常来说对应4个月的数据,所以需要转置或者groupby,其实转置并没有必要,因为业务上来讲,时间窗口是从近及远不断扩大的,比如前1月,前2月,前3月,很少听说前第2月,前第3月,其实穷途末路的时候,我也尝试过前第3月/前第2月这种时间窗口,有些变量还是很突出,但是总体效果并没有太大提升。所以最有用的是groupby,但是我也尝试了行列转置的方法,行列转置用到pandas的pivot方法,pivot方法设定一个index参数,比如用rid,转置,然后确定需要转的列columns,我这个问题上是月份,然后去重命名变量名就可以了。groupby就是和上次jdd比赛类似,肯定是写函数批量做变量,但是我开始想得太细了,而且没有函数化,而我同事抽象得很简单,一个函数分成前1月,前2月,前3月,然后区分连续变量和分类变量,连续变量就算6个描述性统计量,分类变量就只取前1月的数据,这种抽象实现起来就非常快,我当时想得太细,就有各种独特的时间窗口和聚合方法,其实应该特殊就特殊处理,或者如果泛化的包含了特殊,程序效率方面没问题,就全部做出来也无妨!对于前一月,前二月,前三月记录数不等,应该用全部的人去left join,如果不考虑和同事配合的问题,也可以用要建模的人去join,写成函数的一个参数,和同事配合,比如60002单独生成一张宽表比较好。当时我们花了2天半的时间做好变量,然后着手建模,建模评分卡过程中遇到很多python3环境下水土不服的情况,我不断修改自己框架,我安装的seaborn也水土不服,我回滚到当年我最老的画图函数,从修改自己框架过程中我也发现了很多自己框架的问题以及python2和python3的不同之处,python3最明显的不同是print,dict.keys()并不是生成tuple而是专门的dict_keys类,dict.items()也是生成一个专有的类,所以类似dict.keys()[0]的索引方式就会报错,python3我还发现一点不同的地方,就是比如在dict.keys()的迭代过程不能dict.pop(),也就是循环过程中不能动态的改变dict的结构。还有什么不同吗?还有就是我发现我本身regroup逻辑上不对,这里在python3中直接报错,因为字符串和float或者int参与了比较,python3直接会报异常,在python2中一个字符串比任何数字类型都大,所以在python2中我的regroup代码并不会报错,但是最后实现的却是前开后闭,我做了一个改动同时解决了两个问题,就是类似于我的分箱函数一样,copy一份出来再进行条件筛选,改变原来df的值,然后这里再说一点,比如一个int类型Series,某个元素被赋值成字符串,那么整个Series的Dtype就是object,但是具体到每个元素,可能有long型,有str型,这个时候如果用Series.astype(str),那么全部元素都变成str型,Series的dtype还是object。解决了scorecard问题后,有了基本结果,当时平均AUC才0.62几,训练集上的CV在接近0.71,当时训练集还是我的老坏客户定义,任意一期逾期30天会坏,前三期都小于10天为好,从单变量的角度,这种剔除灰色部分样本,的确可以增强变量的区隔能力,比如更大的IV。当时对方的结果也没出来,我就去广州玩了,后来才发现效果并不如他的好!星期一回来上午做了lightGBM和xgboost的尝试,效果并不理想,包括CV的结果最好的也就比评分卡高2个百分点,进行了一些参数优化,效果还是不理想,由于时间有限就暂时放弃了lgb和xgb,下午看到对方的结果有些震惊,好在同事发现了一些好用的衍生变量,他通过精简变量和加入新的衍生变量,测试集上的AUC已经达到了0.65,我当天也在不断尝试优化评分卡试图超过geo的结果,我开始用Y1来建模,效果居然提升了2个点,非常不可思议,这颠覆了我以往的观念,我从消费信贷建模一书中读到建模的时候要去掉灰色地带客户,而且我本人认为y定义最好接近于真正的坏客户定义,但是这一切都被实践打脸了,我后来是用real y划定的分组,然后用有Y1去训练,从道理上讲,这种操作有一定的抗过拟合的意思,这个时候我在测试集上得到了0.642的效果,但是差geo还差一点儿,差我同事就差更多,我当天也比较郁闷,我打算主要就用我同事的方案了,但是第二天我加入了同事的变量唯一主叫号码数/总号码数,想不到这是一个golden feature,直接让我效果达到了0.651,但是这个变量最后段存在拐弯的地方,我regroup了一下,效果达到了0.6539,已经超越了geo1个多百分点,终于长舒了一口气,这里还有一点我同事写了KS的计算,我之前还打算手算,其实用python现成的轮子,一排代码就搞定了,from sklearn.metrics import roc_curve ; fpr, tpr, thre = roc_curve(y,pred); tpr就是累计的bad占比,fpr就是累计的good占比,所以ks = abs(fpr-tpr).max(),这里abs可以用于np.array,很奇怪,按理说应该用np.abs,再然后,我开始考虑融合v71模型和这个运营商模型,我先算了下V71模型的AUC在0.657,我首先采用最简单的融合方式,线性加合在一起,我根据两个模型probability的范围,拍脑袋确定了,两个的系数,第一次融合就达到了0.689,后面稍微调一下权重,AUC达到0.69,ks 0.3,超出我预期的一个结果,说明两个模型互补性非常好。另外一方面如果采用自己的自变量和运营商自变量的组合这种方式,只有3月1日到5月25日的样本用于建模,偏少,v71和运营商评分的stacking,也只能用3月1日到5月25日的样本进行建模,除了两个分的拍脑袋线性组合,我还采取了矩阵策略,V71 decile和运营商模型decile,进行10*10的组合,其实道理上讲,这种组合方式也可以变成训练和测试的方式,先不在测试集上进行10*10的组合,在训练集上组合好确定好规则,测试集上看效果,这里训练集甚至可以用7月16日之后的数据,还有就是测试集上的效果就没法计算AUC,因为是一种10*10的形式,没办法rank order,那如何看呢?只能看看这些cell的逾期率如何,是否稳定。所以我最后两套方案,一套是保守的ensemble后,取TOP 1/20,一种是matrix策略,难以降低逾期,但是可以在保证逾期不变的情况下,放更多客户,这是一个trade off,确定了方案后,后面就是代码整理,程序和文档交付之类的,历时9天,7个工作日完美杀青!
我们最初接触到的数据很原始,分5张表,每张表是客户T-1月到T-4月的数据,5张表大致是用户基础信息画像、用户消费情况画像、用户国际漫游情况、集团客户情况、用户终端情况。首先的任务就是数据清洗,制作变量宽表,因为一笔贷款正常来说对应4个月的数据,所以需要转置或者groupby,其实转置并没有必要,因为业务上来讲,时间窗口是从近及远不断扩大的,比如前1月,前2月,前3月,很少听说前第2月,前第3月,其实穷途末路的时候,我也尝试过前第3月/前第2月这种时间窗口,有些变量还是很突出,但是总体效果并没有太大提升。所以最有用的是groupby,但是我也尝试了行列转置的方法,行列转置用到pandas的pivot方法,pivot方法设定一个index参数,比如用rid,转置,然后确定需要转的列columns,我这个问题上是月份,然后去重命名变量名就可以了。groupby就是和上次jdd比赛类似,肯定是写函数批量做变量,但是我开始想得太细了,而且没有函数化,而我同事抽象得很简单,一个函数分成前1月,前2月,前3月,然后区分连续变量和分类变量,连续变量就算6个描述性统计量,分类变量就只取前1月的数据,这种抽象实现起来就非常快,我当时想得太细,就有各种独特的时间窗口和聚合方法,其实应该特殊就特殊处理,或者如果泛化的包含了特殊,程序效率方面没问题,就全部做出来也无妨!对于前一月,前二月,前三月记录数不等,应该用全部的人去left join,如果不考虑和同事配合的问题,也可以用要建模的人去join,写成函数的一个参数,和同事配合,比如60002单独生成一张宽表比较好。当时我们花了2天半的时间做好变量,然后着手建模,建模评分卡过程中遇到很多python3环境下水土不服的情况,我不断修改自己框架,我安装的seaborn也水土不服,我回滚到当年我最老的画图函数,从修改自己框架过程中我也发现了很多自己框架的问题以及python2和python3的不同之处,python3最明显的不同是print,dict.keys()并不是生成tuple而是专门的dict_keys类,dict.items()也是生成一个专有的类,所以类似dict.keys()[0]的索引方式就会报错,python3我还发现一点不同的地方,就是比如在dict.keys()的迭代过程不能dict.pop(),也就是循环过程中不能动态的改变dict的结构。还有什么不同吗?还有就是我发现我本身regroup逻辑上不对,这里在python3中直接报错,因为字符串和float或者int参与了比较,python3直接会报异常,在python2中一个字符串比任何数字类型都大,所以在python2中我的regroup代码并不会报错,但是最后实现的却是前开后闭,我做了一个改动同时解决了两个问题,就是类似于我的分箱函数一样,copy一份出来再进行条件筛选,改变原来df的值,然后这里再说一点,比如一个int类型Series,某个元素被赋值成字符串,那么整个Series的Dtype就是object,但是具体到每个元素,可能有long型,有str型,这个时候如果用Series.astype(str),那么全部元素都变成str型,Series的dtype还是object。解决了scorecard问题后,有了基本结果,当时平均AUC才0.62几,训练集上的CV在接近0.71,当时训练集还是我的老坏客户定义,任意一期逾期30天会坏,前三期都小于10天为好,从单变量的角度,这种剔除灰色部分样本,的确可以增强变量的区隔能力,比如更大的IV。当时对方的结果也没出来,我就去广州玩了,后来才发现效果并不如他的好!星期一回来上午做了lightGBM和xgboost的尝试,效果并不理想,包括CV的结果最好的也就比评分卡高2个百分点,进行了一些参数优化,效果还是不理想,由于时间有限就暂时放弃了lgb和xgb,下午看到对方的结果有些震惊,好在同事发现了一些好用的衍生变量,他通过精简变量和加入新的衍生变量,测试集上的AUC已经达到了0.65,我当天也在不断尝试优化评分卡试图超过geo的结果,我开始用Y1来建模,效果居然提升了2个点,非常不可思议,这颠覆了我以往的观念,我从消费信贷建模一书中读到建模的时候要去掉灰色地带客户,而且我本人认为y定义最好接近于真正的坏客户定义,但是这一切都被实践打脸了,我后来是用real y划定的分组,然后用有Y1去训练,从道理上讲,这种操作有一定的抗过拟合的意思,这个时候我在测试集上得到了0.642的效果,但是差geo还差一点儿,差我同事就差更多,我当天也比较郁闷,我打算主要就用我同事的方案了,但是第二天我加入了同事的变量唯一主叫号码数/总号码数,想不到这是一个golden feature,直接让我效果达到了0.651,但是这个变量最后段存在拐弯的地方,我regroup了一下,效果达到了0.6539,已经超越了geo1个多百分点,终于长舒了一口气,这里还有一点我同事写了KS的计算,我之前还打算手算,其实用python现成的轮子,一排代码就搞定了,from sklearn.metrics import roc_curve ; fpr, tpr, thre = roc_curve(y,pred); tpr就是累计的bad占比,fpr就是累计的good占比,所以ks = abs(fpr-tpr).max(),这里abs可以用于np.array,很奇怪,按理说应该用np.abs,再然后,我开始考虑融合v71模型和这个运营商模型,我先算了下V71模型的AUC在0.657,我首先采用最简单的融合方式,线性加合在一起,我根据两个模型probability的范围,拍脑袋确定了,两个的系数,第一次融合就达到了0.689,后面稍微调一下权重,AUC达到0.69,ks 0.3,超出我预期的一个结果,说明两个模型互补性非常好。另外一方面如果采用自己的自变量和运营商自变量的组合这种方式,只有3月1日到5月25日的样本用于建模,偏少,v71和运营商评分的stacking,也只能用3月1日到5月25日的样本进行建模,除了两个分的拍脑袋线性组合,我还采取了矩阵策略,V71 decile和运营商模型decile,进行10*10的组合,其实道理上讲,这种组合方式也可以变成训练和测试的方式,先不在测试集上进行10*10的组合,在训练集上组合好确定好规则,测试集上看效果,这里训练集甚至可以用7月16日之后的数据,还有就是测试集上的效果就没法计算AUC,因为是一种10*10的形式,没办法rank order,那如何看呢?只能看看这些cell的逾期率如何,是否稳定。所以我最后两套方案,一套是保守的ensemble后,取TOP 1/20,一种是matrix策略,难以降低逾期,但是可以在保证逾期不变的情况下,放更多客户,这是一个trade off,确定了方案后,后面就是代码整理,程序和文档交付之类的,历时9天,7个工作日完美杀青!
留言
張貼留言