第 二 章

构建语料库

兵马未动,粮草先行

一、什么是语料库

语料库(Corpus)是按照一定采样原则收集、整理并可用于语言研究或模型训练的大规模真实语言材料。它既可以是一摞新闻文本,也可以是带情感标签的十万条评论。

在统计与深度学习时代,语料就是模型的粮草:算法决定模型的上限,而语料质量决定模型能不能摸到这个上限。

语料库的常见分类

划分角度类型示例
是否标注生语料 / 熟语料原始网页文本 / 分词与词性标注语料
语种单语 / 双语 / 多语人民日报语料 / 中英平行翻译语料
领域通用 / 专业维基百科 / 医疗病历、法律裁判文书
文体书面 / 口语新闻、论文 / 客服对话、语音转写
用途评测语料 / 训练语料NLP 比赛公开测试集

值得收藏的公开语料:NLPCC/CCF 评测数据、THUCNews 新闻分类、ChnSentiCorp 酒店评论、LCQMC 句对匹配、维基百科与百度百科 dump;英文侧则有 Penn Treebank、WikiText、IMDB、SQuAD 等。

二、语料从哪里来

  • 公开数据集:最省心。Hugging Face Datasets、Kaggle、天池、DataFountain、各届 NLP 会议(NLPCC、CCKS)官网。
  • 开放 API:如微博开放平台、各类新闻接口,需遵守调用频率与条款。
  • 网络爬虫:从网页抓取,自由度最高,但须尊重 robots.txt、版权与个人信息保护法,仅用于学习研究。
  • 业务沉淀 / 人工构造:客服对话日志、用户评论;数据不足时可做同义改写、回译等数据增强。
爬虫三戒:一戒突破权限抓取隐私数据;二戒高频访问压垮对方服务器;三戒将数据商用或二次分发。学习阶段请控制规模、注明来源。

三、采集:爬虫实战

最简单的静态网页采集组合是 requests(取网页)+ BeautifulSoup(解析 HTML)。先安装:

bashpip install requests beautifulsoup4 pandas

下面的示例演示采集一页文章标题与正文,并写入 CSV:

python · crawler_demo.pyimport csv
import time
import requests
from bs4 import BeautifulSoup

HEADERS = {"User-Agent": "Mozilla/5.0 (学习用途)"}

def fetch(url):
    resp = requests.get(url, headers=HEADERS, timeout=10)
    resp.encoding = resp.apparent_encoding          # 自动判断编码,防乱码
    resp.raise_for_status()
    return resp.text

def parse(html):
    soup = BeautifulSoup(html, "html.parser")
    title = soup.select_one("h1").get_text(strip=True)
    body = soup.select_one("div.article").get_text("\n", strip=True)
    return title, body

def save(rows, path="corpus.csv"):
    with open(path, "w", encoding="utf-8-sig", newline="") as f:
        writer = csv.writer(f)
        writer.writerow(["title", "content"])
        writer.writerows(rows)

rows = []
for page in range(1, 6):                   # 仅抓 5 页做演示
    html = fetch(f"https://example.com/news?page={page}")
    rows.append(parse(html))
    time.sleep(2)                          # 礼貌等待,减轻服务器压力
save(rows)
print("采集完成,共", len(rows), "篇")
如果目标页面是 JavaScript 动态渲染的,可改用 Playwright 或 Selenium 驱动真实浏览器获取渲染后的内容。

四、语料清洗

原始网页文本夹杂着 HTML 标签、广告、导航栏、特殊符号与重复内容,必须清洗。典型流水线为:

  1. 去标签:解析 HTML,只保留正文容器,剔除脚本、样式与广告。
  2. 统一编码与全半角:统一为 UTF-8;按需把全角字母数字转半角,英文统一大小写。
  3. 正则去噪:删除多余空白、URL、连续标点、版权声明等模板化噪声。
  4. 去重:精确去重可用哈希,近似去重可用 MinHash / SimHash,解决转载与洗稿。
  5. 质量过滤:剔除过短、乱码比例高、符号占比异常的文档。
  6. 敏感与隐私处理:脱敏手机号、身份证号、姓名等个人信息。
python · clean_demo.pyimport re
import hashlib

def clean_text(text):
    text = re.sub(r"https?://\S+", "", text)                 # 去 URL
    text = re.sub(r"1[3-9]\d{9}", "<PHONE>", text)        # 手机号脱敏
    text = re.sub(r"[\t\r\f\v]+", " ", text)            # 空白归一
    text = re.sub(r"\n{2,}", "\n", text)
    text = re.sub(r" {2,}", " ", text)
    return text.strip()

def doc_hash(text):
    """用于精确去重的文档指纹"""
    return hashlib.md5(text.encode("utf-8")).hexdigest()

五、语料标注

清洗后的生语料要变成可训练监督模型的熟语料,还需标注。不同任务标注的内容不同:

任务标注内容常见规范 / 工具
分词词边界(词之间加空格)北京大学 / 宾大中文树库规范
词性标注每词的名词、动词等标记POS tagset
命名实体实体边界与类别BIO 体系:B-PER / I-PER / O
情感分类褒 / 贬 / 中性标签可多级标注加仲裁
问答问题、答案、证据段落SQuAD 范式

BIO 是序列标注的事实标准:B 表示实体首词,I 表示实体延续,O 表示非实体。例如:

# 字/词      标签
小明          B-PER
在            O
北京          B-LOC
学习          O
人工智能      O

标注流程建议:制定标注规范文档 → 小规模试标统一口径 → 双人独立标注 → 计算 Kappa 一致性系数 → 分歧仲裁。可用工具:doccano、Label Studio、BRAT。

bash · 十分钟启动 doccano 标注平台pip install doccano
doccano init
doccano createuser --name admin --password pass1234
doccano webserver --port 8000

六、存储格式

  • TXT:一行一篇或一句话,适合大规模语言模型预训练语料;
  • CSV / Excel:表格型小数据,注意用 utf-8-sig 编码以便 Excel 直接打开不乱码;
  • JSON / JSONL:字段灵活,JSONL(每行一个 JSON 对象)是 NLP 工程最主流格式;
  • 数据库:SQLite(零部署)、MySQL/PostgreSQL(多人协作);向量语料可存入向量数据库(第九章问答机器人会用到)。
jsonl · corpus.jsonl 示例{"id": 1, "title": "分词原理", "content": "……", "label": "技术", "source": "web"}
{"id": 2, "title": "情感词典", "content": "……", "label": "技术", "source": "web"}

读取 JSONL 的惯用法

pythonimport json

with open("corpus.jsonl", encoding="utf-8") as f:
    data = [json.loads(line) for line in f if line.strip()]
print(len(data), data[0]["title"])

七、交互演示:语料统计

语料整理完后,第一步往往是摸家底:多少段落、多少句子、平均句长、词种数、高频词分布。下面的演示完全在浏览器内运行——粘贴任意中文文本即可看到统计结果(分词使用内置词典的正向最大匹配)。

语料统计台浏览器本地运行

实际工程中,同样的统计用 Python 几行即可完成:len(text) 看字符量,正则切句看句子数,jieba.lcut 后用 collections.Counter 看高频词,再用 matplotlib 画分布图。