案例一:设备指纹图谱特征衍生——从IP、设备ID、Cookie构建二部图

终于到了第一个完整案例。

前面几章讲了图的基础概念、特征衍生的思路。但说实话,光听理论是不够的。你想想看,真正拿到一笔数据,你知道怎么下手吗?

我个人习惯,从最经典的设备指纹图谱开始讲。为什么?因为设备层的数据最稳定,造假成本也最高。一个团伙可以换手机号,换身份证,但他很难换掉自己的设备环境。

1. 为什么选这三个实体?

IP、设备ID、Cookie。这三样东西,几乎每个互联网反欺诈系统都能拿到。但它们各自有弱点:

  • IP:容易共用,一个公司出口就一个IP。但结合其他设备信息,IP就能成为很好的关联桥梁。
  • 设备ID:IMEI、IDFA、OAID 这些。理论上唯一,但可以被篡改。我记得有个项目,20%的设备ID疑似被改过。
  • Cookie:容易被清除,但也是最细粒度的标识之一。有些用户每天清Cookie,有些半年都不清一次。

单独看任何一个,都不够。但把它们放到一张图里,局面就完全不一样了。

核心思路:用IP->设备ID->Cookie构建二部图,把人-设备-网络环境的关联关系结构化为图谱特征。

2. 二部图如何构建?

构建过程其实不复杂,我拆成三步走:

  1. 数据准备:提取请求日志中的IP、设备ID、Cookie字段。清洗掉空值和明显异常值(比如IP为0.0.0.0)。
  2. 建立边关系:同一个会话中出现的IP和设备ID连一条边,设备ID和Cookie连一条边。可以加权——同一个IP下出现3台设备,权重就是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. 避坑指南:二部图特征衍生常见的三个坑

我曾经在项目中踩过这些坑,分享给你:

  1. 时间窗口没对齐:把7天的数据和1小时的数据混在一个图里。结果是一个IP关联了100台设备,但那是7天累计的——其实每小时只有2台。解决办法:按时间窗口切分,分别建图。
  2. 特征不归一化:度数特征直接投入模型。但有些IP(比如云服务商)天然就有上万台设备,导致模型把正常云IP全判成欺诈。解决办法:度数特征除以子图规模,做归一化处理。
  3. 忽略孤岛节点:没有关联任何其他节点的孤立IP或设备,图特征为0。但孤立设备也可能是新设备,风险未知。解决办法:单独用一个维度标记是否为孤岛。

一句话总结:二部图是设备指纹特征衍生的基础框架,核心价值在于把点状信息转化为结构信息。特征的质量,取决于你对图结构的理解有多深。

下面这张图展示了从原始日志到图谱特征的全流程:

IP-设备ID-Cookie 二部图特征衍生流程 原始请求日志 提取IP/设备ID /Cookie字段 构建二部图 (IP组 + 设备Cookie组) 图谱特征 二部图结构详解 IP_A IP_B IP_C Dev_1 Dev_2 CK_1 CK_2 蓝:IP节点 | 橙:设备节点 | 青:Cookie节点 边代表“同一次请求中关联”

嗯,到这一步,二部图的构建和特征衍生基本就讲完了。这个案例虽然简单,但涵盖了图谱特征衍生的核心思想:把离散的实体,通过共现关系连成图,再从图的结构中提取信息量。