作者:小伍哥
来源:小伍哥聊风控
本文重点:风控策略挖掘、策略推荐,策略发现,风控策略自动化,决策树
下面开始正文:
风控策略同学在挖掘有效的风控规则的时候,经常需要基于业务经验,将那几个特征进行组合形成风控策略,会导致在特征组合的时候浪费大量的时间,我们有没有什么方法,替代人工的分析,直接得出策略组合呢,决策树就是其中的一个选择,可以实现自动化的挖掘大批量的策略组合。
在众多的算法中,决策树整体分类准确率不高,但是部分叶子节点的准确率却可以很高,因此我们可以提取决策树的叶子规则,并筛选准确率比较高的叶子节点,作为风控策略挖掘手段,并进行策略推荐,替代人工或者辅助人工,大大提高策略发现的效率于效果。
本文介绍了如何在风控策略中使用决策树算法来挖掘有效的规则,并会分享自己编写的提取函数,此套代码会在极短的时间挖掘上千条规则,快速且有效,目标就是:风控策略自动化,然后干掉自己。
策略节选
一、数据说明及读取
1、数据集信息
数据从真实场景和实际应用出发,利用个人的基本身份信息、个人的住房公积金缴存和贷款等数据信息,来建立准确的风险控制模型,来预测用户是否会逾期还款。一共提供了40000带标签训练集样本,数据仅有一张表,一共有19个基本特征,且均不包含任何缺失值。
2、数据属性信息
标签:label是否逾期(是 = 1,否 = 0)。
特征:包含以下19个变量,名称和含义如下。
3、读取数据
#数据读取import pandas as pdimport numpy as nppd.set_option('display.max_columns', None)#显示所有的列path = '/Users/wuzhengxiang/Documents/DataSets/RizhaoGongJiJin/train.csv'train = pd.read_csv(path).fillna(-1)train.columnsIndex(['id', 'XINGBIE', 'CSNY', 'HYZK', 'ZHIYE', 'ZHICHEN', 'ZHIWU', 'XUELI', 'DWJJLX', 'DWSSHY', 'GRJCJS', 'GRZHZT', 'GRZHYE', 'GRZHSNJZYE', 'GRZHDNGJYE', 'GRYJCE', 'DWYJCE', 'DKFFE', 'DKYE', 'DKLL', 'label'], dtype='object')
train.head()#查看前面的数据 id XINGBIE CSNY HYZK ZHIYE ZHICHEN ZHIWU XUELI DWJJLX train_0 1 1038672000 90 90 999 0 99 150 1 train_1 2 504892800 90 90 999 0 99 110 2 train_2 1 736185600 90 90 999 0 99 150 3 train_3 1 428515200 90 90 999 0 99 150 4 train_4 2 544204800 90 90 999 0 99 900 DWSSHY GRJCJS GRZHZT GRZHYE GRZHSNJZYE GRZHDNGJYE GRYJCE 12 1737.0 1 3223.515 801.310 837.000 312.00 1 0 4894.0 1 18055.195 53213.220 1065.200 795.84 2 9 10297.0 1 27426.600 13963.140 7230.020 1444.20 3 7 10071.5 1 111871.130 99701.265 2271.295 1417.14 4 14 2007.0 1 237.000 11028.875 35.780 325.50 DWYJCE DKFFE DKYE DKLL label 0 312.00 175237 154112.935 2.708 0 1 795.84 300237 298252.945 2.979 0 2 1444.20 150237 147339.130 2.708 0 3 1417.14 350237 300653.780 2.708 0 4 325.50 150237 145185.010 2.708 0 #构建训练集X = train.loc[:,'XINGBIE':'DKLL']Y = train['label']
二、构建决策树
训练一个决策树,这里限制了最大深度和最小样本树from sklearn import treeclf = tree.DecisionTreeClassifier( max_depth=3, min_samples_leaf=50 )clf = clf.fit(X, Y)
三、决策树的可视化
决策树可视化的方案比较多,都写出来给对比看看,推荐第二种和第三种。对决策树进行可视化,是非常有必要的,能够帮助我们自己充分理解决策树的生成过程,如果是风控,也有利于咱们给业务部门解释数据和结果。
1、plot_tree(太丑,不推荐)
#包里自带的,有点丑tree.plot_tree(clf)plt.show()
2、graphviz对决策树进行可视化
如果搜索“可视化决策树”,很快便能找到由scikit提供的基于Python语言的解决方案:
sklearn.tree.export_graphviz,这个也是最常用的解决方案
import graphviz dot_data = tree.export_graphviz( clf, out_file=None, feature_names=X.columns, class_names=['good','bad'], filled=True, rounded=True, special_characters=True) graph = graphviz.Source(dot_data) graph
生成的决策树解释
1)samples:节点中观察的数量,比如根节点40000,表示数据集总共有4万个样本
2)有多少种类别,整棵树的叶子就有多少种颜色,比如我们这里有2个类别,颜色对应是黄、绿、Gini指数越小,该节点颜色越深,也就是纯度越高。
3)value表示当前节点2种类别的样本有多少,比如下面第一棵树的根节点,value = [37243,2757],表示有37243个好样本,2757坏样本
4)class表示当前那个类别的样本最多,比如下面最右边的一棵树的根节点,class = bad,可以看到当前节点它的坏样本数是最多的。
5)gini:节点的基尼不纯度。当沿着树向下移动时,平均加权的基尼不纯度必须降低。
3、dtreeviz对决策树进行可视化
dtreeviz是我认为非常完美的决策树可视化的包,非常好理解,也非常美观。下面我们看看这个包可视化的结果。
from dtreeviz.trees import dtreeviz testX = X.iloc[77,:] viz = dtreeviz(clf,X,Y, feature_names=np.array(X.columns), class_names={0:'good',1:'bad'}, X = testX) viz.view()
我们把树的深度再加深到5看看,树更复杂了from sklearn import treeclf = tree.DecisionTreeClassifier( max_depth=5, min_samples_leaf=50 )clf = clf.fit(X, Y) from dtreeviz.trees import dtreeviz testX = X.iloc[77,:] viz = dtreeviz(clf,X,Y, feature_names=np.array(X.columns), class_names={0:'good',1:'bad'}, X = testX) viz.view()
也可以横向展示
viz = dtreeviz(clf,X,Y, orientation ='LR', # left-right orientation feature_names=np.array(X.columns), class_names={0:'good',1:'bad'}, X = testX) viz.view()#如果只想可视化预测路径,则需要设置参数 show_just_path=True
viz = dtreeviz(clf,X,Y, feature_names=np.array(X.columns), class_names={0:'good',1:'bad'}, orientation ='LR', # left-right orientation show_just_path=True, X = testX) viz.view()
只展示了预测的路径
有了决策树的可视化,我们就能直接得到每条策略了,当时人为的看,效率还是比较低,我们需要更高效的方式,对数据决策树上的信息进行提取,直接得到规则。
四、决策规则提取
1、决策树的生成的结构探索
要提取出来其中的规则,我们需要探索决策树的存储结构,为了探究sklearn中决策树是如何设计和实现的,以分类决策树为例,首先看下决策树都内置了哪些属性和接口:通过dir属性查看一颗初始的决策树都包含了哪些属性(这里过滤掉了以"_"开头的属性,因为一般是内置私有属性),得到结果如下:
from sklearn.datasets import load_irisfrom sklearn import treeiris = load_iris()clf = tree.DecisionTreeClassifier()clf = clf.fit(iris.data, iris.target)clf.classes_[x for x in dir(clf) if not x.startswith('_')]
大致浏览上述结果,属性主要是决策树初始化时的参数,例如ccp_alpha:剪枝系数,class_weight:类的权重,criterion:分裂准则等;还有就是决策树实现的主要函数,例如fit:模型训练,predict:模型预测等等。
本文的重点是探究决策树中是如何保存训练后的"那颗树",所以我们进一步用鸢尾花数据集对决策树进行训练一下,而后再次调用dir函数,看看增加了哪些属性和接口:
本文的重点是探究决策树中是如何保存训练后的"那颗树",所以我们进一步用鸢尾花数据集对决策树进行训练一下,而后再次调用dir函数,看看增加了哪些属性和接口:
通过集合的差集,很明显看出训练前后的决策树主要是增加了6个属性(都是属性,而非函数功能),其中通过属性名字也很容易推断其含义:
那我们对这个tree_属性做进一步探究,首先打印该tree_属性发现,这是一个Tree对象,并给出了在sklearn中的文件路径:
通过上述doc文档,其中第一句就很明确的对决策树做了如下描述:
- Array-based representation of a binary decision tree.
即:基于数组表示的二分类决策树,也就是二叉树!进一步地,在这个二叉树中,数组的第i个元素代表了决策树的第i个节点的信息,节点0表示决策树的根节点。那么每个节点又都蕴含了什么信息呢?我们注意到上述文档中列出了节点的文件名:_tree.pxd,查看其中,很容易发现节点的定义如下:
虽然是cython的定义语法,但也不难推断其各属性字段的类型和含义,例如:
至此,决策树中单个节点的属性定义和实现基本推断完毕,那么整个决策树又是如何将所有节点串起来的呢?我们再次诉诸于训练后决策树的tree_属性,看看它都哪些接口,仍然过滤掉内置私有属性,得到如下结果:
# 决策树结构探索
dir(clf.tree_)['apply','capacity', 'children_left','children_right', 'compute_feature_importances','compute_partial_dependence', 'decision_path','feature', 'impurity','max_depth', 'max_n_classes','n_classes', 'n_features','n_leaves', 'n_node_samples','n_outputs','node_count', 'predict','threshold', 'value', 'weighted_n_node_samples']
大概比较重要的就是这些了!为了进一步理解各属性中的数据是如何存储的,我们仍以鸢尾花数据集为例,训练一个max_depth=2的决策树(根节点对应depth=0),并查看如下取值:
clf.tree_.children_leftclf.tree_.children_rightclf.tree_.featureclf.tree_.capacityclf.tree_.thresholdclf.tree_.valueclf.tree_.impurityclf.tree_.decision_path
可知:
拿鸢尾花数据集手动验证一下上述猜想,以根节点的分裂特征3和阈值0.8进行分裂,得到落入左子节点的样本计数结果如下,发现确实是分裂后只剩下50个第一类样本,也即样本计数为[50, 0, 0],完全一致。
另外,通过children_left和children_right两个属性的子节点对应关系,其实我们还可以推断出该二叉树的遍历方式为前序遍历,即按照根-左-右的顺序,对于上述决策树其分裂后对应二叉树示意图如下:
2、老方法提取决策树规则
通过上面的分析,我们知道了决策树的存储方式,下面就开始规则提取,在网上搜索,基本上只能收到下面的方法:
数据读取import pandas as pdimport numpy as nppd.set_option('display.max_columns', None)#显示所有的列path = '/Users/wuzhengxiang/Documents/DataSets/RizhaoGongJiJin/train.csv'train = pd.read_csv(path).fillna(-1)train.columns构建训练集X = train.loc[:,'XINGBIE':'DKLL']Y = train['label']训练一个决策树,这里限制了最大深度和最小样本树from sklearn import treeclf = tree.DecisionTreeClassifier( max_depth=3, min_samples_leaf=50 )clf = clf.fit(X, Y)决策树规则提取-老方法
from sklearn.tree import _treedef tree_to_code(tree, feature_names): tree_ = tree.tree_ feature_name = [ feature_names[i] if i != _tree.TREE_UNDEFINED else "undefined!" for i in tree_.feature ] print ("def tree({}):".format(", ".join(feature_names))) def recurse(node, depth): indent = " " * depth if tree_.feature[node] != _tree.TREE_UNDEFINED: name = feature_name[node] threshold = tree_.threshold[node] print("{}if {} <= {}:".format(indent, name, threshold)) recurse(tree_.children_left[node], depth + 1) print("{}else: # if {} > {}".format(indent, name, threshold)) recurse(tree_.children_right[node], depth + 1) else: print("{}return {}".format(indent, tree_.value[node])) recurse(0, 1)tree_to_code(clf,X.columns) return [[161. 0.]]
’可以看得出来,虽然提取出来了策略,但是并不是很完美,还是需要人为拆解策略,于是我继续研究。
3、新方法提取决策树规则
不仅仅对对二叉树的所有路径进行遍历,还需要进行回溯并组合成变量,根据决策树的输出,构建规则提取函数,需要用到二叉树遍历和回溯算法,本人数据结构不是很好,干了两个晚上,真是编程偷不了懒,出来混迟早要还的。代码比较混乱,大家将就看,还好这个部分对效率没啥要求。如果有更好的代码,不吝赐教。
def XiaoWuGe_Get_Rules(clf,X): n_nodes = clf.tree_.node_count children_left = clf.tree_.children_left children_right = clf.tree_.children_right feature = clf.tree_.feature threshold = clf.tree_.threshold value = clf.tree_.value node_depth = np.zeros(shape=n_nodes, dtype=np.int64) is_leaves = np.zeros(shape=n_nodes, dtype=bool) stack = [(0, 0)] while len(stack) > 0: node_id, depth = stack.pop() node_depth[node_id] = depth is_split_node = children_left[node_id] != children_right[node_id] if is_split_node: stack.append((children_left[node_id], depth+1)) stack.append((children_right[node_id], depth+1)) else: is_leaves[node_id] = True feature_name = [ X.columns[i] if i != _tree.TREE_UNDEFINED else "undefined!" for i in clf.tree_.feature] ways = [] depth = [] feat = [] nodes = [] rules = [] for i in range(n_nodes): if is_leaves[i]: while depth[-1] >= node_depth[i]: depth.pop() ways.pop() feat.pop() nodes.pop() if children_left[i-1]==i:#当前节点是上一个节点的左节点,则是小于 a='{f}<={th}'.format(f=feat[-1],th=round(threshold[nodes[-1]],4)) ways[-1]=a last =' & '.join(ways)+':'+str(value[i][0][0])+':'+str(value[i][0][1]) rules.append(last) else: a='{f}>{th}'.format(f=feat[-1],th=round(threshold[nodes[-1]],4)) ways[-1]=a last = ' & '.join(ways)+':'+str(value[i][0][0])+':'+str(value[i][0][1]) rules.append(last) else: #不是叶子节点 入栈 if i==0: ways.append(round(threshold[i],4)) depth.append(node_depth[i]) feat.append(feature_name[i]) nodes.append(i) else: while depth[-1] >= node_depth[i]: depth.pop() ways.pop() feat.pop() nodes.pop() if i==children_left[nodes[-1]]: w='{f}<={th}'.format(f=feat[-1],th=round(threshold[nodes[-1]],4)) else: w='{f}>{th}'.format(f=feat[-1],th=round(threshold[nodes[-1]],4)) ways[-1] = w ways.append(round(threshold[i],4)) depth.append(node_depth[i]) feat.append(feature_name[i]) nodes.append(i) return rules
4、利用函数对规则进行提取
#训练一个决策树,对规则进行提取clf = tree.DecisionTreeClassifier(max_depth=10,min_samples_leaf=50)clf = clf.fit(X, Y)Rules = XiaoWuGe_Get_Rules(clf,X)Rules[0:5] # 查看前5条规则['GRZHZT<=1.5 & DWSSHY<=14.5 & DWJJLX<=177.0 & DWJJLX<=115.0 & DKYE<=111236.2852 & DWSSHY<=4.5 & DWYJCE<=663.54 & DKYE<=67419.1094:45.0:8.0', 'GRZHZT<=1.5 & DWSSHY<=14.5 & DWJJLX<=177.0 & DWJJLX<=115.0 & DKYE<=111236.2852 & DWSSHY<=4.5 & DWYJCE<=663.54 & DKYE >67419.1094:61.0:3.0', 'GRZHZT<=1.5 & DWSSHY<=14.5 & DWJJLX<=177.0 & DWJJLX<=115.0 & DKYE<=111236.2852 & DWSSHY<=4.5 & DWYJCE >663.54 & GRZHYE<=45622.4883 & DKYE<=1825.5625:63.0:2.0', 'GRZHZT<=1.5 & DWSSHY<=14.5 & DWJJLX<=177.0 & DWJJLX<=115.0 & DKYE<=111236.2852 & DWSSHY<=4.5 & DWYJCE >663.54 & GRZHYE<=45622.4883 & DKYE >1825.5625:188.0:0.0', 'GRZHZT<=1.5 & DWSSHY<=14.5 & DWJJLX<=177.0 & DWJJLX<=115.0 & DKYE<=111236.2852 & DWSSHY<=4.5 & DWYJCE >663.54 & GRZHYE >45622.4883:46.0:4.0']len(Rules) # 查看规则总数182
我们可以导出成表格的形式,更加清晰
提高树的深度再看看,max_depth=15,可以看到规则数从182变成了521条,规模更大
clf = tree.DecisionTreeClassifier(max_depth=15,min_samples_leaf=20)clf = clf.fit(X, Y)Rules = Get_Rules(clf,X)Rules[0:5]['GRZHZT<=1.5 & DWSSHY<=14.5 & DWJJLX<=177.0 & DWJJLX<=115.0 & DKYE<=111236.2852 & DWSSHY<=4.5 & DWYJCE<=663.54 & GRZHSNJZYE<=19428.9082 & DKFFE<=142737.0 & CSNY<=600926400.0:54.0:0.0', 'GRZHZT<=1.5 & DWSSHY<=14.5 & DWJJLX<=177.0 & DWJJLX<=115.0 & DKYE<=111236.2852 & DWSSHY<=4.5 & DWYJCE<=663.54 & GRZHSNJZYE<=19428.9082 & DKFFE<=142737.0 & CSNY >600926400.0:18.0:2.0', 'GRZHZT<=1.5 & DWSSHY<=14.5 & DWJJLX<=177.0 & DWJJLX<=115.0 & DKYE<=111236.2852 & DWSSHY<=4.5 & DWYJCE<=663.54 & GRZHSNJZYE<=19428.9082 & DKFFE >142737.0:19.0:4.0', 'GRZHZT<=1.5 & DWSSHY<=14.5 & DWJJLX<=177.0 & DWJJLX<=115.0 & DKYE<=111236.2852 & DWSSHY<=4.5 & DWYJCE<=663.54 & GRZHSNJZYE >19428.9082:15.0:5.0', 'GRZHZT<=1.5 & DWSSHY<=14.5 & DWJJLX<=177.0 & DWJJLX<=115.0 & DKYE<=111236.2852 & DWSSHY<=4.5 & DWYJCE >663.54 & GRZHYE<=73608.0156 & DKYE<=1825.5625 & GRZHSNJZYE<=9524.7949:21.0:2.0']len(Rules)521#可以遍历所有的规则for i in Rules: print(i)
到此为止,我们完成了基础规则的挖掘,面对实际业务,我们还需要更丰富,更灵活的挖掘方式。
五、挖掘更多的风控策略
上面仅仅进行了初步的挖掘,我们还可以对特征进行抽样,然后进行更大规模的抽样,最后从决策树变成了决策森林,感觉有种随机深林的感觉,大家可以试试。如果还有不懂得,可以咨询我。
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
“最近复购率一直在下降,我们的营销力度不小啊,为什么用户还是走了?” “是不是广告投放的用户质量不高?还是我们的产品问题 ...
2025-02-21以下文章来源于数有道 ,作者数据星爷 SQL查询是数据分析工作的基础,也是CDA数据分析师一级的核心考点,人工智能时代,AI能为 ...
2025-02-19在当今这个数据驱动的时代,几乎每一个业务决策都离不开对数据的深入分析。而其中,指标波动归因分析更是至关重要的一环。无论是 ...
2025-02-18当数据开始说谎:那些年我们交过的学费 你有没有经历过这样的场景?熬了三个通宵做的数据分析报告,在会议上被老板一句"这数据靠 ...
2025-02-17数据分析作为一门跨学科领域,融合了统计学、编程、业务理解和可视化技术。无论是初学者还是有一定经验的从业者,系统化的学习路 ...
2025-02-17挖掘用户价值本质是让企业从‘赚今天的钱’升级为‘赚未来的钱’,同时让用户从‘被推销’变为‘被满足’。询问deepseek关于挖 ...
2025-02-17近来deepseek爆火,看看deepseek能否帮我们快速实现数据看板实时更新。 可以看出这对不知道怎么动手的小白来说是相当友好的, ...
2025-02-14一秒精通 Deepseek,不用找教程,不用买资料,更不用报一堆垃圾课程,所有这么去做的,都是舍近求远,因为你忽略了 deepseek 的 ...
2025-02-12自学 Python 的关键在于高效规划 + 实践驱动。以下是一份适合零基础快速入门的自学路径,结合资源推荐和实用技巧: 一、快速入 ...
2025-02-12“我们的利润率上升了,但销售额却没变,这是为什么?” “某个业务的市场份额在下滑,到底是什么原因?” “公司整体业绩 ...
2025-02-08活动介绍 为了助力大家在数据分析领域不断精进技能,我们特别举办本期打卡活动。在这里,你可以充分利用碎片化时间在线学习,让 ...
2025-02-071、闺女,醒醒,媒人把相亲的带来了。 我。。。。。。。 2、前年春节相亲相了40个, 去年春节相亲50个, 祖宗,今年你想相多少个 ...
2025-02-06在数据科学的广阔领域中,统计分析与数据挖掘占据了重要位置。尽管它们常常被视为有关联的领域,但两者在理论基础、目标、方法及 ...
2025-02-05在数据分析的世界里,“对比”是一种简单且有效的方法。这就像两个女孩子穿同一款式的衣服,效果不一样。 很多人都听过“货比三 ...
2025-02-05当我们只有非常少量的已标记数据,同时有大量未标记数据点时,可以使用半监督学习算法来处理。在sklearn中,基于图算法的半监督 ...
2025-02-05考虑一种棘手的情况:训练数据中大部分样本没有标签。此时,我们可以考虑使用半监督学习方法来处理。半监督学习能够利用这些额 ...
2025-02-04一、数学函数 1、取整 =INT(数字) 2、求余数 =MOD(除数,被除数) 3、四舍五入 =ROUND(数字,保留小数位数) 4、取绝对值 =AB ...
2025-02-03作者:CDA持证人 余治国 一般各平台出薪资报告,都会哀嚎遍野。举个例子,去年某招聘平台发布《中国女性职场现状调查报告》, ...
2025-02-02真正的数据分析大神是什么样的呢?有人认为他们能轻松驾驭各种分析工具,能够从海量数据中找到潜在关联,或者一眼识别报告中的数 ...
2025-02-01现今社会,“转行”似乎成无数职场人无法回避的话题。但行业就像座围城:外行人看光鲜,内行人看心酸。数据分析这个行业,近几年 ...
2025-01-31