案例一:设备指纹图谱特征衍生——从IP、设备ID、Cookie构建二部图
终于到了第一个完整案例。
前面几章讲了图的基础概念、特征衍生的思路。但说实话,光听理论是不够的。你想想看,真正拿到一笔数据,你知道怎么下手吗?
我个人习惯,从最经典的设备指纹图谱开始讲。为什么?因为设备层的数据最稳定,造假成本也最高。一个团伙可以换手机号,换身份证,但他很难换掉自己的设备环境。
1. 为什么选这三个实体?
IP、设备ID、Cookie。这三样东西,几乎每个互联网反欺诈系统都能拿到。但它们各自有弱点:
- IP:容易共用,一个公司出口就一个IP。但结合其他设备信息,IP就能成为很好的关联桥梁。
- 设备ID:IMEI、IDFA、OAID 这些。理论上唯一,但可以被篡改。我记得有个项目,20%的设备ID疑似被改过。
- Cookie:容易被清除,但也是最细粒度的标识之一。有些用户每天清Cookie,有些半年都不清一次。
单独看任何一个,都不够。但把它们放到一张图里,局面就完全不一样了。
核心思路:用IP->设备ID->Cookie构建二部图,把人-设备-网络环境的关联关系结构化为图谱特征。
2. 二部图如何构建?
构建过程其实不复杂,我拆成三步走:
- 数据准备:提取请求日志中的IP、设备ID、Cookie字段。清洗掉空值和明显异常值(比如IP为0.0.0.0)。
- 建立边关系:同一个会话中出现的IP和设备ID连一条边,设备ID和Cookie连一条边。可以加权——同一个IP下出现3台设备,权重就是3。
- 创建二部图结构:把IP作为一类节点(左侧),设备ID和Cookie作为另一类节点(右侧)。
嗯,这里要注意。二部图的意思是图可以被分成两组节点,边只存在于不同组之间。IP不能直接连IP,设备ID不能直接连设备ID。为什么要这样?
因为后续做特征衍生时,我们想计算的是跨域关联度。如果IP和设备ID混在一起,很多图算法(比如汉明距离)的效果会变差。
我踩过的坑:曾经把IP和设备ID直接放到同一个节点集合里,跑Louvain社区发现,结果一团糟——十几个IP全被聚到一个社区,因为它们的设备ID都一样。后来改成二部图,社区才变得有意义。
3. 从二部图中衍生什么特征?
图建好了,特征怎么挖?我这里列出最常用的5种图谱特征:
| 特征类别 | 特征名称 | 计算方式 | 反欺诈含义 |
|---|---|---|---|
| 度数特征 | IP关联设备数 | IP节点在二部图中的度数(直接邻居个数) | 一个IP下关联了超过50台设备,极可能是代理IP |
| 度数特征 | 设备关联IP数 | 设备ID节点在二部图中的度数 | 一台设备关联了多个不同地域的IP,可能是模拟器 |
| 二阶关联 | 共享设备率 | 通过IP链接的设备的数量 / 总数 | 团伙标签,多台设备共用一个出口 |
| 社区特征 | 子图规模 | 连通分量中的节点总数 | 子图越大,团伙可能性越高 |
| 结构特征 | 星型中心度 | 单个IP连接的设备数 / 子图总设备数 | 分值接近1时,说明这个IP是所有设备的“集结点” |
这些特征不是拍脑袋想出来的。我在项目中遇到过,团伙作案的典型模式就是:少量IP对应大量设备,设备之间几乎没有直接关联。这个结构特征直接在图上就能看出来。
4. 特征衍生实战:从图到表格
图特征算完,最终还是要落回表格,用于模型训练。我给你写一段最简化的Python代码思路:
import networkx as nx
# 构建二部图
B = nx.Graph()
# 添加IP节点(group 0)和设备节点(group 1)
B.add_nodes_from(ip_list, bipartite=0)
B.add_nodes_from(device_list, bipartite=1)
# 添加边:IP -> 设备
B.add_edges_from(ip_device_pairs)
# 计算IP的度数特征
ip_degree = dict(B.degree([n for n, attr in B.nodes(data=True)
if attr['bipartite'] == 0]))
# 计算共享设备率
for ip in ip_list:
neighbors = list(B.neighbors(ip))
if neighbors:
devices_count = len(neighbors)
# 计算通过这些设备能到达的所有IP
second_hop_ips = set()
for dev in neighbors:
second_hop_ips.update(B.neighbors(dev))
share_rate = len(second_hop_ips) / max(devices_count, 1)
注意:真实场景中,图规模可能是百万级节点。直接用NetworkX会爆内存。我一般用Spark GraphX或者自己实现邻接表。上面代码只适合小样本验证思路。
5. 案例效果:一条真实的反欺诈链路
我拿一个实际项目的数据来说:
- 原始特征(IP、设备ID、Cookie)共37个字段
- 衍生出图特征后,特征维度变成了128个
- 单独用原始特征训练的模型AUC为0.72
- 加入图特征后,AUC提升到0.87
为什么会提升这么多?
因为原始特征只能看到点的信息——这个IP过去有没有被标记过?这个设备是不是已知黑产?
但图特征能看到关系的信息——这个IP下挂了5台设备,其中3台曾经关联过诈骗账户。这个信号在单点特征里是看不到的。
6. 避坑指南:二部图特征衍生常见的三个坑
我曾经在项目中踩过这些坑,分享给你:
- 时间窗口没对齐:把7天的数据和1小时的数据混在一个图里。结果是一个IP关联了100台设备,但那是7天累计的——其实每小时只有2台。解决办法:按时间窗口切分,分别建图。
- 特征不归一化:度数特征直接投入模型。但有些IP(比如云服务商)天然就有上万台设备,导致模型把正常云IP全判成欺诈。解决办法:度数特征除以子图规模,做归一化处理。
- 忽略孤岛节点:没有关联任何其他节点的孤立IP或设备,图特征为0。但孤立设备也可能是新设备,风险未知。解决办法:单独用一个维度标记是否为孤岛。
一句话总结:二部图是设备指纹特征衍生的基础框架,核心价值在于把点状信息转化为结构信息。特征的质量,取决于你对图结构的理解有多深。
下面这张图展示了从原始日志到图谱特征的全流程:
嗯,到这一步,二部图的构建和特征衍生基本就讲完了。这个案例虽然简单,但涵盖了图谱特征衍生的核心思想:把离散的实体,通过共现关系连成图,再从图的结构中提取信息量。