图算法与反欺诈:社区发现、风险传导与资金追踪

各位同学,今天我们来聊聊图计算在反欺诈场景里的几个硬核算法。说实话,信贷审批里最头疼的不是那些明面上的坏账,而是那些隐藏得很深的团伙欺诈。你想想看,一个申请人看起来资质不错,但他背后可能连着一整条黑色产业链。这时候,传统的规则引擎基本就废了。

我个人习惯把反欺诈图算法分成三类:找团伙的、看风险的、追资金的。下面我一个一个讲。

社区发现算法:Louvain 是怎么揪出欺诈团伙的?

社区发现,说白了就是把图里那些联系紧密的节点圈出来。在信贷场景里,这些节点就是申请人,边就是他们之间的关联——比如共用手机号、共用设备指纹、共用紧急联系人。

Louvain 算法是我用得最多的一个。为什么?因为它快,而且不需要你事先告诉它有几个团伙。它自己会通过模块度优化来找到最自然的划分。

核心思想:Louvain 通过两步迭代——局部模块度优化和社区聚合——来最大化社区内部的连接密度。每次迭代,它都会问:把节点 i 挪到邻居社区 C 里,模块度增量 ΔQ 是正的吗?如果是,就挪过去。

我在项目中遇到过这样一个案例:某消费金融平台,每天进件量十几万,用规则引擎只能抓到不到 5% 的欺诈。后来我们上了 Louvain,把申请人按设备指纹和 IP 地址建图,跑了一遍社区发现。结果发现了一个 200 多人的大社区,这些人共用不到 10 台设备,而且进件时间高度集中在凌晨 2 点到 5 点。嗯,这就是典型的团伙包装。

代码实现其实不复杂,我贴一段核心逻辑:

import networkx as nx
import community as community_louvain

# 构建图:节点是申请人,边是共享设备
G = nx.Graph()
G.add_edges_from([
    ('user_001', 'user_002', {'weight': 3}),  # 共享3个设备
    ('user_001', 'user_003', {'weight': 2}),
    # ... 更多边
])

# 运行 Louvain 社区发现
partition = community_louvain.best_partition(G, weight='weight')

# 输出社区大小
from collections import Counter
community_sizes = Counter(partition.values())
print("社区分布:", community_sizes.most_common(10))

避坑指南:我曾经在跑 Louvain 时忽略了边的权重归一化。结果那些因为共用 WiFi 而产生的弱关联,跟共用身份证的强关联混在一起,社区划分完全失真。后来我加了权重归一化,效果才正常。

PageRank 在风险传导中的应用

PageRank 最早是 Google 用来给网页排名的,但用在信贷反欺诈里,它就是一个天然的风险传导工具。你想想看,如果一个申请人跟很多高风险用户有直接关联,那他的风险是不是也应该被调高?

我个人习惯把 PageRank 的初始值设成申请人的信用评分,然后让它在关联图上迭代。每次迭代,一个节点的风险值会沿着边传导到它的邻居。这样,即使某个申请人表面看起来没问题,但只要他连接了几个坏账用户,他的 PageRank 值就会显著上升。

为什么会这样?因为 PageRank 的数学本质是随机游走。一个节点被越多的高分节点指向,它自己的分数就越高。在反欺诈里,这正好模拟了风险的「传染」过程。

参数 推荐值 说明
damping factor 0.85 控制风险传导的衰减速度,值越大传导越远
max_iter 100 迭代次数,一般 50-100 次就收敛了
tol 1e-6 收敛阈值,越小越精确但越慢
import networkx as nx

# 构建有向图:A -> B 表示 A 是 B 的担保人
G = nx.DiGraph()
G.add_edge('user_A', 'user_B')
G.add_edge('user_B', 'user_C')
G.add_edge('user_C', 'user_D')

# 运行 PageRank
pr = nx.pagerank(G, alpha=0.85, max_iter=100, tol=1e-6)
print("风险传导结果:", pr)

注意:PageRank 对孤立节点不友好。如果一个申请人没有任何关联,他的 PageRank 值会趋近于 (1-damping_factor)/N,这可能会低估他的真实风险。我建议对孤立节点单独用其他模型评估。

最短路径与资金追踪

资金追踪,说白了就是顺着钱的流向找源头。在信贷审批里,我们经常需要查一笔贷款资金最终流向了哪里,是不是被挪用了,或者是不是流入了某个已知的欺诈账户。

最短路径算法在这里就派上用场了。我一般用 Dijkstra 算法,因为资金流转的边权重通常是交易金额,而 Dijkstra 正好能处理非负权重的最短路径问题。

我记得有一次,一个客户申请了 50 万的经营贷,说是用来采购原材料。但我们用最短路径一查,发现这笔钱在 3 天内经过了 7 个账户,最后流到了一个赌博平台。嗯,这就是典型的资金挪用。

import networkx as nx

# 构建资金流转图
G = nx.DiGraph()
G.add_edge('loan_account', 'supplier_A', weight=500000)
G.add_edge('supplier_A', 'intermediary_B', weight=500000)
G.add_edge('intermediary_B', 'gambling_platform', weight=500000)

# 查找从贷款账户到可疑账户的最短路径
path = nx.shortest_path(G, source='loan_account', target='gambling_platform', weight='weight')
print("资金流转路径:", path)

# 计算路径总金额
total_amount = sum(G[path[i]][path[i+1]]['weight'] for i in range(len(path)-1))
print("流转总金额:", total_amount)

核心逻辑:最短路径在资金追踪里的应用,本质上是把「钱怎么走的」这个问题转化成了「图里哪条路径的权重和最小」。但要注意,实际场景中资金可能分多笔走不同路径,这时候就需要用 K 最短路径算法,比如 Yen 算法。

我个人习惯在资金追踪里再加一层时间约束。比如,只考虑 7 天内的交易,超过 7 天的边直接忽略。这样能避免把历史交易跟当前贷款混在一起,减少误报。

知识体系总览

下面这张图是我自己画的,把三个算法的核心逻辑和应用场景串在了一起。你可以把它当作一个快速参考。

图算法在信贷反欺诈中的应用体系 Louvain 社区发现 PageRank 风险传导 最短路径资金追踪 找团伙 识别共用设备/号码的 欺诈团伙 看风险 通过关联关系 传导风险评分 追资金 追踪贷款资金 最终流向 三者协同工作流 1. Louvain 先找出可疑社区 2. PageRank 对社区内节点进行风险传导评分 3. 最短路径追踪高风险节点的资金流向

这三个算法单独用效果有限,但组合起来就是一个完整的反欺诈链路。Louvain 帮你圈定嫌疑人,PageRank 帮你量化风险,最短路径帮你找到证据链。我在实际项目中,通常把这三个算法串成一个 pipeline,每天凌晨跑一次,第二天早上就能看到最新的欺诈团伙名单。

个人经验:我曾经在一个项目里只用了 Louvain,结果抓到了团伙但拿不出证据。后来加上最短路径追踪资金流向,才把整个链条打通。所以我的建议是:别偷懒,三个一起上。

好了,这一章的内容就到这里。图算法在反欺诈里的应用远不止这些,但 Louvain、PageRank 和最短路径是三个最基础也最实用的工具。你可以在自己的数据集上试试,看看能发现什么有意思的东西。

专注资料整理