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 图谱数据模型总览
下图展示了反欺诈图谱的完整数据模型,包含实体、关系及关键属性:
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': '成功'}