之前写过一篇《抱团反欺诈问题探讨》的交流文章,抛出了抱团分析中回溯团形成的问题,经过这段时间的思考和琢磨,大致将这个想法落地实现了,所以重新梳理了一下写出来。虽然研究得断断续续,不过好在最后是完成了。
目录
1.最大子团分析
2.抱团回溯分析
3.规则制定
4.总结
一、最大子团分析
本文用得是networkx库实现抱团,并结合pandas进行数据处理,衍生出抱团过程中每一步的变量。我一开始是使用的python_igraph库,但是尝试了一段时间后发现这个库的依赖问题太多,大量精力耗费在解决各种奇奇怪怪的依赖报错问题上。最后决定转向networkx,由于是anaconda自带的库,使用过程除了读英文文档耗了点时间外,没有遇到特别难的问题。
首先将全量申请订单的申请时间、申请状态、手机号、联系人手机号、PD指标按照申请时间从远到近排列。为了熟悉networkx的基本用法,本文先从最大团的分析入手,然后再对最大团的形成过程进行抱团回溯。
keys = df['apply_mobile'].tolist()
values = df['contactmobile'].tolist()
edgelist = list(zip(keys, values))
#抱团
H=nx.Graph(edgelist)
#增加节点属性
for i in df.index:
H.nodes[df.loc[i]['apply_mobile']]['user_id']=df.loc[i]['user_id']
H.nodes[df.loc[i]['apply_mobile']]['app_create_time']=df.loc[i]['app_create_time']
H.nodes[df.loc[i]['apply_mobile']]['fpd1']=df.loc[i]['fpd1']
H.nodes[df.loc[i]['apply_mobile']]['fpd15']=df.loc[i]['fpd15']
H.nodes[df.loc[i]['apply_mobile']]['fpd30']=df.loc[i]['fpd30']
#基于点连接划分子团
h=[H.subgraph(c).copy() for c in nx.connected_components(H)]
这一步生成所有的基于点连接形成的子团,列表的每一个元素是一个graph对象,为了找出最大子团的graph对象,需要做以下操作:
# 找出最大团
h={}
for i in enumerate(nx.connected_components(H)):
if len(i[1])==len(max(nx.connected_components(H),key=len)):
h[i[0]]=H.subgraph(i[1]).copy()
这一步用一个字典存储了最大子团对象,字典的键值为最大子团产生的序号。这一步h有两个最大子团,序号分别为777和2358。
画出最大团:
通过分析最大团发现:这个团一共有9个人,4单申请,2单决绝,拒绝原因为在网时长过短、外部分过低,关联交易有欺诈嫌疑;通过2单,1单发生逾期。
二、抱团回溯分析
回溯分析的实现过程本质就是循环抱团,并对每一步形成的团进行衍生变量的计算。在写代码的过程中我采取的思路是,先采用最大子团最后一个申请的号码为例,衍生出这个号码申请时时看到团的通过率、FPD1%、FPD15%、黑名单命中率、多头拒绝率等指标,然后再去写循环,将这个号码替换成循环过程中的每一个号码即可。
# 循环抱团衍生代码
for i in df.index:
keys = df['apply_mobile'][0:i+1].tolist()
values = df['contactmobile'][0:i+1].tolist()
edgelist = list(zip(keys, values))
H=nx.Graph(edgelist)
#如果形成的团个数大于5个,则开始衍生变量
if len(nx.node_connected_component(H,df['apply_mobile'][i]))>=5:
s=nx.node_connected_component(H,df['apply_mobile'][i])
df.loc[df.apply_mobile==df['apply_mobile'][i],'团人数']=len(s)
df.loc[df.apply_mobile==df['apply_mobile'][i],'团结构']=str(nx.node_connected_component(H,df['apply_mobile'][i]))
#需要剔除本单申请的号码
s.remove(df['apply_mobile'][i])
print(i)
#取出本单申请之前的团内所有号码的订单信息
df_temp=df[0:i+1][df['apply_mobile'][0:i+1].isin(s)]
#变量衍生
df.loc[df.apply_mobile==df['apply_mobile'][i],'通过率']=df_temp.app_id.drop_duplicates().count()/len(df_temp.user_id.unique())
df.loc[df.apply_mobile==df['apply_mobile'][i],'FPD1']=(df_temp[df_temp.fpd1==1].app_id.drop_duplicates().count())/df_temp.app_id.drop_duplicates().count()
df.loc[df.apply_mobile==df['apply_mobile'][i],'FPD15']=(df_temp[df_temp.fpd15==1].app_id.drop_duplicates().count())/df_temp.app_id.drop_duplicates().count()
df.loc[df.apply_mobile==df['apply_mobile'][i],'黑名单命中数']=df_temp[df_temp.reject==1].user_id.drop_duplicates().count()
df.loc[df.apply_mobile==df['apply_mobile'][i],'逾期命中数']=df_temp[df_temp.reject==2].user_id.drop_duplicates().count()
df.loc[df.apply_mobile==df['apply_mobile'][i],'多头拒绝数']=df_temp[df_temp.reject==3].user_id.drop_duplicates().count()
df.loc[df.apply_mobile==df['apply_mobile'][i],'外部逾期数']=df_temp[df_temp.reject==4].user_id.drop_duplicates().count()
df.loc[df.apply_mobile==df['apply_mobile'][i],'团内在逾个数']=df_temp[(df_temp.delayed_status.notnull())&(df_temp.delayed_status!='M0')].user_id.drop_duplicates().count()
下面以两个最大子团(9人团)的形成过程为例,说明团的形成过程:
以上为第一个最大子团的形成过程,其中在形成最大子团之前形成过一个5人团,这个团如果不进行回溯分析,是没有办法分析到的。
上图中有颜色的表示申请件,红色表示申请被拒绝,黄色表示申请通过但发生逾期,绿色表示申请通过且未逾期。在团形成的第2个人申请时,形成了一个5人团,此时第三个人看到的团的通过率为0%,多头拒绝率为100%,第2个人申请通过且发生逾期;第3个人申请时,他所填的联系人未形成团;第4个人申请时,他填写的联系人也是第3个人申请时填写联系人,因此5人团与3人团被连通,形成一个9人团。此时第4个人申请时看到的团的结构为:3人申请,1人通过,2人拒绝(都为多头拒绝)。他的直接联系人未发生逾期,但是他作为联系人出现的申请人(一度关联)以及他的联系人关联的其他订单(二度关联)发生逾期。这种情况下,第4人申请通过,未发生逾期。
再看另外一个最大团:
这个9人团生成的过程中,分别形成过5人团、7人团,然后最终形成了9人团。
这个9人团涉及的4笔订单全部被拒绝,拒绝原因非黑名单类、信贷逾期类、多头类规则,这里时由于变量衍生地不够,应该再加入一些其他拒绝原因的变量。另一方面也说明风控手段的有效性,在无联系人抱团规则的情况下依然有效地防范住了一定的欺诈。
三、规则制定
通过上述地回溯过程,已经得到所有5人以上的团以及团的各种衍生特征,以这些变量为x,是否通过/逾期为y,可以制定一些单变量或者组合变量规则。
上图数据为根据抱团结果虚构,从上图可以看出,5人以上各团的通过率、逾期率情况,一般来说团的人数越大通过率可能越低,但是由于通过率低了,坏人被其他规则拒绝了,进来的人逾期指标不一定和团人数成正相关。
通过分析发现,团内黑名单命中数是比较有效的一条抱团规则。团内黑名单命中人数越多时,通过率越低,且通过件中的FPD15占比依然较高,因此通过抱团分析要找的就是这种拒绝率很高且逾期率很高的规则,也就是单规则的lift值高。类似的规则还可以有:团内多头拒绝占比、团内信贷逾期命中占比等等。
通过组合规则的分析,也就解决了之前那篇文章中的问题:如果一个五人团,A是黑名单拒绝,B通过且未逾期,C通过且逾期(仍然在逾),D通过且逾期(已催回),此时E过来申请时,他看到的团的情况就是:和他有关系的4人中有通过率(75%),逾期率(66.6%)。这种情况下对E如何作决策的问题,通过这种抱团回溯、衍生变量的分析就可以确定最终的阈值。反欺诈抱团分析的核心还是在变量的衍生上,回溯的代码完成的情况下,想要真正地在业务中落地,就需要在衍生变量这块作一些文章了。
四、总结
简单说一下作这个分析的心得,一开始没觉得自己可以把这件事情完成,看了手上excel和sql实现的文件也是很复杂难懂,最后索性搞清了思路后用python去实现,确实简洁和迅速很多。在用python实现过程中,也遇到了不少问题,几近让我觉得自己完不成这个任务,读英文文档时也觉得很难沉下心来去研读,不过后来还是一点点、静下心来坚持完成了这个分析。心态很重要,坚持也很重要,也许这个分析费了很大的力气依然没能完成,或者没有在业务上落地,但是重要的是努力去完成这件事情的过程,人生的很多事情,过程比结果重要。
【作者】:Labryant
【原创公众号】:风控猎人
【简介】:做一个有规划的长期主义者。
【转载说明】:转载请说明出处,谢谢合作!~