直接使用
请打开基于图算法实现金融风控,并点击右上角 “ 在DSW中打开” 。
使用图算法实现金融风控
图算法一般被用来解决关系网状的业务场景。与常规的结构化数据不同,图算法需要把数据整理成首尾相连的关系图谱,更多的是考虑边和点的概念。这里提供了丰富的图算法组件,包括K-Core、最大联通子图、标签传播聚类等。
本示例是使用人物关系图数据,和少量标记用户数据,基于图算法实现金融风控。
运行环境要求
PAI-DSW 官方镜像中默认已经安装了 PyAlink,内存要求 4G 及以上。
本 Notebook 的内容可以直接运行查看,不需要准备任何其他文件。
导入 pyalink 包,并启用本地运行环境
- 在这个示例中,我们使用 useLocalEnv 在本地(也就是 DSW 的 container 内)运行 Alink 作业,使用多线程的方式模拟分布式计算。
- Alink也可以使用usePaiEnv提交到MaxCompute上。
from pyalink.alink import * useLocalEnv(1)
数据准备
本示例需要两个数据集:人物关系图数据表和已知用户标签表(标记哪些用户是欺诈用户,哪些用户是信用用户)。
人物关系图数据
- 每两个人之间的连线表示两人有一定关系,可以是同事关系或者亲人关系等。
人物关系图数据定义
# Alink支持多种数据源, 包括MaxCompute表,OSS,Oracle,内存数据源等。这里使用了内存数据源。 import pandas as pd df = pd.DataFrame([ ["Enoch", "Evan", 10], ["Enoch", "Gregary", 2], ["Gregary", "Hale", 6], ["Evan", "Hugo", 2], ["Evan", "Jeff", 4], ["Gregary", "Keith", 7], ["Jeff", "Keith", 5], ["Hale", "Jeff", 11], ["Keith", "Leif", 3], ["Keith", "Lionel", 1], ["Leif", "Mick", 4], ["Mick", "Noah", 5], ["Lionel", "Noah", 5], ["Rex", "Parker", 3], ["Rex", "Stan", 4], ["Stan", "Parker", 5] ]) edges = BatchOperator.fromDataframe(df, schemaStr='source string, target string, weight double') ### OSS数据源 # OssCsvSinkBatchOp()\ # .setEndPoint("oss-cn-shanghai.aliyuncs.com")\ # .setFilePath('oss://bucket_name/xxx/xxx.csv')\ # .setOverwriteSink(True)\ # .setAccessKeyId('*')\ # .setAccessKeySecret('*') ### MaxCompute数据源 # OdpsSourceBatchOp() \ # .setAccessId("*")\ # .setAccessKey("*")\ # .setEndPoint("http://service-corp.odps.aliyun-inc.com/api")\ # .setProject("*")\ # .setInputTableName("*")
查看人物关系表
edges.lazyPrint(5) BatchOperator.execute()
source | target | weight | |
0 | Enoch | Evan | 10 |
1 | Enoch | Gregary | 2 |
2 | Gregary | Hale | 6 |
3 | Evan | Hugo | 2 |
4 | Evan | Jeff | 4 |
查看离散变量的统计
edges.select('source, target').lazyVizDive() BatchOperator.execute()
查看人物关系表统计信息
edges.lazyPrintStatistics() BatchOperator.execute()
Summary: |colName|count|missing|sum| mean|variance|min|max| |-------|-----|-------|---|------|--------|---|---| | source| 16| 0|NaN| NaN| NaN|NaN|NaN| | target| 16| 0|NaN| NaN| NaN|NaN|NaN| | weight| 16| 0| 77|4.8125| 7.3625| 1| 11|
查看人物关系表统计面板
edges.lazyVizStatistics() BatchOperator.execute()
已知用户标签表
df_labeled_vertices = pd.DataFrame([ ["Enoch", "信用用户", 1.0], ["Evan", "欺诈用户", 0.8] ]) labeled_vertices = BatchOperator.fromDataframe(df_labeled_vertices, schemaStr='vertices string, labels string, weight double') labeled_vertices.print()
vertices | labels | weight | |
0 | Enoch | 信用用户 | 1 |
1 | Evan | 欺诈用户 | 0.8 |
使用图算法判断用户是否是欺诈用户
分为三步,
第一步,最大联通子图
通过最大联通子图组件将数据中的群体分为两部分,并赋予group_id。然后通过filter和JOIN去除图中的无关联人员。
最大联通子图组件可以查找具有通联关系的最大集合,从而排除团队中与风控无关的人。
# 通过联通子图找到无关人员 connected_components = edges\ .link( ConnectedComponentsBatchOp()\ .setEdgeSourceCol("source")\ .setEdgeTargetCol("target")\ )\ .lazyPrint(title="【连通子图】") BatchOperator.execute()
【连通子图】
node | groupId | |
0 | Enoch | 0 |
1 | Evan | 0 |
2 | Gregary | 0 |
3 | Hale | 0 |
4 | Hugo | 0 |
5 | Jeff | 0 |
6 | Keith | 0 |
7 | Leif | 0 |
8 | Lionel | 0 |
9 | Mick | 0 |
10 | Noah | 0 |
11 | Parker | 11 |
12 | Rex | 11 |
13 | Stan | 11 |
画成下图:
如上图所示,结果有两组,groupId=0和groupId=11,可以看出groupId=11中没有已标记的欺诈用户和诚信用户,因此认为groupId=11是无关联人员,需要去掉。
# 过滤groupId=0的用户 selected_nodes = connected_components\ .filter("groupId=0") \ .lazyPrint(5, title="【选择 group 0】") BatchOperator.execute()
【选择 group 0】
node | groupId | |
0 | Enoch | 0 |
1 | Evan | 0 |
2 | Gregary | 0 |
3 | Hale | 0 |
4 | Hugo | 0 |
# 使用Join, 去掉无关人员 join1 = JoinBatchOp()\ .setJoinPredicate("source=node")\ .setSelectClause("source, target, weight")\ .linkFrom(edges, selected_nodes) filtered_edges = JoinBatchOp()\ .setJoinPredicate("target=node")\ .setSelectClause("source, target, weight")\ .linkFrom(join1, selected_nodes)\ .lazyPrint(title="【过滤后的边】") BatchOperator.execute()
【过滤后的边】
source | target | weight | |
0 | Enoch | Evan | 10 |
1 | Enoch | Gregary | 2 |
2 | Gregary | Hale | 6 |
3 | Evan | Hugo | 2 |
4 | Evan | Jeff | 4 |
5 | Hale | Jeff | 11 |
6 | Gregary | Keith | 7 |
7 | Jeff | Keith | 5 |
8 | Keith | Leif | 3 |
9 | Keith | Lionel | 1 |
10 | Leif | Mick | 4 |
11 | Mick | Noah | 5 |
12 | Lionel | Noah | 5 |
第二步,探查每个人的一度人脉及二度人脉等关系
- 单元最短路径组件的输出结果中,distance表示Enoch通过几个人可以联络到目标人
# 指定source(源头) = 'Enoch' filtered_edges.link(\ SingleSourceShortestPathBatchOp()\ .setIsUndirectedGraph(True)\ .setEdgeSourceCol("source")\ .setEdgeTargetCol("target")\ .setEdgeWeightCol("weight")\ .setSourcePoint("Enoch")\ )\ .lazyPrint(title="【单源最短路径】") BatchOperator.execute()
【单源最短路径】
vertex | distance | |
0 | Enoch | 0 |
1 | Evan | 10 |
2 | Gregary | 2 |
3 | Hale | 8 |
4 | Hugo | 12 |
5 | Jeff | 14 |
6 | Keith | 9 |
7 | Leif | 12 |
8 | Lionel | 10 |
9 | Mick | 16 |
10 | Noah | 15 |
第三步,使用标签传播确定未标记点的标签
标签传播分类为半监督的分类算法,原理为用已标记节点的标签信息去预测未标记节点的标签信息。
在算法执行过程中,每个节点的标签按相似度传播给相邻节点,在节点传播的每一步,每个节点根据相邻节点的标签来更新自己的标签, 与该节点相似度越大,其相邻节点对其标注的影响权值越大,相似节点的标签越趋于一致,其标签就越容易传播。 在标签传播过程中,保持已标注数据的标签不变,使其像一个源头把标签传向未标注数据。
最终,当迭代过程结束时,相似节点的概率分布也趋于相似,可以划分到同一个类别中,从而完成标签传播过程
# 标签传播算法 CommunityDetectionClassifyBatchOp()\ .setIsUndirectedGraph(True)\ .setEdgeSourceCol("source")\ .setEdgeTargetCol("target")\ .setEdgeWeightCol("weight")\ .setVertexCol("vertices")\ .setVertexLabelCol("labels")\ .linkFrom(filtered_edges, labeled_vertices)\ .lazyPrint(title="【标签传播--过滤的节点】") BatchOperator.execute()
【标签传播--过滤的节点】
vertex | label | |
0 | Enoch | 信用用户 |
1 | Evan | 欺诈用户 |
2 | Gregary | 信用用户 |
3 | Hale | 欺诈用户 |
4 | Hugo | 欺诈用户 |
5 | Jeff | 欺诈用户 |
6 | Keith | 信用用户 |
7 | Leif | 信用用户 |
8 | Lionel | 信用用户 |
9 | Mick | 信用用户 |
10 | Noah | 信用用户 |
附录
- PyAlink脚本使用方式: https://help.aliyun.com/document_detail/424831.html?spm=5176.21213303.J_6704733920.7.10f253c9AdO1Lj&scm=20140722.S_help@@文档@@424831._.ID_help@@文档@@424831-RL_PyAlink-LOC_main-OR_ser-V_2-P0_0
- Alink算法文档:https://www.yuque.com/pinshu/alink_doc
- Alink一个示例GBDT+FM: https://pai.console.aliyun.com/?regionId=cn-shanghai&workspaceId=270080#/dsw-gallery-workspace/preview/traditionalMachineLearning/gbdt_fm