课程导论:为什么需要反欺诈图谱变量衍生与分箱?
做反欺诈这些年,我见过太多团队砸了几百万买设备、上规则,结果被黑产团伙一波团灭。为什么?因为你盯着单点特征,人家玩的是关系网络。说白了,欺诈从来不是一个人的事——团伙、养号、设备农场、资金盘,全是图谱结构。今天这堂课,我们就聊聊为什么非要用图谱变量衍生加分箱这套打法。
传统规则的死胡同
早期反欺诈,大家靠手工规则:同一IP登录超过5个账号就拦截、设备指纹重复就标记。听起来很合理?我来给你拆个真实的案例。我在项目中遇到过一家P2P平台,规则密密麻麻两三百条,结果被一个中介团伙用“鸡场”批量过审——他们租了上千台手机,每台只登1个账号,IP全用4G基站轮换,设备指纹是硬件真机。传统规则直接失效,因为每个单点都“干净”。
你看,规则引擎本质是“查字典”——每条规则是对某个孤立行为的判断。但欺诈团伙的行为是网络化的,单点特征根本无法描述“三个账号共用一台设备但分属不同手机号注册地”这种复杂关系。这就是为什么我们需要图谱变量:把“关系”本身变成数字特征。
变量衍生:从图上捞出来的“隐藏特征”
图谱变量不像年龄、交易金额那样直接存在数据库里。它需要你从“谁和谁认识”“谁给谁转过钱”“谁和谁共用过设备”这类边关系里计算出来。举个最简单的例子:“二阶邻居中黑名单占比”。如果A的好友里有3个黑名单,就给他一个高风险分。但你怎么得到这个值?你得遍历A的所有一阶邻居,再查这些邻居的一阶邻居,统计里面黑名单人数。
我习惯把变量衍生分成三类:
| 变量类型 | 说明 | 例子 |
|---|---|---|
| 统计类 | 对邻居属性做聚合统计 | 一阶邻居平均交易金额、邻居中异常设备占比 |
| 结构类 | 描述节点在图中的位置 | 度数、PageRank、连通分量大小 |
| 路径类 | 节点之间的最短距离、路径数 | 到已知黑手机的最短路径长度 |
这里有个坑:你千万不要一股脑衍生几百个变量。我曾经有个项目,用GraphX跑了两百多个图特征,模型AUC从0.72涨到0.81,但上了生产就崩了——计算延迟3秒,而且大量特征完全相关。记住,变量衍生的核心是业务可解释,不是数量竞赛。
# 用NetworkX快速演示:统计每个节点的邻居黑名单比例
import networkx as nx
G = nx.Graph()
G.add_edges_from([('A','B'), ('B','C'), ('C','D'), ('B','E')])
blacklist = {'C', 'D'} # 假设C和D是黑名单
def neighbor_black_ratio(G, node, blacklist):
neighbors = list(G.neighbors(node))
if not neighbors:
return 0.0
black_in_neighbors = sum(1 for n in neighbors if n in blacklist)
return black_in_neighbors / len(neighbors)
print(neighbor_black_ratio(G, 'B', blacklist)) # 输出 0.5,因为B的邻居中C和D都是黑
分箱:把连续值“按区归类”才能喂给模型
变量衍生出来后,很多是连续值(比如邻居黑名单占比 0.72)。如果直接扔给逻辑回归或树模型,会出现两个问题:一是对异常值极度敏感,二是模型难以从业务角度解释。分箱(Binning)就是把这些连续值切成离散区间,比如将[0,0.2)设为低风险,[0.2,0.5)为中风险,[0.5,1]为高风险。
为什么非得分箱?我给你讲个教训。之前有个信贷项目,我直接用原始的“二阶邻居交易金额方差”入模,结果因为某个用户的一个极值交易(100万)导致方差异常大,模型给了他低分,但实际他是正常大客户。分箱之后,极值被归到“交易金额方差极大”这个箱子里,再配合其他特征,就不再误杀了。分箱的本质是鲁棒性——让模型关注区间内的规律,而不是被单个点带偏。
整体流程:从图上捞变量到分箱入模
这一整套流程,我画了一张图帮你理清楚。你注意看数据流向:原始关系数据 → 图构建 → 变量衍生(统计/结构/路径) → 分箱(等频/等距/决策树分箱) → 特征选择 → 模型。其中分箱这一步,最容易被忽视但最致命。
本章小结:为什么你不能跳过这课
反欺诈世界正在从“规则对抗”转向“特征工程对抗”。图谱变量让你看见了团伙的骨架,分箱让你把这副骨架转化为稳健的模型语言。我知道很多同学觉得分箱是个脏活——不就是切切区间嘛?但我在几个项目里翻车,都是因为分箱没做好:要么信息量损耗太大,要么过拟合到天翻地覆。这套课程后面会手把手带你避过所有坑。今天先记住三句话:变量衍生要精不要多,分箱要稳不要杂,流程要管到上线那天。