2. 图谱数据建模:实体、关系与属性设计

反欺诈图谱的核心在于将离散的日志数据转化为结构化的图表示。本章将定义图谱中的基本元素:实体(节点)、关系(边)和属性(节点/边的特征),为后续的回放验证与XGBoost特征工程奠定数据基础。

2.1 实体定义:图谱中的“节点”

实体是反欺诈场景中的参与对象。在金融交易反欺诈中,我们主要关注以下四类核心实体:

实体类型 英文标识 业务含义 典型示例
用户 User 账户持有者,交易发起方或接收方 user_id: U10001
设备 Device 用户操作所使用的物理设备 device_id: D-AABBCCDD
IP地址 IP 网络访问来源地址 ip_addr: 192.168.1.10
手机号 Phone 用户绑定的手机号码 phone: 138****0001
建模要点:实体ID必须全局唯一且稳定。建议使用业务主键(如user_id)作为图节点ID,避免使用自增ID,以便在回放验证时进行跨时间片的数据关联。

2.2 关系定义:图谱中的“边”

关系描述了实体之间的交互行为。在反欺诈图谱中,关系通常带有时间戳和方向性。我们定义以下三种核心关系:

  • 登录(Login):用户 → 设备/IP。表示用户在特定时间使用某设备或IP登录系统。
  • 交易(Transaction):用户 → 用户。表示资金从一方流向另一方,通常包含金额、时间等属性。
  • 转账(Transfer):用户 → 手机号。表示用户向某个手机号发起转账操作。
关系方向性:在反欺诈图谱中,关系方向至关重要。例如,“用户A登录设备D”与“设备D登录用户A”在语义上完全不同。我们统一采用“主体 → 客体”的方向建模。

2.3 属性设计:为节点和边赋予特征

属性是实体和关系的特征描述,是后续XGBoost模型特征提取的直接来源。属性设计应遵循“高区分度、低缺失率、业务可解释”原则。

2.3.1 实体属性

实体类型 属性名称 数据类型 示例值 说明
用户 注册时间 datetime 2024-01-15 10:30:00 账户年龄计算基础
账户等级 int 3 1-5级,等级越高风险越低
历史交易次数 int 127 累计交易笔数
设备 设备类型 string iPhone 15 Pro 用于设备指纹聚类
首次出现时间 datetime 2024-02-10 08:15:00 设备新鲜度判断
IP 地理位置 string 北京市朝阳区 异地登录检测
运营商 string 中国联通 代理IP识别
手机号 归属地 string 上海 与用户常驻地对比
是否虚拟运营商 boolean false 虚拟号段风险较高

2.3.2 关系属性

关系类型 属性名称 数据类型 示例值 说明
登录 登录时间 datetime 2024-03-01 14:22:00 时间序列分析基础
登录结果 string 成功/失败 失败次数统计
交易 交易金额 float 5000.00 金额异常检测
交易时间 datetime 2024-03-01 14:25:00 交易间隔计算
交易类型 string 消费/转账 行为模式分类
转账 转账金额 float 2000.00 与交易金额联动分析
转账时间 datetime 2024-03-01 14:26:00 转账频次统计

2.4 图谱数据模型总览

下图展示了反欺诈图谱的完整数据模型,包含实体、关系及关键属性:

反欺诈图谱数据模型 反欺诈图谱数据模型 用户 (User) user_id, 注册时间, 等级 设备 (Device) device_id, 类型, 首次出现 IP地址 (IP) ip_addr, 地理位置, 运营商 手机号 (Phone) phone, 归属地, 是否虚拟 登录 登录 交易 转账 属性设计原则 • 实体属性:描述静态特征,如注册时间、设备类型、IP地理位置 • 关系属性:描述动态行为,如登录时间、交易金额、转账结果 • 时间属性:所有关系和部分实体必须包含时间戳,支持时序回放 • 聚合属性:如“历史交易次数”等统计值,需在回放时动态计算 • 标签属性:如“是否虚拟运营商”,用于快速过滤高风险节点

2.5 属性设计避坑指南

常见错误:
  • 属性冗余:避免在多个实体中存储相同信息(如用户手机号同时存在User和Phone节点中),应通过关系关联。
  • 缺失时间戳:关系边必须携带时间戳,否则无法进行时间窗口回放和时序特征计算。
  • 属性类型混乱:金额字段统一使用float,ID字段统一使用string,避免类型转换错误。
  • 忽略空值处理:对于缺失属性(如设备类型未知),使用默认值或特殊标记,避免图算法报错。

2.6 数据建模代码示例

以下Python代码展示了如何使用NetworkX构建反欺诈图谱,并添加实体、关系及属性:

import networkx as nx
from datetime import datetime

# 初始化有向图
G = nx.DiGraph()

# 添加实体节点(用户、设备、IP、手机号)
G.add_node('U10001', type='User', reg_time=datetime(2024,1,15,10,30,0), level=3)
G.add_node('D-AABBCCDD', type='Device', device_type='iPhone 15 Pro', first_seen=datetime(2024,2,10,8,15,0))
G.add_node('192.168.1.10', type='IP', location='北京市朝阳区', isp='中国联通')
G.add_node('13800010001', type='Phone', location='上海', is_virtual=False)

# 添加关系边(登录、交易、转账)
G.add_edge('U10001', 'D-AABBCCDD', relation='Login', time=datetime(2024,3,1,14,22,0), result='成功')
G.add_edge('U10001', '192.168.1.10', relation='Login', time=datetime(2024,3,1,14,22,0), result='成功')
G.add_edge('U10001', 'U20002', relation='Transaction', time=datetime(2024,3,1,14,25,0), amount=5000.00, type='消费')
G.add_edge('U10001', '13800010001', relation='Transfer', time=datetime(2024,3,1,14,26,0), amount=2000.00)

# 验证图谱结构
print(f"节点数: {G.number_of_nodes()}")
print(f"边数: {G.number_of_edges()}")
print(f"节点属性: {G.nodes['U10001']}")
print(f"边属性: {G.edges[('U10001', 'D-AABBCCDD')]}")
输出结果:
节点数: 4
边数: 4
节点属性: {'type': 'User', 'reg_time': datetime.datetime(2024, 1, 15, 10, 30), 'level': 3}
边属性: {'relation': 'Login', 'time': datetime.datetime(2024, 3, 1, 14, 22), 'result': '成功'}