基于决策树的【非连续特征】风控策略自动化挖掘

大家好,我是小伍哥,最近事情太多了,有点忙,今天继续来写个策略挖掘的文章,时间有限,案例比较简单,我后面用更复杂的数据集更新下。

之前我写了决策树策略挖掘的文章,不过里面都是使用的数值特征,或者说是连续特征,如果我们是文本或者类别特征怎么办呢?能不能用决策树进行挖掘?

我最近研究了下,其实非连续的特征,也是可以用决策树的,挖掘处理的词组合或者行为组合,解释性更好。写个简单的案例,大家有需要的参考下。

我们先来构建一个简单的数据集,这里用的文本数据用的是我从邮箱里面复制出来的垃圾邮件数据,sep是包含空格。通过这个数据,我们尝试下怎么自动化的挖掘出策略组合。

 
from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfVectorizer,CountVectorizerfrom sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score, auc, roc_auc_score train = ['尽快,尽快,完成,工作', '可,代开,各,行业,发票,sep', '可,开,发票,请联系,sep', '明天,一起,约个饭,sep', '完成,的,非常,棒', '项目,效果,很好,sep', '有,发票,薇,sep', '有,开票,微,sep,有', '账单,请,查收', '正规,增值税,发票,sep']label=[0,1,1,0,0,0,1,1,0,1]test = ['代开,增值税,发票,sep']

决策树只能处理数字型特征,那我们就要将文本型特征转换成数值,然后再还原回去。那怎么转换呢,我们首先想到的是one-hot编码,这样就比较简单了。我们使用sklearn.feature_extraction.text这个模块,但是这个有个问题,没有one-hot,我们转换下就行。

sklearn.feature_extraction.text.CountVectorizer这个函数,是每个样本中某个词的出现次数,其实我们只想要是否出现就行。

有了数据,我们要做的,就是对文本进行分词处理了

 
# 实例化vectorizer_word = CountVectorizer(max_features=50,  token_pattern=r"(?u)\b\w+\b",  min_df=1,  analyzer='word',  #ngram_range=(2,5)  ) #训练进行vectorizer_word.fit(train)#词转换成CountVectorizer向量tfidf_train = vectorizer_word.transform(train) tfidf_test = vectorizer_word.transform(test) # 可以看看我们的词典涨什么样print(vectorizer_word.vocabulary_){'尽快': 8, '完成': 7, '工作': 9, '可': 4, '代开': 2, '各': 5, '行业': 23, '发票': 3, 'sep': 0, '开': 10, '请联系': 25, '明天': 15, '一起': 1, '约个饭': 21, '的': 20, '非常': 27, '棒': 18, '项目': 28, '效果': 14, '很好': 12, '有': 16, '薇': 22, '开票': 11, '微': 13, '账单': 26, '请': 24, '查收': 17, '正规': 19, '增值税': 6}# 数据处理import pandas as pdpd.set_option('display.max_columns', None)pd.set_option('display.max_rows', None)pd.set_option('display.width', 200) # 设置打印宽度(**重要**)X = pd.DataFrame(tfidf_train.toarray())# 对大于1的数据全部转换成1X[X>=1]=1

处理前

处理后,可以看到,我们的大于1的都变成1了

对我们的X重新命名,用词的名字进行命名

 
# 对字典进行反转dic = {}for k,v in vectorizer_word.vocabulary_.items(): dic[v] = k    # 对数据集进行命名X.columns = [dic[i] for i in list(X.columns)]

下面就是命名完的表格了

下面是我们的规则提取函数构建,就是那个我之前写吐血的函数。

 
# 构建决策树规则提取函数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

模型构建和规则提取

 
from sklearn import treeimport numpy as npfrom sklearn.tree import _tree# 构建决策树clf = tree.DecisionTreeClassifier( max_depth=10, )clf = clf.fit(X, label)# 规则提取Rules = XiaoWuGe_Get_Rules(clf,X)Rules['发票<=0.5 & 开票<=0.5:5.0:0.0', '发票<=0.5 & 开票>0.5:0.0:1.0', '发票>0.5:0.0:4.0']# 结果格式整理,整理成合格的表格形式df = pd.DataFrame(Rules)df.columns = ['allrules']df['Rules'] = df['allrules'].str.split(':').str.get(0)df['good'] = df['allrules'].str.split(':').str.get(1).astype(float)df['bad'] = df['allrules'].str.split(':').str.get(2).astype(float)df['all'] = df['bad']+df['good']df['bad_rate'] = df['bad']/df['all']# 结果排序&结果保存df = df.sort_values(by='bad',ascending=False)df.to_csv('df.csv',header=True)

这个就是我们挖掘的结果,我们可以看到,大于0.5的,就是包含这个词,小于0.5的,就是不包含,这样就可以指导我们进行规则配置了。

这里的文本,可以是行为,也可以是其他属性特征,只要转换成独立的、非连续的符号就行,比如sex_01,star_01等等。

有这个种非连续特征的挖掘的,可以参考下,我们浅浅的可视化一下,更好的可视化参考我之前的文章。 这个文章也需要更新了,里面的可视化的库已经变更了,并且没有做最后的策略的提取工作,有时间了一步步的优化,大家先将就看看。

 
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 

如果有更复杂的,可视化的效果就会更好点,我们后面在搞。类似下面这种。也可以用dtreeviz这个包,更好看。

   

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值