
这个工具解决什么问题
做文本分类或图像分类,数据标好之后第一件事就是划分训练集和验证集。顺手写个脚本:读文件、随机打乱、切三份、分别存盘——十分钟的事。可麻烦在后面:换一份数据要改路径,换个比例要改数字,想固定结果让实验可复现还得记得设随机种子。最坑的是「划分不均」:你手上有 600 条标注数据,其中某个类别只有 19 条,随机切分之后验证集里一条都没有,训练时这个类等于没有监督信号,模型指标看着还行、上线就翻车。你还得回头写分层抽样,用 sklearn 的 train_test_split(stratify=...) 又要记参数、装环境。一份数据划分折腾半小时,还未必分对。
- 原来的做法:每次手写(或改写)划分脚本;比例、种子写死在代码里;样本量少的类别在随机切分下常常整类落进同一个子集,验证集里一个都没有;想复现上次的结果得翻半天记录找种子。
- 用这个工具:打开工具 → 选数据集文件 → 标签列自动猜好 → 点「开始划分」。程序按类别分别切分,每个类别在训练/验证/测试里都按同一比例出现,小类别也不会被整类切走;随机种子固定,同样的输入重跑一定得到同样的划分。右侧直接给出各子集份数与类别分布交叉表。
- 省下来的:把「写脚本 + 调脚本 + 回头补分层抽样」压缩成「点一次按钮」。600 条数据 0.01 秒出结果,三份文件带统计报告一起落盘。
技术实现
整体是「内核 + 界面」两层。内核 split_core.py 只做纯计算:解析数据集、校验比例、划分、落盘、渲染报告,一行 tkinter 代码都没有,所以可以脱离图形环境用 tests/selftest.py 完整回归。界面 split_gui.py 只负责画控件和把结果贴到屏幕上。分层的原因是 tkinter 的单线程限制:划分逻辑一旦变重(几十万行数据)就会卡住界面,所以内核跑在后台线程里,通过 queue 把结果交回主线程刷新——注意不是直接在后台线程里调 root.after,那在 Tcl 解释器未进入 mainloop 时会直接抛 RuntimeError。
- 份数分配用最大余数法,总和恒等于总样本数:按比例分配最朴素的做法是 round(n × ratio),但三份分别四舍五入之后和往往不等于 n——n=100、比例 1:1:1 时会得到 33/33/33 共 99,凭空少一行,用户看到「原始 100 行、三份加起来 99 行」会直接怀疑工具丢了数据。这里改用最大余数法:先向下取整,再把剩余份额按小数部分从大到小补 1,保证 sum(counts) == n。自测对 n=1..40 与 100/137/999/1000/1001 逐一断言了这一点。
- 分层划分:按类别分别切分,小类别不会被整类切走:随机划分的本质问题是每个类别被独立抽样。一个只占 3%、共 16 条的类别,在 80/10/10 下有很大概率被切得七零八落。分层划分的做法是:把同一类别的行索引取出、单独打乱、按同一套比例切三份,再把各子集的片段拼起来——这样每个子集内部的类别比例都与整体一致。配套做了「至少 1 个」补偿:比例 0.97/0.02/0.01、n=50 时测试集按纯比例只有 0.5 个、取整成 0,会从最大那一组借 1 个过来,避免产出空文件。
- 可复现:类别按字符串排序后处理,与字典顺序无关:所有随机操作共用一个 random.Random(seed) 实例,且分组时类别按 str(key) 排序后依次处理——如果按字典插入顺序处理,同一份数据在不同机器上可能得到不同结果(虽然概率低,但复现性不该有概率)。同输入 + 同种子 → 完全一致的划分,自测里有两条断言专门守这个性质(同种子两次必须全等、换种子必须不同)。
- 不重不漏自检,宁可当场报错也不产出脏数据:每次划分后强制校验:三个子集拼起来不重复、不遗漏、恰好覆盖全部行索引。这不是多余的检查——划分逻辑改坏最典型的表现就是「某些行被分到两份」或「某些行谁都没分到」,而这种错误从结果表格上看不出来(总行数看着还是对的)。自测里还反向验证了校验函数本身能抓到人工构造的重叠与遗漏。
- xlsx 用标准库自己解,不引入 openpyxl/pandas:工具承诺零安装、双击即用,引第三方库等于要求每个用户先装 Python 环境。xlsx 本质是一个 zip,里面是若干 XML,只读第一个工作表的话代码量可控:zipfile 解包、ElementTree 解析 sheetData、按单元格的 r 属性(如 D7)换算坐标落位——空单元格在 xlsx 里是直接不出现的,按顺序读会把后面的列整体错位。支持共享字符串、内联字符串、布尔与公式结果四种单元格类型。
- 编码与换行保真:既不误加 BOM,也不把 CRLF 改成 LF:编码识别先判 BOM,再依次试 utf-8 / gb18030 / big5。两个方向都要防:带 BOM 的 UTF-8 若按普通 utf-8 解,第一列列名会多出一个不可见字符,用户在下拉框里选了名字却匹配不上;反过来普通 UTF-8 文件也不能被报成 utf-8-sig,否则写回时会凭空插入 BOM。输出时源是 GB 系列就沿用原编码,其余统一 UTF-8 带 BOM(Excel 打开中文不乱码);换行风格按源文件保真,否则 Windows 用户会看到「处理过的每个文件每一行都变了」的假 diff。
技术栈:Python 3.8+、tkinter 窗体、纯标准库零依赖、分层抽样
已知局限:一次只处理一个文件;不支持直接写 xlsx(xlsx 来源会导出为 CSV);不支持 K 折交叉验证(只有 train/val/test 三份);不支持按多列复合分层;不做数据清洗与去重(那是另一类工具);只读取 xlsx 的第一个工作表。
操作教程
- 打开程序并选择数据集
双击「AI 训练集划分工具.exe」。点「选择文件…」挑一份数据集(支持 csv / tsv / txt / jsonl / json / xlsx),或者点「示例数据」让程序生成一份 600 行的演示数据直接试用。也可以把数据集文件直接拖到程序图标上启动。
预期结果:右上角显示「已载入:600 行 × 3 列(csv)」,底部预览表里能看到数据前几行与列名。 - 确认表头与标签列
程序会自动判断第一行是不是表头,把结果填进「首行是表头」勾选框;判断不对就手动改一下,预览会立刻刷新。「标签列」下拉框里,程序会按「取值个数适中 + 列名带标签语义」自动猜一列并选中(示例数据会选中 label)。不想分层就在下拉框里选「(不分层)」。
预期结果:标签列显示的是你期望用来分层的列名;数据预览里的列名与实际数据一致。 - 填写划分比例与随机种子
训练/验证/测试三框默认 80 / 10 / 10。两种写法都认:「80/10/10」或「0.8/0.1/0.1」。随机种子默认 42,点「换一个」可以随机换。保持种子不变,重跑一定能得到完全一样的划分。
预期结果:比例框接受数字与百分号;种子框接受整数。填错会弹窗提示人话,不会静默失败。 - 点「开始划分」
点红色主按钮,或直接按快捷键 F5。程序在后台线程里划分,界面不会卡住。
预期结果:底部状态栏显示「完成:600 行 → 训练 480 / 验证 61 / 测试 59」。耗时不到一秒(示例数据只要几毫秒)。 - 看「类别分布」标签页(分层时最该看的一页)
这一页是「类别 × 子集」的交叉表,列出每个类别在训练/验证/测试里各有多少条。开启分层划分后,每一列的类别比例都应该和整体接近。
预期结果:示例数据里 rare 类共 19 条,被分到训练 15 / 验证 2 / 测试 2——三个子集里都有它,这正是分层划分的价值。 - 看「概览」与「划分结果」标签页
概览页给出一份纯文本报告:数据规模、划分方式、标签列、随机种子、各子集份数与实际占比、存放位置。划分结果页是一张表,列出三个子集的份数、实际占比和输出文件名。
预期结果:「合计 N 行,不重不漏校验通过」——三份文件行数加起来一定等于原始行数。 - 打开输出目录取文件
点「打开输出目录」。默认输出到源文件同级的 <文件名>_split/ 目录下。
预期结果:目录里有 reviews_train.csv、reviews_val.csv、reviews_test.csv 三个数据文件,外加 split_manifest.json(记录参数,便于复现)和 split_summary.txt(统计报告)。
常见问题
技术实现与后续维护
工具分为内核与界面两层:split_core.py 负责全部计算(读格式、比例、划分、落盘、报告),split_gui.py 只负责界面。任何划分口径的改动都在内核里,改完跑一遍 tests/selftest.py 即可回归——自测里的期望值大多是外部可验证的事实(比例定义、不重不漏、字节级往返),能真实反映口径变化。运行环境要求很低:Windows 10/11 64 位,不需要装 Python,不需要联网。后续可扩展方向包括多文件批量划分、K 折交叉验证、多列复合分层等,详见开发文档第六节。需要在此基础上做定制(比如适配私有数据格式、接入你们的训练流水线),可以联系站长进行二次开发。
技术构成:
src/split_core.py—— 内核:六种格式的读取、编码与换行处理、比例校验、最大余数法份数分配、随机与分层划分、不重不漏自检、落盘与报告渲染。零 tkinter 依赖,可脱离界面独立调用与测试。src/split_gui.py—— tkinter 图形界面:文件选择、表头与标签列控件、比例与种子输入、后台线程与队列轮询、四个结果标签页、示例数据生成、F5 快捷键与拖拽启动。tests/selftest.py—— 自测脚本,684 项断言,分 16 组覆盖比例归一、份数分配、表头与分隔符识别、编码、CSV/JSON/XLSX 读写、随机与分层划分、端到端无损校验、错误处理与静态检查。_dev/make_demo.py—— 生成演示数据集(类别不均衡的中文文本分类数据),用于截图与端到端验证。_dev/gui_smoke.py—— 界面接线冒烟脚本:构造窗口、载入数据、触发划分、打印结果表格,用于验证界面与内核的接线。DOCS/开发文档.md—— 开发文档:算法取舍(最大余数法、分层划分、可复现)、编码与格式处理、界面线程模型、六个已知坑、扩展方向与维护约定。
运行环境:
环境:Python 3.8+(必须自带 tkinter)。打包命令:pyinstaller --onefile --noconsole --name AI训练集划分工具 src/split_gui.py。必须带 --noconsole,否则双击会先弹黑色控制台窗口;必须用带 tkinter 的 Python 解释器,某些精简发行版不带 tkinter 也能编译通过,但打出的 exe 一运行就报 No module named tkinter。工程内 build.bat 是等价的一键脚本。
可扩展方向:
- 多文件 / 整目录批量划分:界面加目录选择,循环调用 split_dataset 后汇总报告
- K 折交叉验证:把三份扩展成 K 份轮转,plan_split 多返回一组分折结果
- 按多列复合分层:把若干列拼成复合键再分组,核心算法无需改动
- 划分质量报告:给出各类别在三个子集里的比例偏差量化结论
- 结果表格支持点表头排序(Treeview 的 heading command)
- 直接写出 xlsx(需引入 openpyxl 或自己拼 XML)
本工具免费提供使用,但不对外分发源码。如果你需要在本工具基础上做功能调整、对接内部系统或长期维护,可以联系我们做二次开发,源码与工程文档可在定制合作中一并交付。
需要其它功能?可以定制
这个工具只做一件事:手写脚本划分训练集/验证集,每次换数据都要重写,还怕样本量少的类别被整类切走。如果你的场景还需要别的处理,可以联系我们做二次开发,按你的实际数据格式和流程定制。
常见的定制需求:
- 适配你们自己的数据格式(比如带标注信息的 JSON 私有格式)
- 接入你们的训练流水线,划分完直接生成配置文件或触发训练
- 整目录批量划分并汇总一份总报告
- 按「类别 + 语言」「类别 + 时间窗」等多列组合分层
- 加上 K 折交叉验证与每折的统计输出
- 联系方式:https://www.biyeyuanma.cn
- 定制说明:请附上你的数据样例(脱敏即可)和期望结果,方便快速评估工作量
- 交付形式:定制项目可交付可执行程序,按需一并交付源码与工程文档,支持长期维护
使用说明与免责声明
- 本工具在本地运行,不联网、不上传任何数据到服务器。
- 涉及文件改写的功能,请在使用前备份原始文件。
- 软件完全免费,可自由使用与转发,请勿用于倒卖。
- 因误操作造成的数据问题请自行承担。

