四、节点特征与边特征工程

好,咱们今天聊聊特征工程。图神经网络的输入,说白了就是节点和边上的信息。你想想看,如果给模型喂的数据很烂,再牛的 GraphSAGE 也白搭。我在项目中见过太多这种情况:模型结构改来改去,效果纹丝不动,最后发现是特征没做好。

4.1 节点特征:不只是“你是谁”

节点特征分两类:固有属性和结构衍生特征。固有属性好理解,比如用户的年龄、性别、历史购买金额。但光靠这些,模型学不到图的结构信息。所以我们需要自己动手,造一些结构特征出来。

常用节点特征一览

特征类型 典型例子 何时使用
度中心性 节点的邻居数量 基础结构信息,几乎所有场景都需要
PageRank 节点在图中的“重要性” 社交网络、推荐系统,找“大V”节点
局部聚类系数 邻居之间的连接密度 社交网络中的“小团体”检测
K-core 值 节点所在的最密子图层级 识别图的核心与边缘节点

我个人习惯,拿到图数据第一件事就是算 度中心性。为什么?因为它在大部分场景下都有用,而且计算简单。我遇到过一个问题:一个交易网络里,有些节点明明很活跃,但度很高反而意味着风险。所以你别死板,要结合业务理解特征的含义。

如何生成节点特征?

用 NetworkX 库,几行代码搞定:

import networkx as nx

G = nx.karate_club_graph()

# 度中心性
degree_centrality = nx.degree_centrality(G)
# PageRank
pagerank = nx.pagerank(G)
# 局部聚类系数
clustering = nx.clustering(G)
# K-core
k_core = nx.core_number(G)
我的小技巧:把这些特征拼成一个矩阵,作为 GraphSAGE 的初始节点特征输入。你还可以把它们和原始属性拼接,效果往往更好。

4.2 边特征:连接也有“质量”

边特征决定了两个节点之间的关系强弱。在知识图谱里,边往往带有类型标签,比如“朋友”、“同事”、“家人”。但在很多场景下,我们还需要给边赋予权重。

常用的边特征工程方法

  • 边权重:交易金额、通话时长、共同好友数
  • 边类型编码:独热编码、Label Encoding
  • Jaccard 相似度:两个节点的共同邻居占比
  • Adamic-Adar 指数:对共同邻居取对数再求和,更关注稀有邻居

我曾经做过一个社交推荐项目。一开始只用“是否好友”这种 0/1 边特征,效果很差。后来我改成用共同好友数和互动频率做权重,模型 AUC 直接涨了 5 个点。你想想看,同样是朋友,天天聊天和一年说一次话,能一样吗?

避坑指南:我曾经把边权重直接归一化到 [0,1],结果一些边权重变得非常接近,模型学不到区别。后来改用对数变换再标准化,效果好多了。不建议直接用原始值,特别是金额这种长尾分布的数据。

4.3 特征衍生:从“原始”到“高级”

光有基础特征还不够。我们需要做一些交叉组合,让模型看到更多信息。

我的经典衍生策略

  1. 节点特征 × 边特征:比如“用户活跃度 × 联系人亲密度”
  2. 邻居特征聚合:取邻居特征的均值、最大值、标准差
  3. 图距离特征:计算两个节点之间的最短路径长度
  4. 子图特征:比如“两个节点是否在同一个三角结构里”

这里重点说一下邻居特征聚合。你不需要把所有邻居信息都塞进去,那样特征维度会爆炸。我一般只取 Top-K 重要邻居,或者用 GraphSAGE 自带的聚合函数(Mean、Pool、LSTM)来处理。

4.4 特征分箱与离散化

连续特征在图上往往不好处理。比如年龄 25 岁和 26 岁,对模型来说区别不大,但“青年”和“中年”的边界可能很重要。所以我们要做分箱。

分箱方法 适用场景 我的经验
等距分箱 数据分布均匀时 简单粗暴,但容易忽略分布
等频分箱 长尾分布时 常用方法,保证每箱样本量一致
聚类分箱 数据有明显簇结构 效果好但计算成本高,适合离线
决策树分箱 追求和标签强相关 我个人最喜欢,用 LightGBM 的叶子节点做箱

我习惯把分箱后的结果再做一个目标编码:用每个箱内的正样本比例代替原始值。比如“年龄 25-30 岁”这个箱,欺诈率是 10%,那所有在这个箱里的节点都填 0.1。这样既保留了分箱的泛化能力,又注入了标签信息。

核心思想:特征工程的本质是信息压缩与增强。你是在帮模型把原始数据转化为更容易学习的数学形式。做的越好,模型越聪明。

4.5 特征工程整体流程

来看一张图,总结一下我们今天的核心内容。

节点特征与边特征工程流程 原始图数据 节点属性 边关系 节点特征工程 度中心性 / PageRank 聚类系数 / K-core 边特征工程 边权重 / 类型编码 Jaccard / Adamic-Adar 特征衍生与交叉组合 节点×边 | 邻居聚合 | 图距离 | 子图特征 特征分箱与离散化 等距 / 等频 / 聚类 / 决策树 → 目标编码 GraphSAGE 输入特征 节点特征 + 边特征 注意 特征维度不要太高 建议做 PCA 或 选择 Top-K 特征 避免过拟合

流程不复杂:原始数据拆成节点和边,各自做特征工程,再交叉衍生,最后分箱离散化。我一般把这一步和后续建模分开,先离线跑完特征,保存成文件,训练时直接加载。这样效率高,迭代也快。

嗯,内容不少。节点特征、边特征、衍生、分箱,每一个环节都能深挖。但我建议你先从最简单的开始——比如先算个度中心性和 Jaccard 相似度,跑一版基线,看看效果。别一上来就想搞多复杂,图模型最怕的就是特征矩阵太大,跑都跑不动。