面向训练语料的工业级文本质量分类器(61 维特征 + LightGBM)
Project description
textsentinel
面向训练语料的工业级文本质量分类器
一个 61 维手工特征提取器 + LightGBM 分类器,用于从中英混合语料中筛除损坏、跑题或低信号的段落 —— 通常作为 LLM 微调 / 预训练数据准备阶段的前置过滤器。
为什么做这个
在准备中文学术语料给 LLM 训练时,原始段落里经常混着这些"垃圾":
- CNKI PDF 提取遗留的 PUA / 脚注区字符
- 代码块、Shell 命令、IP 地址、文件路径
- LaTeX 公式 dump、行内公式残留
- 破碎的参考文献片段
- OCR 乱码字形
- 漏进中文流水线的纯英文段落
- 展平的回归系数表(数字洪流)
- 标点粘连英文单词(如
.And)
61 维手工特征提取器将文本中的结构性信号(如 PUA 字符、代码标记、表格结构、引用密度、熵值等)编码为固定维度的向量,LightGBM 分类器在此基础上学习软边界,输出 [0, 1] 质量分数。附带一个小 CLI 做批量过滤。
特性
- 61 维手工特征,分 5 个主题组(基础统计、表格结构、引用、语言风格、PDF 提取损坏)。
- LightGBM booster,特征顺序确定性 —— 跨进程、跨机器反复加载结果稳定。
- CLI ——
tqd score、tqd filter、tqd info、tqd-download、tqd-train。 - 全量类型提示,
py.typed(PEP 561)。 - 无深度学习依赖 —— 纯 NumPy + scikit-learn + LightGBM。
- 可复现 —— 固定随机种子,特征提取确定性。
- Linux / macOS / Windows + Python 3.10 / 3.11 / 3.12 全平台测试通过。
安装
pip install textsentinel
如需训练、CLI、进度条等可选依赖:
pip install "textsentinel[cli,train]"
快速上手
下载预训练模型,然后三行代码完成打分:
tqd-download --dest models/model.txt
from tqd import QualityClassifier
clf = QualityClassifier.from_pretrained("models/model.txt")
print(clf.predict("用户通信需求提升和通信技术革新是移动通信系统演进的源动力。"))
# 0.92
print(clf.should_keep("```python\nprint(1)\n```"))
# False
过滤 JSONL 语料:
tqd filter --model models/model.txt \
-i corpus.jsonl \
-k corpus.kept.jsonl \
-d corpus.dropped.jsonl
在自有标注数据上重新训练:
tqd-train --labeled data/labeled.jsonl --output models/my_model.txt
性能指标
| 指标 | 数值 |
|---|---|
| 5 折 CV AUC(均值) | 0.9913 |
| 5 折 CV AUC(标准差) | 0.0003 |
| 测试集 AUC | 0.9913 |
| 测试集准确率(阈值 0.70) | 0.9647 |
| 测试集样本数 | 31,221 |
| 训练集样本数 | 145,694 |
| 正例占比 | 0.880 |
完整 61 维特征说明见 docs/features.md,超参调优建议见 docs/training.md。
目录结构
textsentinel/
├── tqd/ # Python 包(导入名)
│ ├── __init__.py # 公开 API
│ ├── _version.py
│ ├── classifier.py # LightGBM 包装
│ ├── features.py # 61 维特征提取
│ ├── training.py # 交叉验证 + 阈值寻优
│ ├── download.py # 模型下载
│ ├── cli.py # `tqd` 命令
│ ├── config.py # YAML 配置加载
│ ├── exceptions.py # 异常体系
│ ├── logging.py # 日志
│ └── py.typed
├── tests/ # pytest 测试(单元 + 集成)
├── examples/ # 可运行示例
├── docs/ # mkdocs-material 站点
├── configs/ # 默认 YAML 配置
├── assets/ # 静态资源
├── models/ # 模型目录(默认空,按需下载)
├── scripts/ # 辅助脚本(mkdocs 等)
├── .github/ # CI、Issue 模板、Dependabot
├── pyproject.toml # 构建 + 工具配置
├── mkdocs.yml # 文档配置
├── README.md # 简体中文(你在这里)
├── CHANGELOG.md
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── SECURITY.md
├── LICENSE
└── CITATION.cff
架构
模块布局
tqd/
├── __init__.py # 公开 API 转发
├── _version.py # 版本常量
├── classifier.py # QualityClassifier:LightGBM 包装
├── cli.py # `tqd` 命令行入口
├── config.py # YAML 配置加载
├── download.py # 模型下载工具(`tqd-download`)
├── exceptions.py # 异常体系
├── features.py # 61 维特征提取
├── logging.py # 日志配置
├── training.py # 训练流水线(`tqd-train`)
└── py.typed # PEP 561 标记
数据流
推理:
QualityClassifier.from_pretrained(path)—— 加载 LightGBMBooster和附带的meta.json(含threshold和feature_names)。一次性成本(~10 ms),线程间共享安全。clf.predict(text)—— 计算 61 维特征向量(内部functools.lru_cache缓存),跑 booster。clf.should_keep(text)—— 把得分与clf.threshold比对。
特征缓存(lru_cache(maxsize=4096))对同一段文本被反复打分的场景(例如批量任务重跑)特别有用。
训练:
load_jsonl_texts(path)—— 加载已标注的 JSONL 数据。train_lightgbm(X, y, cv_folds=5)—— 5 折 CV 训 5 个 booster,然后在全部数据上训最终 booster。tune_threshold(booster, X_val, y_val, target_recall=0.95)—— 在满足召回率目标的前提下,挑精度最高的阈值。clf.save(path)—— 写path和path.meta.json,供后续from_pretrained使用。
设计决策
- 61 维特征向量,不需要 GB-level 模型。 一个梯度提升树推理亚毫秒且完全确定性。
- 特征名是 API 契约。
FEATURE_NAMES的顺序是模型文件格式的一部分,改动顺序必须重训。 - 纯 NumPy 推理 —— 不依赖 torch / GPU。
pip install后随便哪台机器都能跑。 - CLI 优先。 高频用户用 shell;
tqd覆盖最常见场景(score、filter、info),免写 Python。
错误体系
所有异常都继承自 TextSentinelError:
| 异常 | 触发条件 |
|---|---|
ModelFileError |
模型文件缺失、不可读,或在占位分类器上调 .predict()。 |
FeatureDimensionMismatchError |
保存的模型特征数与当前代码不一致。 |
ConfigurationError |
YAML 配置缺失或格式错误。 |
DownloadError |
模型下载时网络或校验失败。 |
贡献
欢迎所有形式的贡献 —— 提 Issue、修文档、加功能、改性能都行。详见 CONTRIBUTING.md。参与即表示同意遵守我们的 CODE_OF_CONDUCT.md。
引用
如果在学术工作中使用本库,请通过 CITATION.cff 引用。示例 BibTeX:
@software{axliupore_textsentinel,
author = {axliupore},
title = {textsentinel:面向训练语料的文本质量分类器},
year = {2026},
url = {https://github.com/axliupore/textsentinel},
}
开源协议
Apache 2.0 —— 见 LICENSE。
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file textsentinel-0.1.0.tar.gz.
File metadata
- Download URL: textsentinel-0.1.0.tar.gz
- Upload date:
- Size: 36.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3676f197d247327deee2d9add89e6d59f3fd009e2f002eb8838b0dd30347f791
|
|
| MD5 |
f963b079f80c473d0c2a3ea5345a626c
|
|
| BLAKE2b-256 |
cc58d22b67fa459a25392e83a4e20a8c4ad39088658e4f5aa920593bdd72a9e7
|
File details
Details for the file textsentinel-0.1.0-py3-none-any.whl.
File metadata
- Download URL: textsentinel-0.1.0-py3-none-any.whl
- Upload date:
- Size: 32.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67d142e65de37b7754c6c7a4088182937a5f90c9e4d6669b16f3654d891012d1
|
|
| MD5 |
acb86e0118cb98ba0237e53c4a739f59
|
|
| BLAKE2b-256 |
15e0f3aac42203d5c11d34469428d0dad03d2164e6a04b894c347e4dc7f776de
|