# 01 · 任务定义与数据集(第一性原理) > 本文档面向"懂一点 ML 但不完全熟悉图推荐系统"的读者,从**为什么**出发讲清楚 CS3319 Project 2 究竟在做什么、为什么它本质上是一个异构图上的链路预测问题、五个数据文件各自代表什么,以及为什么我们必须把它当成图问题、而不是表格二分类来解。所有数字与仓库内权威事实表一致。 --- ## 1. 一句话定位:这是一个"学术阅读推荐"任务 CS3319 Project 2 给你一个学术网络:6,611 名**作者(author)**、79,937 篇**论文(paper)**,以及作者↔论文、作者↔作者、论文→论文三类边。任务的核心问题是: > **给定一个 (作者, 论文) 对,请预测该作者是否"会读/该读"这篇论文。输出 1(推荐)或 0(不推荐)。** 这正是**推荐系统(rec recommender system)**最经典的形式之一:二部图上的**链路预测(link prediction)**。所谓"链路预测",就是在一张已知部分连边的图上,预测两个节点之间**未来是否会出现一条边**。这里"边"的语义是"作者读这篇论文",所以预测边 = 给作者推论文 = 阅读推荐。 测试集一共有 **2,047,262** 对(≈2.05M)(`data_and_docs/bipartite_test_ann.txt`),我们要为每一对输出 0/1,提交 CSV 两列 `Index,Predicted`,公开榜(leaderboard)**只在 50% 的测试集上评分**(`data_and_docs/project_evaluation.md`),评估指标是 **F1-Score**。 ### 1.1 为什么 author-paper pair 等价于链路预测 把作者放一列、论文放一列,二部图(bipartite graph)只有"作者→论文"这种跨类型的连边,不存在"作者→作者"在同一侧的连边(那属于合著网,是另一张图)。在这个二部图上: - **训练集** `bipartite_train_ann.txt`(682,421 行)= **已存在的边(正样本)**,即作者历史上读过/引用过的论文; - **测试集** `bipartite_test_ann.txt`(2,047,262 行)= **一组候选 (作者,论文) 对**,问你这些对里**哪些会成边**。 这正是链路预测的标准设定:已知边学结构,对未见对打分并切阈值。"成不成边"在推荐语境里就是"推不推荐",所以本文档把"链路预测/边预测/推荐打分"三者等同使用。 --- ## 2. 节点与边的第一性原理拆解 ### 2.1 两类节点 | 节点类型 | id 范围 | 数量 | 是否有初始特征 | |---|---|---|---| | author | 0 – 6610 | **6,611** | 无(只能从图结构学) | | paper | 0 – 79936 | **79,937** | 有:512 维 USE 句向量 | **关键不对称**:只有论文带初始内容特征(`feature.pkl` 是 `(79937, 512)` 的 `torch.float32` 张量,即每篇论文一个 512 维 Universal Sentence Encoder 向量,来源 `dataset.md`)。**作者没有显式属性向量**——这一事实决定了后续建模:作者侧特征必须靠"邻居聚合"(作者读过的论文的向量、合著者读过的论文)来构造。这也正是 LightGCN、DeepWalk/Node2Vec、高阶引用传播等方法存在的根本理由:它们都是把论文侧的内容/结构信息**传播**到作者侧。 ### 2.2 三类边及其方向语义 | 边类型 | 文件 | 行数 | 方向 | 语义 | |---|---|---|---|---| | author → paper(二部) | `bipartite_train_ann.txt` | 682,421 | author→paper | 作者读过/引用了该论文(正样本边) | | author ↔ author(合著) | `author_file_ann.txt` | 9,663 | **无向** | 两位作者合作过(`dataset.md`:"two authors have cooperated") | | paper → paper(引用) | `paper_file_ann.txt` | 327,113 | **有向**:前者 cites 后者 | 行内第一列=引用者(citing),第二列=被引用者(cited) | > **方向是后续建模的硬约束**。引用边是有向的(论文 A 引用论文 B ≠ B 引用 A),因此最终方法里高阶传播才分 `fwd / bwd / undir` 三向(见 `code/high_order_graph_stack.py` 的 `build_high_order*`,以及 `H_k = R·C^k` / `G_k = S·R·C^k` 公式)。合著边天然无向,所以在邻接矩阵里双向拼接。这些都是从数据本身的方向语义自然推出的设计选择,不是拍脑袋。 ### 2.3 文件样例(本审计实测 head) ``` bipartite_train_ann.txt "2844 39942" # 作者2844 读 论文39942 author_file_ann.txt "5349 278" # 作者5349 与 作者278 合著 paper_file_ann.txt "19068 75036" # 论文19068 引用 论文75036 ``` 注意 `paper_file_ann.txt` 里 `19068` 连续出现在多行(如 `19068 75036`、`19068 37541`)——这是真实学术网络里**一篇综述/高被引论文向外大量引用**的长尾现象,也是合著/引用网高度稀疏、幂律分布的直接证据。 --- ## 3. 五个数据文件逐一定义 这是本文档的核心。每个文件讲四件事:**存什么、在图里是什么、模型里怎么用、论文里怎么写**。 | 文件 | 内容 | 图意义 | 在模型中的作用 | 在论文中怎么写 | |---|---|---|---|---| | `bipartite_train_ann.txt` | 682,421 行 `author paper` 对,已知正边 | 二部图的**已观测正边** | (1) LightGCN/BPR-MF 的 BPR 正样本源;(2) 留出 10% 作验证正例(见 §4);(3) `test_known_mask.npy`:凡是测试对也出现在此的,提交时强制预测 1 | "the observed author–paper interactions, used as positive supervision and for the held-out validation split" | | `bipartite_test_ann.txt` | 2,047,262 行 `author paper` 对,待预测 | 二部图上**待判定的候选边** | 对每一对算最终 LightGBM 分数,按 score 排序取 top 50% 预测为 1,再叠加 known-mask | "the set of candidate author–paper pairs to be scored; the submission predicts the top-ranked 50% as positives" | | `author_file_ann.txt` | 9,663 行 `a1 a2` 无向合著边 | author-author **同构**子图 | (1) LightGCN 异构图里一条边类型;(2) 高阶传播 `G_k = S·R·C^k` 中合著矩阵 S 的来源——把**合著者读过的论文**也作为候选证据;(3) 硬负采样里的 coauthor_pool(`code/train_val_lgcn_ensemble.py:273-305`) | "the undirected co-authorship graph, providing the structural matrix S for higher-order propagation G_k = S·R·C^k" | | `paper_file_ann.txt` | 327,113 行 `p_citing p_cited` 有向引用边 | paper-paper **有向**子图 | (1) 引用矩阵 C(及转置 Cᵀ);(2) **高阶引用传播的核心**:作者历史论文经 k 步引用扩散 `H_k = R·C^k` 到候选论文——这是最终方法把公开 F1 从 0.96252 提到 0.96626 的关键增量 | "the directed citation graph; its adjacency C powers the higher-order propagation H_k = R·C^k" | | `feature.pkl` | `(79937, 512)` `torch.float32`,约 156 MB | **论文节点的内容属性**(USE 句向量) | (1) LightGCN 论文节点 515→embed 的投影输入;(2) content-mean-cos、top-k content similarity、18 维 rich content profile 的直接来源 | "512-d USE sentence embeddings for each paper, serving as node attributes and the basis for all content features" | **load 约定**(直接进代码):`feature.pkl` 用 `pickle.load` 后取 `.numpy()`;每行 `a p` 即一条边/一对;边文件均空格分隔两列整数。 --- ## 4. 训练集 vs 测试集 vs 验证集(三种"集"别混) 这三者经常被混淆,但它们是三件不同的事: | 名称 | 来源 | 规模 | 正负比例 | 用途 | |---|---|---|---|---| | 训练集(train) | `bipartite_train_ann.txt` 的 90% | ≈614,179 条正边 | 全是正样本 | 学模型参数 | | **验证集(val)** | 留出 train 的 10% 正边 + 等量随机非边 | **136,484 对** | **人工 1:1** | leak-free 选模型/阈值(不参与提交) | | 测试集(test) | `bipartite_test_ann.txt` | 2,047,262 对 | **正例比例未知** | 最终提交,公开榜评其中 50% | 验证集由 `make_notebook_style_split(root, seed=202, train_frac=0.9)` 构造(`code/train_val_lgcn_ensemble.py:132-165`): ``` 留出 10% 训练正边作验证正例 = round(682421 × 0.1) = 68,242 条 再随机采样 68,242 条"非边"(不是正样本的对)作验证负例 → 验证集 = 68,242 正 + 68,242 负 = 136,484 对,刻意 1:1 ``` **为什么验证集要人工造 1:1**:真实测试集正负极度不平衡(几十万正边 vs 数亿可能负对),但 1:1 的小验证集方便用 **StratifiedKFold OOF** 算一个 leak-free 的 F1 来横向比较模型。代价是:1:1 是"人造的",和真实测试分布**有偏移**——这正是最终提交不用概率阈值、而用 rank cutoff 的根本原因(见 §6)。 > **load-bearing 警告**:切分 seed 烘焙进了每个 score/feature 文件名(`val_*seed202*`)。换 `--split-seed` 会让**整条流水线作废**,必须端到端重算。仓库内所有缓存产物只对 seed=202 有效。 --- ## 5. 为什么是"异构图"而不是"表格二分类" 把 (作者,论文) 对当成表格行、各做几个统计特征、丢进 LightGBM 做 0/1 分类——这看起来也能跑。为什么官方和我们的最终方法都坚持异构图? **第一性原理**:这个任务的信号**不在节点属性里,而在跨类型关系里**。一张表能编码"作者读了多少篇论文、论文被多少人读",但编码不了下面这种**跨 2~3 跳的结构路径**: - **A-P-P^k(高阶引用传播)**:作者读过的论文,引用了哪些论文?那些被引论文再引用了哪些?k 步扩散后落到候选论文上的"证据强度"——这就是 `H_k = R·C^k`。 - **A-A-P-P^k(合著传播)**:我的合著者读过的论文,经引用扩散到候选——这是 `G_k = S·R·C^k`。 - **A-P-A-P(meta-path)**:和我读过同一篇论文的其他作者,还读了什么? 这些是 **meta-path / 高阶图结构**特征,纯表格二分类**结构上无法表达**(你需要在 2~3 跳的异构邻居上做矩阵乘法)。官方任务说明明确要求"Build a heterogeneous network, which contains two types of nodes"(`data_and_docs/project_description.md`),三类边混合正是为了让这些跨类型路径可计算。 **实证**:最终方法把高阶有向引用传播叠到 LightGCN+随机游走+内容特征之上,验证 F1 从 0.9649 → **0.9669**、公开 F1 0.96252 → **0.96626**。这个增量**只来自图结构**,没有任何新数据——直接证明了图建模不可替代。 ### 异构 vs 同构 - **同构图(homogeneous)**:所有节点/边同类(如纯合著网、纯引用网)。DeepWalk/Node2Vec 默认在同构图上游走。 - **异构图(heterogeneous)**:节点/边多类型。本任务 author 与 paper 是两类节点,必须用异构图(或把二部/合著/引用拼成多关系图)。LightGCN 在 `build_data` 里把 4 种边类型一起塞进 PyG `HeteroData`(`code/train_val_lgcn_ensemble.py:239-270`)。 --- ## 6. 为什么稀疏 + 长尾 = 难,以及为什么 F1 比 accuracy 重要 ### 6.1 稀疏度(实测计算) | 量 | 计算 | 值 | |---|---|---| | 二部图正边密度 | 682,421 / (6,611 × 79,937) | 682,421 / 528,184,207 ≈ **1.29e-3** | | 合著边相对节点对 | 9,663 / (6,611²) | 9,663 / 43,705,321 ≈ **2.2e-4** | | 长尾 | 56% 作者度=1(只读过 1 篇) | — | 二部图正边密度仅 **0.13%**:99.87% 的 (作者,论文) 组合**没有**观测边。这意味着: 1. **绝大多数候选对是负样本**,正样本极度稀有 → 类别严重不平衡。 2. **冷启动**:56% 作者只有 1 条历史记录,行为信号近乎为零,纯协同过滤(CF)对这些作者失效——必须靠**内容特征**(USE 向量)+**图结构传播**(高阶引用/合著扩散)补足。 ### 6.2 长尾 合著网与引用网都是幂律分布:少数高产出作者/高被引论文占据大量边(如前述 `19068` 反复出现)。长尾节点(度=1 的作者)在 CF 里几乎没有邻居可聚合,这是为什么方法栈里要混入 **DeepWalk/Node2Vec**(全局游走接近度)和**内容画像**,而不能只靠 LightGCN 的局部邻居聚合。 ### 6.3 为什么用 F1 而非 accuracy 若用 accuracy:模型只需把**几乎所有**测试对都预测为 0(因为真实正例比例低),accuracy 看起来很高却完全没用——它根本没"推荐"到任何东西。F1 = $2 \cdot P \cdot R / (P + R)$ 同时考虑: - **Precision** = tp/(tp+fp):推荐出去的,有多少真是该读的; - **Recall** = tp/(tp+fn):真正该读的,有多少被推荐出来了。 F1 对"假负"(漏推)和"假正"(乱推)都敏感,在类别不平衡的推荐/检索场景下是标准指标。这也解释了**最终决策为什么是 rank cutoff top 50%**(`submission_rich_rw7_highorder_directed_r0.500000.csv`):1:1 人工验证集算出的"最优概率阈值 0.4617"**无法迁移**到真实测试分布(迁移后正例率漂移到 0.5242),因为 LightGBM 概率在 val→test 间不校准。所以改成"按分数排序、固定取 top 一半"的**排序式决策**,绕开概率校准问题。 > **课程规则约束**(`data_and_docs/project_description.md`):禁抄袭(提交后查重)、禁从别处下载同源数据集、禁用预训练模型(须从零构建)。注意 `feature.pkl` 的 USE 向量是**官方提供、人人可用**的节点属性,不属于"预训练模型"违规——这是数据的一部分,不是我们训练的。 --- ## 7. 可迁移到论文中的写法 以下是可直接进 ACM 中文论文 TeX 的正式表述,已校准所有数字与方向语义。 > **任务形式化(Formalization)。** 给定异构学术网络 $\mathcal{G}=(\mathcal{V}_a \cup \mathcal{V}_p, \mathcal{E}_{ap} \cup \mathcal{E}_{aa} \cup \mathcal{E}_{pp})$,其中 $|\mathcal{V}_a|=6{,}611$ 名作者、$|\mathcal{V}_p|=79{,}937$ 篇论文。$\mathcal{E}_{ap}$ 为 author→paper 二部交互边(682,421 条已知正边),$\mathcal{E}_{aa}$ 为无向合著边(9,663 条),$\mathcal{E}_{pp}$ 为**有向**引用边 $p_i \to p_j$($p_i$ 引用 $p_j$,327,113 条)。论文节点附带 512 维 USE 句向量 $X_p \in \mathbb{R}^{79937 \times 512}$;作者节点无初始属性。任务对 2,047,262 个测试对 $(a, p)$ 预测 $y \in \{0,1\}$,以 **F1** 为指标,公开榜评其中 50%。 > > **为何是链路预测。** 该问题即二部图上的链路预测:$\mathcal{E}_{ap}^{\text{train}}$ 为观测正边,$\mathcal{E}_{ap}^{\text{test}}$ 为待判候选对;预测"作者 $a$ 是否会读论文 $p$"等价于判定未观测对上是否存在潜在正边。 > > **为何需要异构图建模。** 信号高度依赖跨类型路径而非节点属性:作者侧无初始特征,须由论文侧内容经邻接矩阵传播得到。我们因此定义高阶引用传播 $H_k = R \cdot C^k$($R$ 为 author-paper 二部邻接,$C$ 为引用邻接,$k$ 步扩散)与合著传播 $G_k = S \cdot R \cdot C^k$($S$ 为合著邻接),分别沿 forward/backward/undirected 三向计算。此结构信号在最终方法上将公开 F1 由 0.96252 提升至 0.96626,验证集 1:1 OOF F1 由 0.9649 提升至 0.9669。 > > **评估与决策。** 数据呈长尾稀疏分布(二部图正边密度 $1.29\times10^{-3}$,约 56% 作者度数为 1),类别极度不平衡,故采用 F1 而非 accuracy。考虑到人工 1:1 验证集(留出 10% 正边 + 等量随机非边,共 136,484 对)与真实测试分布存在偏移,最终提交采用**排序式决策**:按预测分数对测试对排序,取 top 50% 为正预测,并强制与训练集重叠的已知正边为 1。 --- *本文档所有数字经仓库内 `wc -l` 实测与权威事实表交叉核验;方向语义以 `dataset.md` 为准;F1 以标准 $2PR/(P+R)$ 为准(`project_evaluation.md` 中缺因子 2 的表述判定为笔误)。*