资讯详情

资讯详情

高中数学NLP数据集构建全流程:从采集清洗到标注验证的工程实践

简介针对高中数学学科的知识图谱构建需求提供了一份包含2232个样本、2399个实体的领域数据集共整理出12种关系、11250个实体关系对。面向NLP初学者与AI开发者适用于命名实体识别、实体关系抽取、文本分类等任务的训练与评测也可支撑基于高中数学教材的知识图谱搭建和推理应用。资源包为RAR压缩格式体积约506KB共6个文件涵盖训练集、测试集、实体列表、上下文实体关联表及数据库SQL与说明文档便于直接加载到深度学习框架或关系型数据库中开展实验。已有2507人浏览学习说明其在中学学科知识建模场景中具有一定参考价值。拿到后可获得完整的数据样本划分结构、实体关系数据库定义及原始标注说明省去从教材中人工摘录和标注的整理成本适合用于构建高中数学学科知识图谱的初步原型验证。1. 自然语言处理数据集“高中数学学科”先想清楚要喂给模型什么如果要做教育领域的 NLP 项目比如数学题的自动判分、知识点诊断、智能错题本、试题推荐甚至让大模型做数学题第一步从来不是选模型而是先弄一份能用的自然语言处理数据集。高中数学学科这个方向尤其特殊它的文本里全是公式符号、图形描述和严谨的数学语言通用语料里的新闻、百科文本根本顶不上。很多团队在这个方向翻车不是模型不行而是数据集构建阶段就埋了雷——公式乱码、题干残缺、知识点标注错误训出来的模型自然没法看。这一篇我按自己做过教育 NLP 项目的思路把构建一份高中数学学科自然语言处理数据集的完整过程拆开讲从数据结构设计、采集清洗、LaTeX 公式规整、知识点标注到质量验证和避坑。适合正在做智慧教育、题库系统、数学学科大模型微调的工程师或课程设计团队照着这条路径你可以在两周内产出一份能用于训练和评测的高质量数学语料集。2. 高中数学 NLP 数据集的结构设计从一道题到一个训练样本2.1 四大文本类型教材语料、题目语料、解析语料、知识点标签构建高中数学学科的数据集第一步不是找数据而是确定你要哪几类文本。我一般把数学学科的 NLP 数据集拆成四个相互独立又有关联的部分。教材语料是基础底料。它包含高中数学全部必修和选修内容的概念定义、定理描述、公式推导过程覆盖函数、三角、数列、立体几何、概率统计等模块。这类语料的价值在于给模型提供标准化的数学语言表达像“函数的单调性”“等差数列的通项公式”这些术语模型得先见过足够多的标准表述才不至于在其他任务上表现飘忽。题目语料是核心资产。一道题的结构非常规整题干、选项如果是选择题、答案、解析。题目的文本特征是短、信息密度高、数学符号密集而且不同来源的排版差异极大。比如同一道函数单调性的题人教版教材课后题是一个写法五年高考三年模拟里的题是另一个写法网上题库的 OCR 结果可能是第三个写法。数据集的鲁棒性恰恰取决于你收集了多少种“写法”的同一种题。解析语料决定了模型能不能学会解题步骤。解析文本通常是分步的每步有因果逻辑比如“由 f(x)3x^2-6x令 f(x)0得 x0 或 x2”。这种文本对模型学习推理链条极有帮助也是后期做解题过程生成、步骤得分判定的必要原料。知识点标签是监督信号。每道题至少要标到一级知识点函数、几何、概率和二级知识点函数的单调性、直线与圆的位置关系。标签做的越细后续做学情诊断、薄弱点分析的场景就越有底气。我见过不少团队最初只做了题目和答案省掉了解析和标签结果做知识图谱时发现没有关联边做推荐系统时没法聚类最后灰溜溜回来补标返工成本远高于一开始多花的时间。2.2 样本粒度选择以“题”为单元还是以“句”为单元数据结构设计里另一个关键决策是样本粒度。同一个题目语料按题切是一种做法按句切是另一种做法。它们服务于不同任务不能混着用。以“题”为单位的数据集适合做题目分类、难度预测、知识点标注、相似题检索。每个样本是一个完整的 JSON 对象包含题干、选项、答案、解析、知识点、难度等字段。这种方式符合人的认知习惯也符合大多数下游任务的输入输出形态。以“句”为单位的数据集适合做数学语言理解、实体识别、关系抽取。比如“已知函数 f(x)x^3-3x求 f(x) 在区间 [-2,2] 上的最大值”这句话里“函数 f(x)x^3-3x”是一个函数表达式实体“区间 [-2,2]”是一个定义域实体“最大值”是目标属性。按句切分能把这些细粒度信息挖出来但标注成本要翻倍。我一般建议如果资源有限优先做“以题为单位 解析文本的句子级切分备注”。也就是数据主体按题存同时把解析字段切分成句子列表这样两个粒度都有了还不破坏题目完整性。数据格式大致是{ question_id: math_000123, grade: 高一, module: 函数, knowledge_points: [函数的单调性, 导数与函数单调性], question_type: 解答题, difficulty: 0.65, question_text: 已知函数 f(x)x^3-3x求 f(x) 的单调区间。, options: [], answer: 单调递增区间为 (-∞,-1) 和 (1,∞)单调递减区间为 (-1,1)。, analysis_steps: [ 求导得 f(x)3x^2-33(x-1)(x1)。, 令 f(x)0解得 x-1 或 x1。, 令 f(x)0解得 -1x1。 ] }这种结构的好处是模型训练时可以直接取字段拼接做选择题时用“question_text options”做解答题生成时用“question_text analysis_steps”做知识点分类时用“module knowledge_points difficulty”当标签一个数据集多个用处。2.3 标注体系知识点标签、难度系数、题型分类的字段设计标注体系是一份自然语言处理数据集能不能被用起来的命门。高中数学的知识点体系有国家课程标准的框架可以参考但落地时建议做成两层一层跟着课标走一层跟着题库已有体系走。知识点标签建议用两级体系。一级知识点按高中课程标准的几个大模块分包括集合与逻辑、函数与导数、三角函数与解三角形、数列、不等式、立体几何、解析几何、概率统计、计数原理等。二级知识点再细化比如“函数与导数”下面挂“函数的概念”“函数的单调性”“奇偶性”“周期性”“导数运算”“导数与单调性”“导数与极值”“导数与最值”。注意二级知识点之间不是互斥的一道含参导数题可能同时标“导数与单调性”和“导数与极值”这种多标签情况在数学里非常常见字段设计上不能用单个字符串要用数组。难度系数建议直接用 0~1 的小数越大越难。但这个值怎么定常见做法有两种一种是人标让经验丰富的老师按“得分率预估”打分另一种是数据驱动从题库系统里取历史得分率归一化。如果两者都没有可以用题目结构特征做粗估比如“含参”“分类讨论”“多步推理”这些特征词出现难度就往高处标。人标是上限数据驱动是真实情况。题型分类最少要有选择题、填空题、解答题三类如果后续要做批改场景解答题还要细分出“证明题”“计算题”“应用题”。题型字段千万不能在后期修改因为下游任务对题型高度敏感——选择题的数据增强方式和解答题完全不同干扰选项生成和解答步骤生成的模型结构也完全不同。字段设计如果一开始就能考虑到 JSON 格式、多标签数组、难度数值化后面做训练集构建时就不用做二次清洗能省出至少三成的时间。很多项目做到一半推翻重来根因就是第一版字段没设计好。3. 数据采集与预处理把 PDF 教材和题库文本洗成干净语料3.1 多源采集教材 PDF、真题卷、题库网站的抓取策略结构设计完了就进入采集环节。高中数学学科的语料来源优先级我一般这样排正版教材 PDF 和教师用书、各省历年高考真题卷和模拟卷、开放题库网站的结构化数据、学校内部讲义和手写教案的 OCR。教材 PDF 是质量最高的来源但获取途径有限且版权要自行评估。历年真题是第二优先因为真题的题干严谨、答案规范、解析完整而且每年的真题卷都有公开的 PDF 和网页版。题库网站的数据量大但噪声也大很多网站是扫描件跑 OCR 出来的公式乱码率能到 15%~30%。抓策略上我一般先用爬虫在几个固定的教育类公开数据站和题库站做定向抓取再在本地做真题卷 PDF 的批量解析。定向抓不像通用爬虫那样要用复杂的反爬对抗因为目标是特定域名基本在 requests BeautifulSoup 就能解决。抓的时候要注意把页面里的 HTML 实体和 Latex 渲染后的文本抓成两种版本后面清洗时再选。真题 PDF 的处理需要另走一条路因为 PDF 里的公式有几种形态原生文本、字体编码后的伪文本、图片型公式、扫描件。PDF 解析我常用 pdfplumber 配合正则提取文本骨架再用公式检测模型或规则识别图片型公式最后统一用 Mathpix 或自训练 OCR 把公式转为 LaTeX。注意 Mathpix 这类 API 是按张数收费的真题卷每页图片里公式密度高预算消耗很快我一般只对公式密集区走 OCR对纯文字页面直接走 pdfplumber 提取能把成本压掉一半以上。3.2 PDF 抽取与 OCR 的工程处理公式、图片、表格怎么处理高中数学的 PDF 抽取里有三个高难组件公式、图片、表格。处理不好后面全乱套。公式的抽取顺序是先检测、后识别、再规整。检测阶段用 pdfplumber 先拿文字层里的 Unicode 数学符号如 ∑、∫、√、π如果文字层本身就有这些符号说明是数字版 PDF直接按文本块切出来即可。如果文字层是空白的或全是乱码字体那就把页面渲染成图片用公式检测模型框出公式区域再走 OCR。图片的处理方式是高中数学题目里的图片大部分是几何图形和函数图像这些图片在数据集里应该独立存储并在题目的 JSON 里用“image_ref”字段去引用而不是把图片二进制塞进文本字段。因为后续训练视觉语言模型时图片要单独过视觉编码器文本再过文本编码器两者是并行输入字段分离对两者都有利。但图片必须有配套的“图意文本描述”比如“在平面直角坐标系中函数 yf(x) 的图像是一条过点 (1,2) 的曲线”。这段描述可以让多模态模型在做题时理解图意也可以让纯文本模型在无图情况下仍能阅读题目。表格的处理相对简单但容易被忽略。高中数学里概率统计模块有大量的表格型题目比如频数分布表、列联表。PDF 抽取时表格经常散架行对不齐。我一般用 camelot 或 tabula 先把表格结构提取出来转成 Markdown 表格文本再嵌入到题目的题干字段里。转成 Markdown 而不是留着 JSON 嵌套数组原因是下游模型训练时 Markdown 表格能直接被理解而嵌套数组还需要额外序列化。3.3 清洗规则去噪、去重、编码修复的一套正则清洗是数据工程里最琐碎但最决定下限的环节。高中数学学科的数据清洗我沉淀了一套固定顺序的规则按执行顺序排列顺序错了会出问题。import re import unicodedata def clean_math_text(raw_text: str) - str: # 1. 统一 Unicode全角转半角保留必要的数学符号 text unicodedata.normalize(NFKC, raw_text) text text.replace(\u3000, ).replace(\xa0, ) # 2. 清理 OCR 常见的噪声字符 text re.sub(r[□◇►★☆※①②③④⑤⑥⑦⑧⑨⑩], , text) text re.sub(r[ \t], , text) # 3. 修复断裂的行行尾没有句号且下一行是小写字母或数字开头 lines text.split(\n) fixed_lines [] for i, line in enumerate(lines): if i len(lines) - 1 and not line.rstrip().endswith((。, , , , , ., )): if re.match(r^[a-zA-Z0-9\\$(], lines[i 1].strip()): lines[i 1] line.strip() lines[i 1].strip() continue fixed_lines.append(line) text \n.join(fixed_lines) # 4. 清理超长空白行 text re.sub(r\n{3,}, \n\n, text) # 5. 合并被 OCR 拆散的内联公式如 f ( x ) 变成 f(x) text re.sub(r\\(\s*), \\\\, text) text re.sub(r(\d)\s*\.\s*(\d), r\1.\2, text) return text.strip()这段代码里的几个正则值得展开说明。第 1 步的 NFKC 标准化可以在全角和半角之间做统一数学场景里“”和“()”混用的问题能一并处理。第 2 步清理 OCR 噪声字符像 □ 和 ◆ 这种通常是扫描件里图片识别失败的占位符直接删掉比留着让模型瞎猜好。第 3 步的行修复逻辑小心思最多OCR 经常在“f(x) ”后面断行断行后的下一行如果以数字或字母开头就把两行拼接回去但如果上一行以句号或等号结尾就说明是合理换行不该拼。第 4 步和第 5 步是常规操作把多余空行压掉、把公式里的空格去掉。清洗脚本跑完后要做一轮人工观测随机抽 100 条打印出来看重点看公式有没有被拆坏、中英文之间有没有多余空格、分隔符是不是统一了。这一步是玄学但极重要机器过滤完全替代不了人的眼睛公式拆分这种错误正则偶尔会漏。4. 题目结构化解析从原始文本到 JSON 训练样本4.1 题干、选项、答案、解析的四段切分原始文本洗净了下一步是把一段连续文本切分成结构化字段。高中数学题目的文本结构多数是规律可循的但边界条件极多我和团队打磨这套切分规则花了很久这里把核心逻辑写出来。切分思路是分层正则匹配。先用一个大的模式匹配把题目整体切成题干、选项、答案、解析四块再对每块单独处理。对于选择题选项部分必然存在“A.”“B.”“C.”“D.”这样的标记且答案字段是单个字母。对于填空题题干后面直接跟答案解析可有可无。解答题则最复杂题干和解析之间常有“【答案】”“【解析】”“解”“【详解】”等标记词。import re def split_question(text: str) - dict: # 优先处理带“解析/答案”标记的题目 result { question_text: , options: [], answer: , analysis: } # 分离题干和答案/解析区 ans_markers re.split(r【?(?:答案|参考答案)[】】?:?, text) if len(ans_markers) 1: question_zone ans_markers[0] answer_zone ans_markers[1] else: # 没有答案标记尝试找“解”作为解答题的分界 sub_split re.split(r(?![一二三四五六七八九十])解[:], text) if len(sub_split) 1: question_zone sub_split[0] answer_zone 解 sub_split[1] else: question_zone text answer_zone # 从题干区提取选项 opt_pattern re.findall( r([A-D][\.、)]\s*)([^A-D][^【】]*), question_zone ) if opt_pattern: result[options] [opt[1].strip() for opt in opt_pattern] # 去掉题干里的选项文字 question_text re.sub(r[A-D][\.、)]\s*[^A-D]*?, , question_zone) result[question_text] question_text.strip() else: result[question_text] question_zone.strip() # 尝试从答案区提取答案和解析 for line in answer_zone.split(\n): line line.strip() if re.match(r^[A-D]$, line): result[answer] line # 解析一般为答案区里剩下的非空内容 result[analysis] re.sub(r^[A-D]$, , answer_zone).strip() return result这个切分方法的适用性是 80% 的规范题目。它的核心设计是“分层兜底”先找显式的“答案”标记找不到再找“解”字再找不到就把整段当题干。这样一层层降级能保证大多数题目不会整体解析失败。注意“解”字的分割用了负向断言避免把题干里“解题思路”“理解题意”这些词错当成解析开始位置。选项提取的正则是最容易出问题的部分因为选项内容本身可能包含“A.”或“B.”的公式比如选项里的“|a|1”中没有任何字母加句点但如果选项内容包含英文缩写或特殊格式就会误截。我在实际运行时对提取出的选项做了长度校验如果选项文本超过 100 个字符可能是误匹配需要人工复核。4.2 LaTeX 公式抽取与规整让数学符号不变成乱码数学学科的 NLP 数据集公式规整是生死关。很多通用 NLP 工具包在数学文本上漂得没法看就是因为对公式的内部结构没有概念。公式在原始文本里可能以三种形式存在Unicode 数学符号、LaTeX 源码、OCR 乱码。数据集构建阶段要把前两种统一规范把第三种尽量修复。Unicode 数学符号和 LaTeX 的对应关系需要做一张映射表。比如“≤”对应“\leq”“√”对应“\sqrt”“∑”对应“\sum”。还有一种情况是教材 PDF 里的公式自带排版格式比如上标是“3”但字号偏小、位置偏高提取后变成普通数字这种特征在纯文本里看不出来只能靠 OCR 专用模型去恢复。公式规整的工程实现上我会把每个题目里的公式单独抽出来存成两个字段display_formula 和 inline_formula。display_formula 是独立成行的公式inline_formula 是嵌入在文本里的公式。这两者的 LaTeX 表达有细微差别——行内公式不能有 \displaystyle独立公式则相反。import re def normalize_latex(text: str) - str: # 把文本中的数学符号替换为 LaTeX 命令 symbol_map { ≤: r\leq, ≥: r\geq, ≠: r\neq, ×: r\times, ÷: r\div, ±: r\pm, ∞: r\infty, →: r\to, ∈: r\in, ∑: r\sum, ∫: r\int, √: r\sqrt, π: r\pi, α: r\alpha, β: r\beta, θ: r\theta, λ: r\lambda, Δ: r\Delta } for char, latex in symbol_map.items(): text text.replace(char, latex) # 修复常见 OCR 错误字母 o 被识别为 0数字 1 被识别为 l text re.sub(r(?[a-zA-Z])0(?[a-zA-Z]), o, text) text re.sub(r(?\d)l(?\d), 1, text) # 统一括号 text text.replace(, ().replace(, )) # 把裸数字前的 x 修正为乘法符号 text re.sub(r(?[a-zA-Z])x(?\d), r\\times , text) # 清理多余空格但保留 LaTeX 命令内部的空格 text re.sub(r\\[a-zA-Z]\s, lambda m: m.group(0).strip() , text) return text.strip()公式规整有个重要的原则宁可保留原生的 LaTeX 结构也不要过度“美化”。比如\frac{1}{2} 和 0.5 是等价的数学表达但 NLP 模型对这两者的学习是两回事。LaTeX 结构保留得越完整模型学到的数学语法就越准确。文本真正要转成 LaTeX 的地方是那些 OCR 出来的长得像乱码的符号序列不是在公式里做等价变形。公式规整后的质量校验有个土办法把所有含有公式的题目文本打印出来数一下“\frac”“\sqrt”“\sum”这些命令的出现频率是否符合分布。如果一道题里\sum 出现了八次那大概率是 OCR 把某种装饰性符号误识别了。公式的“语义合理性”校验是建议人工抽检的重点。4.3 知识点自动标注基于关键词表与规则打分知识点标注是纯手工做不动的上万道题靠人标能熬死人。我采用的自动标注方案是关键词表 规则打分 人工抽检三层不依赖大模型做零样本推理。原因是大模型做数学题的知识点标注精度不稳定且专业术语和模型内部表示的对应关系不可控。关键词表的构建方式是先用教材目录做种子词表每个二级知识点挂 3~10 个典型关键词和典型公式模式。比如“函数的单调性”挂“单调递增”“单调递减”“增函数”“减函数”“f(x)0”“f(x)0”“等比数列”挂“等比”“公比”“通项公式”“S_na_1(1-q^n)/(1-q)”等。然后拿这个种子词表在未标注语料上跑一遍采集高频共现词人工筛一遍补充进词表。规则打分做两层第一层是硬匹配题干或解析里出现某个知识点的关键公式片段比如“S_n a_1(1-q^n)/(1-q)”直接判定为等比数列题。第二层是软匹配题干里出现“递增”但没有“单调”字样就按一定分数给“函数的单调性”加分。最后按分数从高到低取前三个知识点作为候选标签交给人工复核。def auto_label_question(question_text: str, analysis_text: str, knowledge_graph: dict) - list: scores {} text question_text analysis_text for kp, rules in knowledge_graph.items(): score 0 for keyword in rules[keywords]: if keyword in text: score 1 for pattern in rules[patterns]: if re.search(pattern, text): score 3 if score 0: scores[kp] score # 最多返回前三个知识点且分数差异过大的只取最高分 sorted_kps sorted(scores.items(), keylambda x: x[1], reverseTrue) if not sorted_kps: return [] top_three [kp for kp, sc in sorted_kps[:3]] if len(sorted_kps) 2 and sorted_kps[0][1] sorted_kps[1][1] * 2: return [sorted_kps[0][0]] return top_three这个规则打分方案最大的问题是知识点的“重叠性”。一道数列题可能同时匹配“等比数列”和“数列通项”但人的判断里“数列通项”是更通用层面的知识点应该优先。所以我在打分时给特殊知识点加了权重系数比如“等比数列”的公式模式权重为 3而“数列通项”的关键词权重只有 1。这样特殊在前、通然后在后更能接近人的标注习惯。自动标注的结果不能直接用还是要做抽检。我一般按 10% 的比例抽检如果抽检准确率低于 85%就把新发现的误判案例并入关键词表的负面词表重新迭代一轮。两轮迭代之后准确率基本能稳定在 90% 以上。5. 高中数学 NLP 数据集的常见问题与排查五个翻车现场5.1 公式 OCR 识别率低文本里出现大量乱码现象采集的题目文本里出现“f ( x )”中间缺了等号、根号被识别成“V”、分数变成“1 2”这种错位输出整体乱码率超过 30%。原因多数题库网站的历史数据是扫描件跑的 OCR切了数学公式识别能力弱的引擎。通用 OCR 对数学符号的上下文不敏感把∑识别成 δ、把∫识别成 f 的例子很常见。解决至少在两个层面处理。一是对原 PDF 做公式区域检测把公式区域单独切出来走数学专用 OCR非公式区域走普通文字识别。二是把已污染的文本先用符号映射表做一轮清洗再用“上下文字典”修错。如果题干里出现“求 f ( x ) 的最大值”“f ( x )”中间明显缺少“”用上下文规则补上等号。5.2 同一道题在多个来源重复出现去重后样本量骤减现象采集了 3 万道题按题干做 minhash 去重后只剩 8000 道去重率 70% 以上。原因题库网站之间存在大量的转载关系同一道题被改几个数字、换一个选项顺序就当成新题发布。解决去重不能只算字符串相似度要考虑同题变体。我建议先用字符串精确去重再做 SimHash 或 MinHash 相似度去重。相似度阈值设在 0.85 左右超过阈值就对比题目里的数字和选项内容完全一致或只有符号格式差异的就合并保留信息最完整的一条。5.3 知识点标签严重不均衡压轴题样本太少现象自动标注之后做统计函数与导数的题目占了 45%概率统计占 35%而“立体几何”和“解析几何”的题目加一起不到 20%。导数压轴题里的“含参讨论”类目下只有几十条样本。原因题库网站的内容分布天然偏向高频考点而压轴题的题量本来就少加上自动标注对长题干、多步骤的解答题匹配准确率低很多压轴题被打上了错误或不完整标签。解决针对稀缺类目做定向补充采集。去专门搜“导数压轴”“含参讨论”“圆锥曲线综合”这类题源而不是继续泛采。如果还是不够就做题目变体生成——把已有题目的数字替换成同范围的其他值注意保持题干和答案的逻辑一致性。这种增强后的样本打上“is_synthetic”标记避免模型混淆。5.4 题干被 OCR 切成两半结构化切分失败现象切分脚本跑完有 12% 的题目“question_text”字段只有半句话后半段跑到了“analysis”字段里。原因PDF 里的公式区域被 OCR 作为一个独立块抽走剩下文本被拆成两个段落中间没有衔接词。切分脚本按段落边界找答案/解析标记结果把后半段文本误认为是解析。解决在切分前先做段落重组。把同一题号范围内、中间没有“答案”“解析”等标记词的多个连续段落合并成一个逻辑段。合并后再跑四段切分。另外对疑似断裂的题干做一次长度校验题干过短比如少于 15 个字符且下一条记录有相似“题干尾部”的自动拼接。5.5 解析文本里的“解”“由题意得”干扰模型训练现象训练出的解题步骤生成模型有时直接输出空话比如“解由题意得……得证”后面没有实质内容。原因解析语料里“解”“由题意得”“显然”这类套话出现频率极高模型学到了这些词之后用于表示“开始解题”的概率非常大就产生了崩溃归纳。解决在清洗阶段不要删掉这些词而是做两类数据的区分。一类用于训练模型“解题格式”保留这些引导词另一类用于“推理步骤生成”要把套话词过滤掉只保留含具体数学操作步骤的句子。我一般做法是把解析句子按动词分类动词是“令”“由”“得”“代入”“化简”的保留“显然”“可知”“不难证明”这种逻辑引导词放入弱监督集。6. 数据集质量验证与小样本启动先让模型跑起来再扩容6.1 用一个小模型做冒烟测试验证数据可学数据集构建完成之后先不要急着上大模型。我习惯拿一个百亿参数以下的小模型做冒烟测试验证数据的“可学习性”。测试任务选三个知识点分类、题型分类、简单解题步骤生成。如果小模型在这三个任务上能有超出随机水平的明显表现说明数据集的基本质量过关。冒烟测试的配置我一般固定下来用 5000 条训练样本300 条验证样本训练 3 个 epoch看验证集准确率和 loss 曲线。知识点分类准确率能到 60% 以上题型分类能到 85% 以上就说明标签和文本的对应关系是清晰的。如果准确率极低多半不是模型问题而是数据里有系统性标注错误这时候要回溯检查自动标注那一步。跑冒烟测试时的数据划分有个容易踩的坑不能随机划分要按“题目来源”划分。同一个来源的题目标注风格和文本风格高度一致随机划分会让模型学到来源特征而不是数学特征。按来源划分后准确率会下降但那个下降后的数字才是真实水平。6.2 人工抽检的五个检查点冒烟测试过了不能代表一切人工抽检是数据集上线前的最后一道闸门。我有五个固定的检查点每个检查点的抽样数量至少 100 条。第一个检查点是公式完整性。抽 100 条含公式的题目看 LaTeX 命令是不是配平的有没有\frac 少了后面的大括号或者\sqrt 里的内容被截断。第二个检查点是知识点标签的合理性。只看题干不看预测结果先自己标三个知识点再对比系统标出来的三个重合度低于 50% 就说明标签体系的粒度设定有问题。第三个检查点是答案和题干的一致性。答案是解析的最后一行能被推导出来的结果如果答案和题干数据自相矛盾那就是数据整并时出了错。第四个检查点是难度系数的分布。统计难度系数的直方图正常应该是近似正态分布如果出现所有题目都集中在 0.4~0.6 之间说明标注时大家都往中间值靠了。第五个检查点是文本编码。随机抽 100 条打印到终端看有没有“\u”转义残留、有没有半角全角混用导致的排版错乱。这个问题在数据量大的时候常常被忽略但下游模型一旦输入编码错乱推理结果直接作废。6.3 增量迭代从 500 题到 5000 题的扩展路径数据集的第一版不用贪大。我建议先以 500 道题为目标覆盖全部一级知识点和 60% 的二级知识点在冒烟测试通过后再按“缺什么补什么”的原则扩到 5000 道。扩量过程中有个教训不要盲目加新来源优先把已有来源的题目做深。同一个来源的题目从 100 道扩展到 500 道文本风格一致清洗管道可以复用边际成本低。新来源引入一次至少要跑两轮清洗规则迭代成本远高于多采旧来源的题。扩展路径上我是按“知识点矩阵 难度矩阵”两个维度做增量规划的。先统计现有数据在“知识点 × 难度”这个二维矩阵里的覆盖情况找出空白格再定向补采。比如“立体几何 × 高难度”是空白就去搜“立体几何 二面角 动点 取值范围”这类题。这种定向补采比按来源补采更有效因为它的目标是补齐分布短板而不是单纯堆量。最后想讲一个我自己的教训早期做这份数据集时我在清洗阶段用了一个很激进的正则把题干里的“2019 全国 I 卷”这类来源信息全部删掉理由是噪声小后来发现这些年份和地区信息对模型做迁移学习有微弱的正向作用——它们帮助模型理解题目风格和难度分布。从那以后凡是删除类操作我都要先想一想这条信息有没有语义价值再决定保留还是删除。这份克制让我在数据集这条路上少走了很多弯路希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →