这道 Open Data St.Gallen 竞赛表面与分类有关,实际更接近议会事务文本的多标签推荐与排序任务。评价指标采用 MAP@K,决定了建模重点不只是判断标签是否相关,而是让真正有价值的结果尽量排在前列。
这类题目很适合用来训练真实项目能力,因为公共文本服务并不只需要一个预测标签,更需要可用于检索、归类和知识关联的结果列表。围绕文本清洗、标签结构识别、基线模型搭建、语义表示与排序优化展开,能够完整覆盖从数据理解到原型落地的关键环节。
文章目录
赛题概述
本案例地址 Open Data St.Gallen。
这是一道以公共文本数据为基础的推荐系统实战题,核心任务并非传统商品推荐,而是围绕议会事务分类与相关推荐构建排序能力,更接近政务信息检索与知识发现的应用场景。赛题规模不大,但问题非常真实:需要从文本语义表示、候选召回、相关性排序到结果评估形成完整链路,对自学者而言,适合练习文本推荐建模、离线验证设计、MAP@K 指标理解,以及把机器学习方案转成可解释业务工具的能力。
| 模块名称 | 内容简介 | 所需技能 | 数据类型 | 应用场景 |
|---|---|---|---|---|
| 赛题背景 | 该题属于基于开放政务数据的文本推荐与检索项目,关注的是如何从议会事务、政策文本等信息中发现语义相关内容,帮助使用者更高效地定位相近议题、历史案例或关联事务。与常见电商推荐不同,这类任务更强调文本理解、信息组织和公共信息服务价值,属于具有明确现实落地方向的小型应用型竞赛。 | 需要具备问题抽象能力,将"找相似议会事务"转化为召回与排序问题;还需要文本表示学习、特征工程、推荐建模与结果解释能力。 | 以结构化标签配合文本内容为主,实际完成过程中通常会涉及标题、摘要、事务描述、主题词、类别信息及自建验证样本。 | 公共服务数字化、政务知识检索、政策信息导航、法规与议题关联发现、机构内部知识管理。 |
| 竞赛目标 | 参赛方案需要输出一套能够为目标议会事务生成相关推荐结果的排序系统,本质上是构建可运行的文本推荐流程,而不是只做单点分类。高质量方案通常不仅要给出预测结果,还要体现候选生成、相似度建模、排序优化和离线评估设计的完整技术路线。 | 需要掌握文本向量化、语义相似度建模、候选召回、排序优化、验证集构造,以及把实验过程组织成可复现原型的工程化思维。 | 核心是文本语料与关联关系数据,可能结合类别字段、历史共现关系、人工标注相关性对,以及基于语义嵌入构建的中间特征。 | 政务推荐引擎、法规检索助手、公共信息发现系统、行业文档推荐工具、知识服务型原型开发。 |
| 评价指标 | 赛题采用 MAP@K 作为核心评估方式,重点考察推荐列表前部结果的平均命中质量,不只是判断是否找对相关项,更关注相关结果在排序中的靠前程度。这意味着方案设计不能停留在粗粒度召回,而需要围绕"前几条是否真正有用"优化排序表现。 | 需要理解排序学习与信息检索评测逻辑,能够围绕 Top-K 结果做特征设计、模型比较、误差分析和离线实验复盘。 | 涉及推荐列表、相关项标签、排序分数、候选集结果,以及用于本地复现实验的验证划分数据。 | 搜索排序优化、知识库问答检索、内容分发系统、政务信息推荐等依赖前列结果质量的真实业务场景。 |
| 业务意义 | 这类赛题对应的真实价值,在于把分散、冗长且难以浏览的公共文本资料转成可搜索、可关联、可推荐的信息服务能力。实际项目中,这种能力可以减少人工查找成本,提升议题分析效率,也能为公共机构构建更可用的数字知识入口,体现推荐系统在非商业场景中的落地潜力。 | 需要把算法效果与业务可用性结合起来思考,包括结果可解释性、系统可维护性、数据更新机制和面向使用者的交付表达。 | 除原始文本外,还会延伸到业务规则、知识目录、人工反馈数据、场景化查询输入和持续更新的数据资产。 | 公共服务数字化平台、政策研究辅助系统、行业知识助手、非商业信息服务产品、组织级知识发现系统。 |
数据详解
这场竞赛在数据组织上呈现出比较典型的 Kaggle 社区项目特征:真正与建模相关的信息并不分散,核心线索主要集中在任务标题、简短概述、评价指标、数据入口以及少量提交约束中。题面信息显示,任务背景与议会事务分类有关,但竞赛又被归入推荐系统方向,并采用 MAP@K 作为评价指标,这说明目标并不只是做单标签分类,更可能是在候选标签或候选结果中输出一个有顺序的推荐列表,系统关注的是"正确结果是否排在前面"。这类任务在真实业务中很常见,例如政策主题归类、知识库条目推荐、工单路由、文档标签分发,本质上都属于带排序约束的多候选预测问题。阅读结构化字段时,重点不应放在论坛 ID、组织 ID、是否启用某些平台功能之类的管理元数据上,而应聚焦那些能够回答"任务要预测什么、结果如何评分、数据从哪里获取、提交受什么限制、比赛是否有现实激励约束"的字段。当前这份结构化数据还存在一个明显特点:数据文件说明、标签字段定义、数据规模等细节没有直接展开,这意味着真正开始建模前,仍需进入数据页面核对文件结构、主键关系、目标列形式以及训练集与测试集的拆分方式,不能仅凭平台摘要就直接设计算法流程。
| 字段名称 | 类型/范围 | 描述信息 |
|---|---|---|
| competition_title | 字符串 | 竞赛主标题为 Open Data St.Gallen,用于识别项目来源与公开数据背景。标题本身信息量有限,但结合数据入口可判断这是一个基于开放政务或公共事务数据的建模任务。 |
| competition_subtitle | 字符串/空值 | 副标题为空,说明平台摘要没有提供额外业务补充。缺少副标题时,需要更多依赖 overview、数据页和代码案例来还原任务场景。 |
| overview | 字符串 | 概述为德语 "Klassifikation von Parlamentsgeschäften (Recommender)",可理解为"议会事务分类/推荐任务"。这直接揭示了业务对象是议会相关事项,任务形式带有推荐或排序色彩,不宜简单按普通分类赛题处理。 |
| category_level_1 / category_level_2 | 字符串 | 平台归类为 推荐与检索 / 推荐系统。该归类有助于判断建模方向:输出往往不是单个类别,而是按相关性排序的一组候选结果,评价方式也更接近排序学习而非纯准确率优化。 |
| tags | JSON 数组 | 标签中仅给出 MAP@{K},说明竞赛最关键的技术信号来自评价指标。标签数量不多,但已经足以提示该任务强调 Top-K 排序质量,适合关注召回、候选排序、文本相似度、语义嵌入等方法。 |
| evaluation_algorithm_name | 字符串 | 评价指标为 MAP@{K},即"前 K 个结果的平均准确率均值"。该指标要求预测结果不仅包含正确项,还要尽量排在靠前位置,对推荐系统、标签排序、多候选匹配任务尤其重要。 |
| evaluation_algorithm_abbreviation | 字符串 | 指标缩写记录为 M,实际参考价值不大,但可与完整指标名对应,避免误读平台缩写。真正有用的是完整指标名称和其排序导向。 |
| enabled_date | 时间 | 比赛开放时间为 2022-02-22 19:21:53。该字段对建模没有直接影响,但能帮助判断赛题所处时间背景,以及参考代码是否可能使用较新的预训练模型或工具链。 |
| deadline_date | 时间 | 报名截止时间为 2031-01-01 07:59:00。这一异常偏长的开放周期说明它更像持续开放的社区练习赛,而不是短周期奖金竞赛,适合用于长期练手、复现实验和方法对比。 |
| team_merger_deadline_date | 时间 | 队伍合并截止时间同样为 2031-01-01 07:59:00。对个人学习影响较小,但表明竞赛规则整体较宽松,不是高压赛制。 |
| max_daily_submissions | 整数 | 每日最多提交 5 次。这个限制会直接影响实验策略,意味着本地验证方案必须可靠,不能依赖频繁线上试错。对排序任务而言,离线交叉验证设计尤其关键。 |
| max_team_size | 整数 | 最大组队人数为 10。对技术方案本身影响不大,但说明竞赛允许协作式探索,适合多人分工做特征、文本表示、排序模型和误差分析。 |
| reward_type / reward_quantity / num_prizes | 字符串/数值/空值 | 奖励相关字段均为空,说明这不是以奖金驱动的正式商业竞赛,更偏向学习、研究或公开数据实践场景。对读者而言,这意味着关注重点应放在任务价值与方法训练,而不是竞赛收益。 |
| total_teams | 整数 | 参赛队伍数为 9。样本外竞争压力较小,排行榜参考意义有限,更适合作为结构化文本推荐任务的练习项目,而不是依赖榜单验证方法优劣。 |
| dataset_url | URL 字符串 | 数据下载入口是最关键的实操字段之一,所有真正的建模工作都要从这里展开。结构化摘要没有展开文件细节,因此必须进入该页面确认训练集、测试集、样本主键、标签格式及提交样例。 |
| dataset_description | 字符串/空值 | 数据集描述为空,说明平台摘要没有提供文件级解释。这会增加前期数据理解成本,建模前需要自行检查字段含义、缺失情况、文本内容长度以及标签组织方式。 |
| total_compressed_bytes / total_uncompressed_bytes | 整数/空值 | 数据规模字段为空,无法直接判断训练成本。实际项目中,这会影响是否采用大型文本嵌入模型、是否需要批处理编码、是否能在本地完成全量实验。 |
| description | Markdown 长文本/空值 | 竞赛长描述为空,意味着题面上下文较少。业务理解不能只依赖平台首页,需要结合数据文件、公开 Notebook 以及提交格式反推真实任务定义。 |
| rules | Markdown 长文本/空值 | 规则说明为空,没有额外限制可供参考。缺少规则细节时,重点应转向提交格式、评分逻辑和外部数据使用边界,避免因默认假设错误而影响实验设计。 |
| case_details | JSON 对象 | 平台附带了一条代码案例信息,其中包含 SentenceEmbeddings Notebook,公开分数约为 0.83225。这条信息虽然不是官方规则的一部分,但对方法选择很有价值,说明基于句向量或语义表示的文本匹配方案具有可行性。 |
| has_kernels / only_allow_kernel_submissions 等平台控制字段 | 布尔值/空值 | 这类字段主要描述平台是否启用 Notebook、排行榜或某些提交机制,属于平台运行元数据。除非直接影响提交流程,否则对理解任务与建模帮助有限,可作为补充信息而非核心阅读对象。 |
| forum_id / organization_id / host_name 等平台管理字段 | 字符串/空值 | 这类字段主要用于平台内部组织与页面索引,不参与任务定义、数据理解或建模设计。阅读竞赛结构化数据时可以直接降权处理,避免信息噪声。 |
| 目标标签字段 | 未提供 | 当前结构化摘要没有给出明确的目标列名称,也没有说明是单标签、多标签还是候选排序格式。这是进入数据页后必须优先确认的信息,因为它会直接决定损失函数、验证方式、提交文件结构和特征工程路线。 |
| 数据文件说明 | 未提供 | 训练集、测试集、样例提交文件、辅助表是否存在,当前摘要均未展开。真实建模中,这部分信息决定任务是单表预测、文本匹配,还是需要多表关联与候选生成。 |
| 数据规模 | 未提供 | 样本量、特征列数量、文本字段长度、标签基数都未在摘要中展示。对于推荐与排序任务,这些信息会直接影响是否采用传统稀疏表示、梯度提升树、浅层排序模型,或语义向量检索方案。 |
解题思路
这类赛题表面上属于文本分类,实际更接近"面向排序的标签推荐"问题,因此天然适合多条建模路线并行推进。原因在于,文本侧既可以从词频、关键词、共现关系中提取稳定信号,也可以借助语义向量和预训练语言模型捕捉更深层的上下文含义;目标侧又不是单纯预测单一类别,而是需要围绕候选标签给出排序结果,并用 MAP@K 评估前若干个推荐标签的质量。这意味着,轻量方法在建立可靠基线、理解数据分布、验证标签不平衡问题时很有价值,语义模型在处理近义表达、长文本上下文、标签边界模糊时更有优势,而融合方案则更适合针对排序指标做最后优化。对于自学者和实战项目而言,合理路径不是只押注某一种模型,而是围绕"规则基线---稀疏文本表示---语义表示---深度模型---排序优化"逐步推进,在可解释性、训练成本和最终分数之间找到平衡。
| 方法标题 | 案例适配度 | 方法说明 | 操作流程 | 优点 | 缺点 |
|---|---|---|---|---|---|
| 关键词规则与标签词典基线 | 68% | 围绕议题文本中高频政治术语、机构名称、主题词构建标签词典,用关键词匹配和统计共现完成初步标签推荐,属于规则与统计特征路线。对于公开数据、标签语义较明确的议会事务文本,这类方案适合快速形成可提交基线。 | 清洗文本并统计标签相关关键词;为每个标签整理词典和共现词;按匹配强度对标签打分;输出前 K 个标签;结合验证集微调匹配权重。 | 上手成本低,解释性强,适合快速理解文本主题与标签关系;对少量训练样本场景较友好;便于发现脏数据、标签别名和术语缩写。 | 泛化能力弱,遇到同义改写和隐含语义时效果有限;难以处理长文本中的上下文关系;在 MAP@K 指标下,排序细节通常不如学习型模型稳定。 |
| TF-IDF 加 One-vs-Rest 线性分类 | 90% | 将文本转成词项权重向量,再用 Logistic Regression 或 Linear SVM 做多标签独立分类,是文本任务中最经典也最稳健的基线。对于标签数量有限、文本主题性较强的政务类文本,这条路线通常具有很高的性价比。 | 分词或子词切分;构建词和 n-gram 的 TF-IDF 特征;按标签训练多个二分类器;输出各标签概率;按概率排序并截取前 K 个标签。 | 训练快、资源占用低,适合作为正式基线;对中短文本分类非常有效;容易做交叉验证和特征分析;结果通常比纯规则方法明显更稳。 | 对深层语义和远距离依赖建模不足;若文本存在大量近义表达或复杂句式,召回容易受限;多标签相关性通常没有被显式利用。 |
| 句向量或词向量加传统分类器 | 82% | 使用 Word2Vec、FastText、Sentence-BERT 等向量表示文本,再配合 XGBoost、LightGBM、Logistic Regression 或相似度检索完成标签预测。这条路线介于稀疏特征和深度模型之间,强调语义表示的迁移能力。 | 生成文本向量或句向量;拼接少量统计特征;训练多标签分类器或基于标签原型向量做相似度排序;在验证集上优化 top-K 输出。 | 比 TF-IDF 更能处理近义词和语义改写;实现难度低于端到端深度模型;若竞赛附件中的 sentence embeddings 案例可复用,落地效率较高。 | 向量质量高度依赖预训练模型与语种适配;文本较长时平均池化可能损失关键信息;若标签边界细粒度较强,传统分类器可能吃不满语义优势。 |
| 多通道 CNN 或 BiLSTM 文本多标签分类 | 76% | 将文本序列输入 CNN 或 RNN,利用局部模式或上下文序列信息学习标签概率,属于经典深度学习路线。若文本长度适中且训练样本质量较好,这类模型能比线性模型更充分地利用词序信息。 | 构建词表和嵌入层;将文本编码为序列;训练 CNN 或 BiLSTM 多标签模型;输出每个标签的概率;根据验证集选择 top-K 或概率阈值。 | 能学习词序、短语模式和上下文关系;比手工特征更自动化;适合作为从传统方法过渡到深度学习的练习方案。 | 对数据量和训练配置更敏感;若样本规模不大,容易不如 TF-IDF 基线稳定;长文本建模能力有限,训练和调参成本高于线性模型。 |
| Transformer 预训练模型微调 | 94% | 使用 BERT、RoBERTa、DeBERTa 或适配德语的预训练模型进行多标签微调,直接从上下文语义出发预测标签排序。这是当前文本分类任务中最有竞争力的主流路线,尤其适合政治文本中存在复杂表达、正式语言和长距离语义依赖的情况。 | 选择与语种匹配的预训练模型;对文本进行 tokenizer 编码;构建多标签输出层;用验证集监控 MAP@K 相关表现;对 top-K 排序做后处理。 | 语义理解能力强,对同义改写、上下文依赖和长句表达更友好;通常具有最高的单模型上限;适合进阶练习真实工业级文本建模流程。 | 算力与显存需求高;对超参数、最大长度和学习率较敏感;若训练样本偏少或标签噪声较大,收益不一定稳定超过强基线。 |
| 两阶段检索加重排序标签推荐 | 88% | 将问题拆成"先召回候选标签,再对候选标签排序",更贴近推荐系统思路。第一阶段用关键词、BM25 或向量相似度召回相关标签,第二阶段用分类模型或交叉编码器重排,天然适配 MAP@K 这类排序指标。 | 建立文本到标签的召回机制;为每条样本生成候选标签集;提取文本与标签匹配特征或语义特征;训练重排序模型;输出排序后的前 K 个标签。 | 与竞赛所属推荐系统方向高度契合;能把分类问题转成排序问题,更贴近评估指标;便于融合规则、统计和深度特征。 | 流程较复杂,工程实现门槛高;需要设计标签表示和召回策略;若标签集合本身较小,两阶段优势可能不如单阶段模型明显。 |
| 多模型融合与阈值优化 | 92% | 将规则基线、TF-IDF 线性模型、句向量模型、Transformer 模型的输出做加权融合,并围绕 MAP@K 优化排序和截断策略。这不是单一模型替换,而是面向最终指标的系统性优化路线。 | 收集多个模型的标签分数;做归一化和加权融合;按验证集搜索最优权重;联合调节 top-K 截断和概率阈值;输出最终标签排序。 | 往往能稳定提升排行榜成绩;不同模型对关键词、语义、长文本的偏好互补;非常符合真实项目中"多路召回+统一排序"的落地思路。 | 维护成本高,实验管理复杂;若单模型差异不明显,融合收益有限;对验证集划分质量和离线评估一致性要求较高。 |
操作案例
基础流程样例
一、读取数据并建立任务视角
该竞赛的核心是基于议会事务相关文本做多标签推荐或分类,评价方式采用 MAP@K,说明模型不仅要判断某个标签是否相关,还要尽量把真正相关的标签排在更靠前的位置。教学场景下,基础实现可以先按标准多标签文本分类流程展开:读取训练集与测试集,识别文本字段与标签字段,整理出可直接送入模型的输入输出结构。由于 Kaggle 页面未直接给出字段细节,代码中采用"自动识别标签列 + 可配置文本列"的写法,更适合实际落地时面对结构不完全确定的数据文件。
python
import os
import re
import ast
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MultiLabelBinarizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.pipeline import Pipeline
from sklearn.multiclass import OneVsRestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
DATA_DIR = "./data" # 修改为本地数据目录
TRAIN_PATH = os.path.join(DATA_DIR, "train.csv")
TEST_PATH = os.path.join(DATA_DIR, "test.csv")
train_df = pd.read_csv(TRAIN_PATH)
test_df = pd.read_csv(TEST_PATH)
print("train shape:", train_df.shape)
print("test shape:", test_df.shape)
print("train columns:", train_df.columns.tolist())
print(train_df.head(3))
二、查看标签结构并识别多标签表达方式
多标签任务与单标签分类的根本差别,在于一条样本可能同时对应多个标签。真实项目中,标签常见的存储方式有两种:一种是每个标签占一列,以 0/1 表示是否命中;另一种是单独一列,用字符串或列表保存多个标签。只有先看清标签结构,后续建模、评估和提交格式才不会走偏。下面的示例代码优先尝试识别 0/1 标签列;如果没有明显的标签列,再回退到"标签列表列"的处理方式。
python
def detect_binary_label_columns(df, min_positive_ratio=0.001):
"""
自动检测二值标签列:
1. 列中非空唯一值仅包含 0/1
2. 至少存在一定比例的正样本,避免把无意义管理列误识别为标签
"""
label_cols = []
for col in df.columns:
values = df[col].dropna().unique()
if len(values) == 0:
continue
if set(values).issubset({0, 1}):
pos_ratio = df[col].mean()
if pos_ratio >= min_positive_ratio:
label_cols.append(col)
return label_cols
label_cols = detect_binary_label_columns(train_df)
print("detected binary label columns:", label_cols)
def try_parse_label_list(x):
if pd.isna(x):
return []
if isinstance(x, list):
return x
if isinstance(x, str):
x = x.strip()
if not x:
return []
try:
parsed = ast.literal_eval(x)
if isinstance(parsed, list):
return parsed
except:
pass
# 兜底:逗号分隔
return [i.strip() for i in x.split(",") if i.strip()]
return []
if len(label_cols) == 0:
candidate_label_list_cols = []
for col in train_df.columns:
if train_df[col].dtype == "object":
sample = train_df[col].dropna().astype(str).head(20)
if sample.apply(lambda s: ("[" in s and "]" in s) or ("," in s)).mean() > 0.3:
candidate_label_list_cols.append(col)
print("candidate label-list columns:", candidate_label_list_cols)
if not candidate_label_list_cols:
raise ValueError("未识别到明确标签列,需要根据实际数据手动指定。")
label_list_col = candidate_label_list_cols[0]
train_df["_label_list"] = train_df[label_list_col].apply(try_parse_label_list)
mlb = MultiLabelBinarizer()
y = mlb.fit_transform(train_df["_label_list"])
label_cols = mlb.classes_.tolist()
y_df = pd.DataFrame(y, columns=label_cols, index=train_df.index)
else:
y_df = train_df[label_cols].copy()
print("label count:", len(label_cols))
print("label sample:", label_cols[:10])
print("positive count per label:")
print(y_df.sum().sort_values(ascending=False).head(10))
三、文本字段整理与基础预处理
文本分类效果的下限,往往由文本字段是否选对决定。议会事务场景中,标题、摘要、正文、主题说明等字段都可能影响标签判断。教学示例里采用"候选字段自动拼接"的方式,把常见文本列合并成一个统一输入;同时做基础清洗,包括转小写、去除多余空白、保留字母数字与常见字符。对于德语原文或中英混合文本,这类轻量预处理已经足以支撑 TF-IDF 基线模型。
python
TEXT_CANDIDATES = [
"text", "document", "content", "description", "title",
"summary", "abstract", "body", "question", "parlamentsgeschaeft"
]
available_text_cols = [c for c in TEXT_CANDIDATES if c in train_df.columns]
if not available_text_cols:
# 回退策略:选择 object 类型中最像文本的列
object_cols = train_df.select_dtypes(include=["object"]).columns.tolist()
non_label_object_cols = [c for c in object_cols if c not in label_cols]
if not non_label_object_cols:
raise ValueError("未识别到文本字段,需要根据实际数据手动指定。")
available_text_cols = non_label_object_cols[:2]
print("selected text columns:", available_text_cols)
def clean_text(text):
text = "" if pd.isna(text) else str(text)
text = text.lower()
text = re.sub(r"\s+", " ", text)
text = re.sub(r"[^\w\säöüßàáâãåæçèéêëìíîïñòóôõøùúûüýÿ-]", " ", text)
text = re.sub(r"\s+", " ", text).strip()
return text
def build_text(df, text_cols):
combined = df[text_cols].fillna("").astype(str).agg(" ".join, axis=1)
return combined.apply(clean_text)
X_text = build_text(train_df, available_text_cols)
X_test_text = build_text(test_df, [c for c in available_text_cols if c in test_df.columns])
print(X_text.head(3).tolist())
四、训练集验证集划分
多标签任务的验证集划分不能只看样本数量,还要关注标签分布是否被破坏。严格做法通常会使用迭代分层抽样,但教学基础版优先保证流程简洁和依赖通用,因此采用普通随机划分,同时固定随机种子,确保结果可复现。若标签极度稀疏,后续扩展阶段再引入更适合多标签场景的分层方法。
python
X_train, X_valid, y_train, y_valid = train_test_split(
X_text,
y_df,
test_size=0.2,
random_state=42
)
print("X_train:", X_train.shape)
print("X_valid:", X_valid.shape)
print("y_train:", y_train.shape)
print("y_valid:", y_valid.shape)
print("train label density:", y_train.values.mean())
print("valid label density:", y_valid.values.mean())
五、基础建模:TF-IDF + One-vs-Rest 逻辑回归
对于中小规模文本多标签任务,TF-IDF 配合 One-vs-Rest 逻辑回归是一套非常稳定的入门基线。TF-IDF 负责把文本转成稀疏向量,逻辑回归按标签分别学习判别边界,One-vs-Rest 则把多标签问题拆成多个二分类子任务。这类方法训练快、解释性强、调参成本低,适合作为比赛初版和业务原型的共同起点。
python
model = Pipeline([
("tfidf", TfidfVectorizer(
max_features=50000,
ngram_range=(1, 2),
min_df=2,
max_df=0.95,
sublinear_tf=True
)),
("clf", OneVsRestClassifier(
LogisticRegression(
solver="liblinear",
max_iter=1000,
class_weight="balanced"
)
))
])
model.fit(X_train, y_train)
六、验证集预测与多标签评估
该竞赛官方指标是 MAP@K,核心强调排序质量。为了让教学代码更容易理解,基础版评估先使用多标签任务中常见的按列 ROC AUC,并结合整体微平均 AUC 来观察模型是否能把正标签打出更高概率。由于 One-vs-Rest 逻辑回归天然支持概率输出,也适合继续生成每条样本的 Top-K 标签推荐结果,为后续贴近比赛指标的评估打基础。
python
valid_proba = model.predict_proba(X_valid)
valid_pred = (valid_proba >= 0.5).astype(int)
print("valid_proba shape:", valid_proba.shape)
# 按标签计算 ROC AUC,自动跳过验证集中只有单一类别的标签
auc_per_label = {}
for i, col in enumerate(y_valid.columns):
y_true_col = y_valid.iloc[:, i].values
if len(np.unique(y_true_col)) < 2:
continue
auc_per_label[col] = roc_auc_score(y_true_col, valid_proba[:, i])
auc_series = pd.Series(auc_per_label).sort_values(ascending=False)
print("mean label-wise ROC AUC:", auc_series.mean())
print("top label ROC AUC:")
print(auc_series.head(10))
# 微平均 ROC AUC
valid_cols_mask = [len(np.unique(y_valid.iloc[:, i].values)) >= 2 for i in range(y_valid.shape[1])]
y_valid_filtered = y_valid.iloc[:, valid_cols_mask]
proba_filtered = valid_proba[:, valid_cols_mask]
micro_auc = roc_auc_score(
y_valid_filtered.values.ravel(),
proba_filtered.ravel()
)
print("micro ROC AUC:", micro_auc)
七、构造 Top-K 推荐结果并贴近竞赛评价方式
MAP@K 的关注点不只是"是否命中",还包括"命中的标签排在第几位"。因此即使基础模型暂时用 ROC AUC 做验证,也应当把概率结果转成每条样本的标签排序结果。下面给出一个简化版的 Top-K 生成逻辑,用于查看模型最可能推荐的标签;如果验证集保留了真实标签,也可以顺手实现一个教学版 MAP@K 计算函数,帮助理解排行榜指标的业务含义。
python
def top_k_labels(prob_matrix, label_names, k=5):
topk_indices = np.argsort(-prob_matrix, axis=1)[:, :k]
results = []
for row in topk_indices:
results.append([label_names[i] for i in row])
return results
valid_top5 = top_k_labels(valid_proba, y_valid.columns.tolist(), k=5)
print("sample top-5 predictions:")
for i in range(min(3, len(valid_top5))):
print(i, valid_top5[i])
def apk(actual, predicted, k=5):
predicted = predicted[:k]
score = 0.0
hits = 0.0
for i, p in enumerate(predicted):
if p in actual and p not in predicted[:i]:
hits += 1.0
score += hits / (i + 1.0)
if len(actual) == 0:
return 0.0
return score / min(len(actual), k)
def mapk(actual_list, predicted_list, k=5):
return np.mean([apk(a, p, k) for a, p in zip(actual_list, predicted_list)])
# 从验证集二值标签还原真实标签列表
actual_valid_labels = []
for idx in range(y_valid.shape[0]):
row = y_valid.iloc[idx]
actual = row.index[row.values == 1].tolist()
actual_valid_labels.append(actual)
valid_map5 = mapk(actual_valid_labels, valid_top5, k=5)
print("validation MAP@5:", valid_map5)
八、对测试集生成提交结果
比赛落地阶段,模型最终价值体现在可交付结果上。多标签推荐任务常见的提交格式,是为每条测试样本输出按概率从高到低排列的标签序列。由于具体提交模板可能因竞赛而异,示例代码保留一个通用写法:读取测试集、生成 Top-K 标签,并输出为可继续适配的 CSV 文件。真实提交前需要再对照官方 sample submission 调整列名和格式。
python
test_proba = model.predict_proba(X_test_text)
test_top5 = top_k_labels(test_proba, y_valid.columns.tolist(), k=5)
submission = pd.DataFrame({
"row_id": np.arange(len(test_top5)),
"predicted_labels": [" ".join(labels) for labels in test_top5]
})
print(submission.head())
submission.to_csv("submission_baseline.csv", index=False)
扩展流程概述
这套基础流程适合教学展示,也适合作为真实项目中的第一版可运行原型。继续向竞赛增强版推进时,关键方向不在于盲目替换更复杂的模型,而在于逐步贴近任务本质:评价指标要求标签排序更准确,议会文本可能存在长文本、专业术语、标签稀疏和标签共现关系,简单的独立二分类虽然易于起步,却难以充分利用这些结构信息。实际优化通常会围绕更可靠的多标签分层验证、更贴近 MAP@K 的本地评估、德语文本的专门预处理、词袋特征与语义向量融合、基于 Transformer 的文本编码、标签相关性建模、阈值与 Top-K 策略联调,以及模型融合展开。这样的升级路线既符合 Kaggle 比赛的提分逻辑,也符合政务文本推荐、法规归类、知识条目分发等业务场景中的真实需求。
| 扩展流程 | 流程说明 | 流程目标 |
|---|---|---|
| 多标签分层验证 | 用更适合多标签任务的分层抽样替代普通随机切分,减少验证集标签分布波动 | 提升离线评估稳定性,降低线上线下偏差 |
| 本地 MAP@K 评估对齐 | 围绕排序结果建立更严格的本地验证函数,并检查不同 K 值下的表现 | 让优化方向更贴近官方排行榜指标 |
| 德语文本增强预处理 | 引入德语停用词、词形还原、复合词处理和领域术语清洗 | 提高文本表示质量,减少噪声特征 |
| 特征工程升级 | 在 TF-IDF 基础上叠加字符 n-gram、标题与正文分域特征、元信息特征 | 增强模型对短词、拼写变体和结构信息的捕捉能力 |
| 语义向量建模 | 使用 Sentence-BERT、German BERT 等预训练模型提取句向量或直接微调 | 提升对长文本语义和近义表达的识别能力 |
| 标签相关性建模 | 利用标签共现关系、Classifier Chains 或后处理重排机制 | 改善多标签之间相互依赖带来的预测偏差 |
| 阈值与排序策略优化 | 不再固定 0.5 阈值,而是按标签或样本动态决定输出数量 | 提升召回与排序质量,优化最终 MAP@K |
| 类别不均衡处理 | 通过重采样、损失加权、难样本学习等方式处理长尾标签 | 提高稀有标签识别率 |
| 模型融合 | 融合线性模型、树模型与深度语义模型的输出概率 | 兼顾稳健性与上限表现 |
| 提交后处理 | 结合标签先验频率、重复规则和业务约束修正预测结果 | 提高提交结果的一致性与业务可解释性 |
优秀案例解析
这一节选取案例时,重点关注两类来源:一类是该竞赛在公开代码区已经出现、且能够直接反映赛题解法思路的赛中项目样例;另一类是在更广泛的推荐与检索生态中,被反复验证有效的标杆方案。由于 Open Data St.Gallen 当前仍属于社区型长期开放竞赛,公开信息中未见稳定的正式获奖方案沉淀,参考价值更高的内容往往来自可复现 Notebook、官方或研究机构发布的检索推荐系统实践,以及与公共服务、知识组织、可信推荐相关的真实项目。对于这道题,真正值得借鉴的并不是单一模型名称,而是如何把"议会事务分类/推荐"抽象成文本匹配与候选排序问题,如何处理德语文本和标签稀疏,如何在离线评估指标 MAP@K 下构建更贴近业务落地的召回---排序链路,以及如何让方案具备可维护、可迁移和可解释的特性。表中的案例因此既覆盖了竞赛现场可见的直接样例,也补充了在公共治理、科学知识发现、数字公共服务等场景中高度相近的生态标杆案例。
| 创建时间 | 作者 | 案例解析 |
|---|---|---|
| 2022-04 | Beat Tödtli | SentenceEmbeddings 关键词:句向量、语义检索、德语文本、MAP@K、Kaggle Notebook。该案例是当前竞赛页面中可确认的公开项目样例,也是与赛题最直接相关的参考材料。核心思路是用句向量把议会事务文本映射到统一语义空间,再通过相似度完成候选推荐或类别匹配。这类方法对短文本、标题文本和描述文本混合输入较为友好,尤其适合标签体系不完全平衡、词面表达不统一的场景。其价值不只在于竞赛得分,更在于原型完成度较高:文本清洗、嵌入生成、相似度排序、结果提交形成了完整闭环,能够直接迁移到政府公开数据检索、法规条目关联和内部知识库推荐。 |
| 2020-06 | UK Parliament / National Archives 团队 | Hansard at Huddersfield / Semantic Search in Parliamentary Debates 关键词:议会文本、语义搜索、数字人文、公共数据、知识发现。该类项目并非 Kaggle 竞赛案例,但与本赛题在业务对象上高度一致,处理的都是议会语料、公共事务文本和面向检索的知识组织问题。其代表性在于把传统关键词搜索升级为语义层面的发现机制,让同一政策主题下表述差异较大的议会文本能够被关联起来。对本赛题的启发是,议会事务分类完全可以转化为"以历史案例为索引库的语义推荐",而不必局限于刚性的多分类框架。这种建模方式在真实场景中的价值更高,因为公共管理系统更关心相似案件归类、议题跟踪与政策研判,而不是单次预测标签本身。 |
| 2020-10 | deepset | Haystack: End-to-End Neural Search 关键词:神经检索、双塔召回、排序重排、离线部署、可解释检索。Haystack 是开源检索生态中的标杆项目,适合作为本赛题的工程化参照。其框架把文本匹配任务拆成召回与重排两层:前者负责快速找到候选议会事务,后者负责提升前 K 结果排序质量,这与 MAP@K 指标导向高度一致。对本赛题而言,若数据规模扩大,单纯全量相似度计算会很快触达性能瓶颈,而 Haystack 这类方案展示了如何在保证检索质量的同时兼顾服务化部署。更重要的是,它强调文档索引、嵌入更新、评估组件和 API 封装,适合延展到政务搜索、法规问答和内部政策知识助手等场景。 |
| 2019-11 | UK Government Digital Service / Government Digital Service 团队 | GOV.UK Search Relevance and Taxonomy Work 关键词:公共服务、信息组织、主题分类、搜索相关性、数字包容。GOV.UK 相关公开实践展示了公共服务网站如何通过主题体系、页面分类和搜索相关性优化,让公民更容易找到政策、办事指南与法规信息。虽然不是 Kaggle 竞赛代码,但与本题的"公共事务文本归类与推荐"在落地逻辑上高度相通:标签设计不是纯学术问题,而是服务可达性和数字公平问题。对本赛题的借鉴点在于,建模时不能只追求分数,还要考虑标签体系是否稳定、同义主题是否需要合并、排序结果是否可解释。对于自学者而言,这类案例能帮助建立一个更接近真实业务的视角,即推荐系统在公共领域承担的是信息分发责任,而不仅是点击率优化。 |
| 2021-09 | Allen Institute for AI | SciNCL / SPECTER 系列学术文献推荐实践 关键词:文本嵌入、相似文档推荐、迁移学习、稀疏标签、科研知识发现。SPECTER 及其后续工作是文本推荐领域极具代表性的生态标杆,核心价值在于使用预训练语义表示解决"表面词不同但主题接近"的文档匹配问题。议会事务文本与学术摘要在结构上存在相似性,都是信息密度高、专业术语多、主题边界细的文本集合。对本赛题而言,SPECTER 类方案证明了基于文档级嵌入的近邻检索非常适合做候选召回,再叠加轻量排序即可形成稳定基线。其现实意义在于,这类方法可复用到科学知识推荐、政策研究资料归档和跨机构文档联查,特别适合数据标注有限但文本规模持续增长的场景。 |
| 2021-08 | Sentence-Transformers / Tom Aarsen 等贡献者 | Sentence-Transformers: Semantic Search Examples 关键词:Sentence-BERT、语义搜索、零样本迁移、轻量部署、相似度排序。该案例集合并非特定比赛提交,但它几乎是文本推荐与检索任务中最常见、最可落地的原型路线之一。其优势在于实现成本低、验证速度快,适合作为竞赛早期强基线,也适合在真实业务中快速搭建最小可用系统。对于 Open Data St.Gallen 这类议会事务推荐题,Sentence-Transformers 可以直接承担"文本编码器"角色,并通过余弦相似度产生 Top-K 结果,与 MAP@K 的评估形式天然一致。若本地算力有限或需要边缘部署,这类方案比大型生成式模型更稳妥,也更易于维护。 |
| 2022-09 | OpenSearch 社区 | OpenSearch Neural Search 关键词:向量检索、混合检索、生产部署、可扩展性、离线在线一致性。OpenSearch Neural Search 展示了传统搜索引擎如何吸收向量检索能力,把关键词匹配与语义匹配结合起来。这对本赛题具有很强的工程启发意义,因为议会事务文本既有正式术语,也存在简写、别称和上下位概念,仅靠词面规则容易漏召回,仅靠向量相似度又可能损失可控性。混合检索路线能够在公共信息服务场景中更稳健地平衡准确率与覆盖率。若未来把竞赛原型扩展为政务开放数据门户、法规条目导航或议题监测系统,这类方案比单一 Notebook 更接近生产环境。 |
| 2023-03 | European Parliament / Publications Office of the European Union(相关公开数据生态) | EU Open Data Portal / Legislative and Parliamentary Data Access 关键词:开放数据、立法文本、跨语种、知识组织、公共治理。欧洲开放数据生态中与立法、议会和政策文件相关的数据服务,提供了一个比竞赛更真实的应用背景:文本不仅要被分类,还要被检索、关联、复用和跨语种传播。虽然这不是单一算法案例,但它揭示了本赛题在现实中的价值边界,即高质量推荐系统可以成为公共治理数字化的底层能力。对参赛解法的借鉴在于,数据预处理不能只做常规清洗,还要考虑元数据规范化、语言变体、文档版本和主题层级,这些因素都会影响 MAP@K 之外的真实使用效果。 |
总结
这类竞赛的价值,在于把推荐系统方法带入非商业文本场景。议会事务、政策议题和公共文档往往存在表述分散、语义相近却词面不同的问题,单纯依赖关键词或单标签分类很难满足实际检索需求,而多标签排序方案更接近真实业务中的信息组织方式。
从实践角度看,这个案例并不依赖庞大数据量才能体现价值。即使从 TF IDF 线性模型起步,只要验证设计合理,再结合句向量、候选重排和结果后处理,仍然能够逐步逼近可交付的推荐原型。对于政务知识库、法规检索和公共信息导航场景,这条技术路线具有明确迁移意义。