简介SIGHAN中文纠错数据集及转换后格式.zip 面向中文自然语言处理研究者、拼写检查与语法纠错方向的开发者及学生提供汉语语法错误检测与拼音标注的权威语料。原始数据源自新加坡国立大学团队涵盖错别字、词序错误、词语搭配不当等多种人工标注错误类型适合训练与评测中文纠错算法。压缩包共78个文件约19.92MB以txt文本为主辅以sgml标注文件、readme说明、jar工具、pdf论文、xlsx表格及py脚本兼顾原始语料与转换后格式便于直接接入模型训练流程。资源内含SIGHAN 7/8及CLP14等版本并附配对数据生成脚本与简繁转换模块可帮助读者快速完成数据预处理、错误标注、训练验证测试集划分及CoNLL等格式转换。目前已有378人学习下载适合需要系统掌握中文纠错语料构建与评估流程的中高级开发者参考。1. SIGHAN中文纠错数据集从zip包到可训练格式中间隔着多少坑做中文文本纠错CSC的人绕不开 SIGHAN 这三个字。它不是一个数据集而是从 2013 年到 2015 年连续三届中文拼写纠错评测Chinese Spelling Check沉淀下来的一整套标注语料覆盖简繁体、母语者与非母语者写作场景。你手上拿到的SIGHAN中文纠错数据集及转换后格式.zip本质就是把这些原始评测文件连同已经转好的训练格式打包在一起——省掉的是你自己从零解析原始标注、对齐字级标签、再拼成 seq2seq 或序列标注输入的那几个小时。但“省掉”不等于“没有”。我见过太多人解压完直接pd.read_csv结果训练时 loss 不降、验证集 F1 卡在 0.1 上下回头才发现原始 SIGHAN 的标注是“句级 位置 替换字”三元组而转换后的格式如果没对齐字符偏移标签整体错位。这篇笔记就按“这个 zip 里到底是什么 → 怎么把它变成能喂给模型的张量 → 转换和对齐环节最容易翻车的地方”这条线走一遍适合已经跑过 BERT 或 Seq2Seq 微调、但第一次碰中文纠错数据的人。2. 拆开zip先看清SIGHAN原始标注与转换后格式的对应关系2.1 原始SIGHAN三件套source、target、位置标注SIGHAN 每一届的语料组织方式略有差异但核心结构一致一个*.sgml或*.txt存原始句子一个存纠错后的句子还有一个存错误位置和类型。以 2014 年简体中文评测为例典型文件是SIGHAN14_Train.sgml、SIGHAN14_Train.lst和SIGHAN14_Train.correct。.lst里每行格式是sid start_offset, end_offset这里的 offset 是字符级的不是字节级。很多人用 Python 读文件时默认按字节处理或者用len()去算中文长度结果偏移量对不上。正确做法是先把整句读成str再用切片取错误片段。.correct文件里每行是sid correct_sentence注意.correct给的是整句纠正后结果不是只给替换字。所以如果你要做字级序列标注每个字标 0/1需要自己用原始句和纠正句做 diff再结合.lst的位置做校验。2.2 转换后格式通常长什么样常见的转换后格式有两种一种是parallel 格式src\ttgt每行一对句子直接用于 Seq2Seq 训练另一种是char-level BIO 格式每行是字\t标签用于 BERT CRF 或 Token Classification。你拿到的 zip 里如果包含train.json、dev.json、test.json大概率是{src: ..., tgt: ...}或{text: ..., labels: [...]}结构。这里有一个容易忽略的点SIGHAN 原始数据里有些句子没有错误。转换时如果直接把所有句子都塞进训练集负样本比例会偏高模型倾向于全预测“无错”。我一般会在转换脚本里加一个过滤只保留至少有一个错误位置的句子作为正样本同时从无错句里采样等量作为负样本比例控制在 1:1 到 1:2 之间。2.3 用Python快速验证zip内文件结构拿到 zip 先别急着解压到项目根目录用zipfile列一下清单确认文件数和目录层级import zipfile with zipfile.ZipFile(SIGHAN中文纠错数据集及转换后格式.zip, r) as z: for info in z.infolist(): # 只打印文件名和大小避免解压后才发现嵌套了三层 print(f{info.filename:60s} {info.file_size:10d} bytes)逻辑说明infolist()返回每个成员的元数据file_size是压缩前大小。如果看到__MACOSX/开头的条目那是 macOS 打包时自动生成的资源分叉文件解压后可以直接删不影响数据。参数上filename可能包含中文Windows 下用cp936编码解压容易乱码建议统一用utf-8或gbk显式指定。3. 把SIGHAN转成序列标注格式对齐、标签、切分三步走3.1 字符偏移对齐为什么你的标签总是错一位原始.lst里的 offset 是从 0 开始还是从 1 开始不同年份的 SIGHAN 不一样。2013 年是从 1 开始2014 和 2015 年是从 0 开始。如果你不确认这一点直接拿 offset 去切片就会整体偏移一位。验证方法很简单取一个已知错误句用 offset 切出来的片段应该正好是错字。下面是一个对齐并生成字级标签的脚本def align_labels(src_sentence, correct_sentence, error_spans): src_sentence: 原始句子 str correct_sentence: 纠正后句子 str error_spans: list of (start, end) 字符级偏移 返回: list of (char, label) label1 表示该字错误 labels [0] * len(src_sentence) for start, end in error_spans: # 注意 end 通常是 exclusive即 [start, end) for i in range(start, min(end, len(src_sentence))): labels[i] 1 # 用纠正句做一次校验如果 src 和 correct 在非错误位置不一致说明对齐有问题 for i, (c_src, c_tgt) in enumerate(zip(src_sentence, correct_sentence)): if c_src ! c_tgt and labels[i] 0: print(f警告位置 {i} 字符不一致但未标记错误: {c_src} - {c_tgt}) return list(zip(src_sentence, labels))逻辑说明先按 error_spans 打标签再用纠正句做交叉验证。如果出现“字符不一致但标签为 0”说明 offset 解析有误或句子长度不匹配。参数上end是否包含在切片内取决于原始标注习惯SIGHAN 一般用 exclusive所以range(start, end)是对的。3.2 从parallel格式到BIO用diff自动生成标签如果你只有src\ttgt平行句对没有原始 offset可以用difflib.SequenceMatcher自动 diffimport difflib def parallel_to_bio(src, tgt): 将平行句对转为字级标签1错误0正确 matcher difflib.SequenceMatcher(None, src, tgt) labels [0] * len(src) for tag, i1, i2, j1, j2 in matcher.get_opcodes(): if tag ! equal: # 替换或删除src 中 [i1, i2) 都是错误位置 for i in range(i1, i2): labels[i] 1 return list(zip(src, labels))逻辑说明get_opcodes()返回(tag, i1, i2, j1, j2)tag 为replace、delete、insert、equal。对于inserttgt 多出字符src 没有对应位置通常忽略或标记为 0。参数上SequenceMatcher的autojunk默认 True对长句可能误判建议设为False。3.3 训练/验证/测试切分别用随机切分SIGHAN 官方已经给了 train/dev/test 划分但很多人转换后直接train_test_split(random_state42)导致同一来源的句子同时出现在训练和验证集指标虚高。正确做法是保留官方划分如果官方没给 dev就从 train 里按文档级切分而不是句子级。具体来说如果原始数据有文档 ID按文档 ID 分组后再切。from sklearn.model_selection import GroupShuffleSplit # 假设 df 有 doc_id 列 gss GroupShuffleSplit(n_splits1, test_size0.1, random_state42) train_idx, dev_idx next(gss.split(df, groupsdf[doc_id]))逻辑说明GroupShuffleSplit保证同一 doc_id 的句子只出现在一边。参数上test_size0.1是常见比例如果数据量小于 5000 句可以调到 0.15 保证验证集有足够错误样本。4. 转换后格式的坑编码、空行、简繁混用与标签泄漏4.1 编码问题GBK与UTF-8混用导致读入乱码SIGHAN 原始文件有的是 GBK有的是 UTF-8甚至同一届里不同文件编码不同。如果你用open(path, r)不指定 encodingWindows 下默认 GBKLinux 下默认 UTF-8跨平台跑脚本就会翻车。我一般统一用open(path, r, encodingutf-8, errorsreplace)遇到乱码字符先记下来再单独用gbk重读那个文件。def read_sighan_file(path): for enc in [utf-8, gbk, gb18030]: try: with open(path, r, encodingenc) as f: return f.readlines() except UnicodeDecodeError: continue raise ValueError(f无法解码文件: {path})逻辑说明按 utf-8 → gbk → gb18030 顺序尝试gb18030 是 gbk 的超集覆盖更多生僻字。参数上errorsreplace会丢失信息所以这里不用而是靠异常切换编码。4.2 空行与空白字符一个空格让标签整体偏移原始文件里经常有空行、行尾空格、全角空格。如果你用line.split(\t)后不 stripsrc末尾多一个空格和tgt长度不一致diff 就会把空格标成错误。处理方式是在读入后统一strip()但注意句首句尾的空格可能是标注的一部分strip 前先确认原始数据是否用空格表示缺失字。4.3 简繁混用SIGHAN 2013 的隐藏陷阱SIGHAN 2013 同时包含简体和繁体如果你只做简体纠错需要过滤掉繁体句子。简单方法是统计句子中繁体字符比例超过阈值就丢弃。但更稳妥的是用opencc做一次转换再和原始句对比如果转换后变化很大说明是繁体句。from opencc import OpenCC cc OpenCC(t2s) # 繁体转简体 def is_traditional(sentence, threshold0.3): converted cc.convert(sentence) diff sum(1 for a, b in zip(sentence, converted) if a ! b) return diff / max(len(sentence), 1) threshold逻辑说明t2s是繁转简配置如果转换后大量字符变化说明原句是繁体。参数上threshold0.3是经验值低于这个值可能是简繁混用或个别异体字。4.4 标签泄漏验证集里混入了训练集的纠正句如果你用平行句对做 Seq2Seqtgt是纠正后句子。切分时如果按src切分但tgt和另一边的src重复就会泄漏。检查方法把训练集的所有tgt和验证集的所有src做交集如果非空说明有泄漏。解决方式是按句对整体切分或者用src的哈希做分组。5. 避坑与排查SIGHAN转换中最容易翻车的5个地方5.1 现象训练 loss 不降验证 F1 始终为 0原因标签全为 0或者标签和输入长度不一致导致 padding 后错位。常见于用tokenizer编码后没有对齐labelstokenizer会把一个中文字拆成多个 subword而你的标签还是字级。解决用tokenizer的word_ids()方法把字级标签映射到 subword 级只保留第一个 subword 的标签其余设为 -100忽略。tokenized tokenizer(src, return_tensorspt, is_split_into_wordsTrue) word_ids tokenized.word_ids() labels [] for wid in word_ids: if wid is None: labels.append(-100) else: labels.append(char_labels[wid])5.2 现象解压后文件名乱码读不到文件原因zip 打包时用了 GBK 编码文件名解压时用 UTF-8 解码。解决用zipfile手动指定编码解压with zipfile.ZipFile(zip_path) as z: for info in z.infolist(): info.filename info.filename.encode(cp437).decode(gbk) z.extract(info, extract_dir)5.3 现象offset 切片出来的不是错字原因offset 从 1 开始或者 offset 是字节偏移而非字符偏移。解决先确认年份2013 年 offset 从 1 开始减 1 再用。如果是字节偏移先sentence.encode(utf-8)再切片然后decode。5.4 现象模型把所有字都预测为正确原因负样本比例过高或者正样本标签没有正确传播。解决检查正负样本比例控制在 1:1 到 1:2。如果正样本太少可以用WeightedRandomSampler过采样。5.5 现象验证集指标远高于测试集原因验证集和测试集同源或者验证集太小。解决确保验证集和测试集来自不同文档或不同年份。如果数据量允许验证集至少 500 句其中错误句不少于 200 句。6. 进阶技巧用SIGHAN做数据增强与跨域验证SIGHAN 数据量不大训练集通常几千句直接微调 BERT 容易过拟合。我一般会做两件事一是用同音字/形近字替换做增强二是用跨年份验证检验泛化。同音字替换的思路是从混淆集里随机选一个和原字同音或形近的字替换后作为新的错误句标签标 1。混淆集可以用pypinyin生成同音字形近字可以用zhon或手工整理。注意替换后要保证句子仍然通顺否则模型学到的是噪声。我一般只替换名词和动词不替换虚词。from pypinyin import pinyin, Style def get_homophones(char): 返回同音字列表需要预先构建拼音到字的映射 py pinyin(char, styleStyle.NORMAL)[0][0] return pinyin_dict.get(py, []) def augment_with_homophone(sentence, labels, prob0.1): 随机替换非错误位置的字为同音字生成新样本 new_sentence [] new_labels [] for ch, lab in zip(sentence, labels): if lab 0 and random.random() prob: homophones get_homophones(ch) if homophones: new_sentence.append(random.choice(homophones)) new_labels.append(1) continue new_sentence.append(ch) new_labels.append(lab) return .join(new_sentence), new_labels逻辑说明只替换原本正确的字替换后标为错误。参数上prob0.1控制增强强度太高会破坏语义。pinyin_dict需要自己从pypinyin的词典构建或者用现成的同音字表。跨年份验证更简单用 2013 年训练2014 年验证2015 年测试。如果指标下降超过 10 个点说明模型对年份风格过拟合需要加入年份无关的特征或做领域自适应。我自己的习惯是每次转换完数据先跑一个 baseline记录三个年份的 F1再决定要不要做增强。这个习惯帮我省了很多后悔药——有一次发现 2015 年测试集 F1 只有 0.3回头查才发现 2015 年数据里繁体句没过滤干净。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
Windows上模拟ARM运行麒麟V10:QEMU信创测试环境搭建指南 做信创测试的朋友,十有八九都会撞上同一个问题:交付要求你的系统跑在“鲲鹏麒麟”上,可手头根本没有鲲鹏服务器。我在这个事上折腾了好几轮,后来试着用 QEMU 在 Windows 上模拟 ARM 架构,把银河麒麟 V10 装进虚拟机&am… · 2026/9/26 11:24:45
基于STM32的智能鸽子驯养系统设计与实战 1. 项目概述:这不是玩具,是养鸽人的“智能哨兵”我第一次在河北邢台一个老鸽友的棚里看到这套系统时,他正用手机点开微信小程序,轻点两下就给三公里外的鸽舍远程投喂了200克玉米——不是靠遥控器,而是系统根据当天光照… · 2026/9/26 11:24:45
基于Python的微博情感分析系统:数据采集、情感判定与可视化实战 简介:面向本科毕业设计的Python微博情感分析系统项目,适合计算机、数据科学相关专业学生用于课程设计与毕业答辩,同时也可作为机器学习自然语言处理入门的实战参考。资源包共71个文件、6.25MB,以31个Python脚本为核心,… · 2026/9/26 11:24:39
中兴光猫实战改造:桥接、SN/MAC与地区码修改全攻略 1. 中兴光猫实战改造的核心逻辑与准备工作1.1 为什么越来越多人折腾光猫运营商给的光猫,默认状态下就是个“黑盒”——路由模式、自带WiFi、远程管理全开,用户能碰的只有表面那点设置。但实际用下来问题不少:光猫拨号再转发一层,N… · 2026/9/26 12:00:42
Java连接MySQL全攻略:从JDBC驱动原理到排查实战 做 Java 后端这几年,我见过太多新人在第一道坎上摔跟头:Java 怎么连 MySQL?网上教程良莠不齐,照着抄一遍,有人报 ClassNotFoundException,有人被时区乱码折腾到怀疑人生,还有人连了半小时只看到… · 2026/9/26 12:00:42
C#代码复杂度警示录:20个真实案例揭示如何编写更简洁、可维护的代码 作为C#开发者,我们都希望编写干净、可维护且可扩展的代码。但即便怀着最好的初衷,也容易陷入让代码难以阅读、测试或扩展的模式。随着时间的推移,小的捷径可能演变成大的混乱——导致Bug频发、开发疲劳和系统脆弱。
本文将列举20个清晰的信号… · 2026/9/26 12:00:42
Notepad++可信安装指南:规避签名失效与中文路径崩溃 简介:本资源为Windows平台下开箱即用的Notepad 7.5.8官方安装包,面向程序员、Web开发者及轻量级文本编辑需求者,解决系统记事本功能单一、缺乏语法高亮与插件扩展能力的问题。压缩包为ZIP格式,大小13.2MB,内含完整安装… · 2026/9/26 12:00:42
RT-Thread 星火一号 STM32F407 BSP 开发指南:从快速上手到设备树驱动 操作系统嵌入式物联网嵌入式OSRTOS 【免费下载链接】rt-thread RT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/ 项目地址: https://gitcode.com/gh_mirrors/rt/rt-thread 点击查看 免费下载 本文围绕… · 2026/9/26 12:00:42
HTML+CSS+JS响应式网页源码实战避坑指南 简介:这是一份面向Web前端初学者与中级开发者的意大利风味餐厅主题响应式网站HTML源码,适用于课程设计、毕业项目或小型商业站点快速搭建。资源采用纯HTML5CSS3JavaScript实现,无需后端依赖,完整呈现餐厅介绍、菜单展示、在线预约… · 2026/9/26 12:00:36
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46