利用回归决策树自动化挖掘风控策略规则

序言

在信贷风控策略的业务中,单个变量规则已经不足以满足业务需求。我们面临着一个挑战:如何将不同特征组合起来,以更准确地识别风险?传统的人工分析耗时耗力,陷入无限加班的死循环中。通过自动化的策略组合挖掘,决策树算法可以轻松发现大批量的潜在策略组合。我们只需提取决策树的叶子规则,就能得到丰富的风控策略。这意味着,我们可以告别繁杂的人工分析,开启策略挖掘的自动化新篇章。

一、读取数据及数据概况

本文使用超10万条数据及61个特征进行讲解,并将数据集划分为训练集和时间外验证集。

  • train:训练集,用于训练决策树
  • oot:时间外验证集,用于验证训练集策略规则分布是否有明显偏差。

二、决策树模型训练及可视化

决策树有回归和分类2个算法。2个算法在相同的参数下,挖掘的规则结果是一致的(读者可自行验证)。本文使用的是sklearn中的回归树进行训练,然后使用基于sklearn中的tree.export_graphviz模块将决策树可视化。

决策树回归算法的可视化结果,可以根据value值的大小显示渐变色,value值越大,颜色越深;value值其实就是代表着坏样本率;比DecisionTreeClassifier()更加直接明了。这也是笔者选择DecisionTreeRegressor()函数进行训练并可视化的原因。

import pydotplus
from six import StringIO
from IPython.display import Image
import graphviz 
from sklearn import tree
import os
import re
os.environ["PATH"] += os.pathsep + 'D:/Graphviz/bin/'
dtree = tree.DecisionTreeRegressor(
    criterion='friedman_mse',
    splitter='best',
    max_depth=3,
    min_samples_split=1800,
    min_samples_leaf=800,
    random_state=15,
    max_leaf_nodes = 10)



xtrain = train_df.drop(['Y','ID', 'data_label'],axis = 1)
ytrain = train_df['Y']
dtree = dtree.fit(xtrain, ytrain)
dot_data = tree.export_graphviz(dtree, feature_names=xtrain.columns,           
                                filled=True,rounded=True,
                                special_characters=True,precision = 4 ,)
graph = graphviz.Source(dot_data,format = 'svg')
# graph.render('决策树可视化图', view=False)
graph

tree.DecisionTreeRegressor 是 scikit-learn 中用于回归问题的决策树模型。以下是一些常用参数:

  • criterion:衡量分割质量的标准。默认 "squared_error"(均方误差)。
  • splitter:决策树节点分割策略。默认是 "best"(选择最好的分割点)。
  • max_depth:树的最大深度。超过这个深度的节点将不会再被分割。
  • min_samples_split:一个节点必须具有的最小样本数,才能被分割。
  • min_samples_leaf:叶子节点必须具有的最小样本数。
  • max_features:寻找最佳分割时考虑的特征数量。
  • random_state:用于控制随机性的种子。
  • max_leaf_nodes:最大叶子节点数量。
  • min_impurity_decrease:分割节点的不纯度减少阈值。

这些参数可以通过调整来优化模型的性能和泛化能力,可以适当调整max_depth,max_leaf_nodes参数来控制规则的个数。

tree.export_graphviz 函数用于将决策树模型导出为 Graphviz 格式的文件,以便进行可视化。以下是一些常用参数:

  • decision_tree:训练好的决策树模型。
  • max_depth:导出的最大深度。如果设置为 None,则将完整的树导出。
  • feature_names:特征的名称列表。如果为 None,则使用默认的特征名称(例如 "X[0]")。
  • class_names:类别的名称列表(仅针对分类树)。如果为 None,则使用默认的类别名称。
  • precision:浮点数输出的数字精度。
  • filled:指定是否填充节点的颜色以表示类别。
  • rounded:指定是否为节点添加圆角。

这些参数可以根据需要调整,以便生成符合特定要求的决策树可视化结果。

Python环境中,除了需要安装graphviz库外("pip install graphviz"),需独立下载安装Graphviz才能在代码中调用。Graphviz官网下载

三、决策树可视化内容调整

原始默认的决策树可视化图输出信息不能够快速了解每个节点和每条规则的信息,因次,将基于原始的可视化图做一些调整,添加一些风控常需要分析的指标。其逻辑就是对原始dot_data字符串内容做一些修改。

代码如下:

def regressor_dot_adj(decision_tree, feature_names):
    """
    将原始的dot文件相关内容修改成风控规则需要的指标
    decision_tree:训练好的决策树
    feature_names: 数据集列名

    """

    samples_total =  decision_tree.tree_.n_node_samples[0]
    origin_badrate = dtree.tree_.value[0][0,0]
    
    dot_data = tree.export_graphviz(decision_tree,feature_names=feature_names,
                                    class_names=['good','bad'],filled=True,
                                    rounded=True,special_characters=True,precision = 4)
    
    lines = dot_data.split('] ;')
    
    dot_new = ''
    for item in lines:
        item = item + '] '
        samples = re.findall(r"(?<=samples\ \=\ ).*?(?=\<)", item)
        value = re.findall(r"value = (\d+\.\d+)", item)

        if len(samples) > 0 and len(value)>0:
            samples = int(samples[0])
            value = float(value[0])
            samples_rate = samples / samples_total
            lift = round(value/origin_badrate,2)
            item = re.sub(r'(?<=squared_error\ \=\ )\d+(\.\d+)?', str(round( samples_rate * 100, 2)) + '%', item)
            item = item.replace('squared_error', 'SamplesRate')
            item = re.sub(r'(?<=value\ \=\ )(\d+\.\d+)', str(round( value * 100, 2)) + '%', item)
            item = item.replace('value', 'BadRate')
            item = re.sub(r'(>, fillcolor=")', r'<br/>Lift = {}\1'.format(lift), item)            
            dot_new += item + ';'
        else:
            dot_new += item

    dot_new = dot_new[:-2]#.replace("value","bad_rate")
    return dot_new
dot_data_new = regressor_dot_adj(dtree,xtrain.columns)
graph = graphviz.Source(dot_data_new,format = 'svg')
# graph.render('决策树可视化图', view=False)
graph

如上图:每个节点添加"Lift值","SamplesRate样本占比";将"value"修改为"BadRate"。可以看到最右边的Lift值接近6倍,而样本占比仅有1.39%;可以将这个路径作为一条拒绝规则;当然也可以根据实际业务情况适度调整。

四、提取策略规则

决策树训练完成后,我们希望能对应到客户明细中,即客户命中了哪一条规则。这就需要对决策树各节点遍历获取规则信息,将规则转为python脚本执行并按dataframe格式输出,以便后续计算。

代码如下:

import numpy as np
def get_rules(dtree, feature_names):
    tree_rules = []
    def recurse(node, rule):
        if dtree.tree_.feature[node] != tree._tree.TREE_UNDEFINED:
            feature = "df['"+feature_names[dtree.tree_.feature[node]]+"']"
            # feature = ""+
            threshold = dtree.tree_.threshold[node]
            left_node, right_node = dtree.tree_.children_left[node], dtree.tree_.children_right[node]

            recurse(left_node, rule + [f"{feature} <= {round(threshold,4)}"])
            recurse(right_node, rule + [f"{feature} > {round(threshold,4)}"])
        else:
            class_label = np.argmax(dtree.tree_.value[node])
            tree_rules.append(rule)

    recurse(0, [])

    rules = [f"{' and '.join(rule)}" for rule in tree_rules]
    return rules

Rules = get_rules(dtree, xtrain.columns)

### 决策树规则逻辑转化为Python 代码
def rules_to_code(function_name,Rules):
    n=1
    rule_name={}
    py_code ="def {}(df):\n".format(function_name)
    for i in Rules:
        demo = "\telif "+i +":\n\t\treturn 'rule{}'\n".format(n)
        rule_name["rule{}".format(n)]=i.replace("df['", "").replace("']", "")
        n=n+1    
        py_code = py_code+demo
    py_code = py_code.replace('el', '', 1)
    # 字符串转化Python代码并执行
    return py_code,rule_name
sample_df2 =sample_df[['Y','ID', 'data_label']]
function_code,rule_name = rules_to_code("rules_apply",Rules)
exec(function_code)
sample_df2['规则序号']=sample_df.apply(rules_apply,axis=1)
sample_df2['规则名称']=sample_df2['规则序号'].map(rule_name)
sample_df2

五、策略规则统计

到这里,我们就拿到了每个客户命中某个策略规则的明细表,所以我们很简单就能统计每个规则下的好坏样本的分布,并导出Excel文档。可以看到,训练集train和时间外验证集oot的SampleRate分布相近,说明挖掘的6条策略规则,较为稳定。

代码如下:

def rule_stat(df):
    bg_cnt = df.pivot_table(index = ['规则序号','规则名称'],values = ['ID'],columns = ['Y'],aggfunc='count',margins=True)
    bg_cnt.columns = ['good(#)','bad(#)','samples']
    # bg_cnt = bg_cnt.reset_index()

    bg_cnt['SamplesRate']=(bg_cnt['samples']/bg_cnt.loc['All','samples'][0]).apply(lambda x: '{:.2%}'.format(x))
    bg_cnt['BadRate'] = bg_cnt['bad(#)']/bg_cnt['samples']
    bg_cnt['Lift'] = round(bg_cnt['BadRate']/bg_cnt.loc['All','BadRate'][0],2)
    bg_cnt['BadRate'] = bg_cnt['BadRate'].apply(lambda x: '{:.2%}'.format(x))
    return bg_cnt


train_rule_stat = rule_stat(sample_df2.query("data_label=='train'"))
oot_rule_stat = rule_stat(sample_df2.query("data_label=='oot'"))
rule_stat = pd.concat([train_rule_stat,oot_rule_stat],axis = 1,keys=['训练集','时间外验证集'])

writer = pd.ExcelWriter("策略自动挖掘.xlsx")
rule_stat.to_excel(writer,sheet_name = "规则统计")
sample_df2.to_excel(writer,sheet_name = "明细",index=False)
writer.save()
writer.close()

到此,已经完成了策略规则的挖掘。通过决策树算法的自动化策略组合挖掘,能够快速发现潜在策略组合。在训练决策树时,需注意过拟合情况,过程中可以适当调整max_depth,max_leaf_nodes等参数来减小过拟合,同时可以使用时间外的数据集应用到训练集生成的规则下的分布来验证训练集是否有严重过拟合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值