第一章:NLP概述与文本预处理

大家好,我是你们这门课的主讲。今天咱们聊聊NLP的起点——文本预处理。

说实话,我见过太多同学一上来就调模型、跑BERT,结果数据一塌糊涂,模型效果自然惨不忍睹。文本预处理,说白了就是NLP的地基。地基不稳,楼盖得再高也得塌。

1.1 NLP发展史:从规则到深度学习

NLP这几十年的发展,我把它分成三个阶段。你想想看,是不是很有意思?

  • 规则时代(1950s-1990s):全靠人工写规则。比如“如果句子以‘吗’结尾,就是疑问句”。我刚开始接触NLP时,还见过老代码里几千条if-else,维护起来简直噩梦。
  • 统计时代(1990s-2010s):用概率说话。朴素贝叶斯、HMM、CRF这些模型开始流行。我记得2012年做分词项目,CRF还是主流方案。
  • 深度学习时代(2010s至今):Word2Vec、LSTM、Transformer、BERT……模型越来越强,但数据预处理的重要性一点没减。

核心观点:无论模型多先进,80%的问题出在数据上。文本预处理就是帮你解决那80%的问题。

1.2 应用场景:NLP到底能干啥?

NLP的应用场景,说白了就是“让机器理解人话”。我挑几个最常见的说说:

场景 典型任务 我踩过的坑
搜索推荐 Query理解、关键词提取 用户搜“苹果”,到底是水果还是手机?
智能客服 意图识别、情感分析 用户说“你行你上啊”,情感是正面还是负面?
内容审核 敏感词检测、文本分类 “我靠”在不同语境下含义完全不同
机器翻译 Seq2Seq、注意力机制 “吃食堂”翻译成“eat the canteen”就闹笑话了

个人经验:做NLP项目,先搞清楚业务场景。我见过有人给客服系统上BERT,结果用户问“几点下班”,模型回了篇小作文。杀鸡焉用牛刀?

1.3 文本清洗:脏数据是万恶之源

文本清洗,说白了就是“去杂质”。我做过一个项目,数据里全是HTML标签、特殊符号、乱码。模型训练完,准确率不到50%。后来一查,原来是数据没洗干净。

常见的清洗操作:

  • 去HTML标签:用正则或者BeautifulSoup
  • 去特殊符号:保留中文、英文、数字即可
  • 去空白字符:多余的空格、换行、制表符
  • 统一大小写:英文全部转小写
  • 编码转换:统一为UTF-8
import re

def clean_text(text):
    # 去HTML标签
    text = re.sub(r'<[^>]+>', '', text)
    # 去特殊符号,保留中文、英文、数字
    text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9]', ' ', text)
    # 去多余空格
    text = re.sub(r'\s+', ' ', text).strip()
    return text

避坑指南:我曾经在清洗时把“3.14”中的点去掉了,结果数值全变了。清洗前一定要确认业务含义,别一刀切。

1.4 分词:Jieba vs HanLP

分词是中文NLP的第一步。中文不像英文有空格,所以分词很关键。我常用的两个工具:Jieba和HanLP。

Jieba:轻量级选手

Jieba上手快,适合快速验证。它有三种模式:

  • 精确模式:最常用,适合文本分析
  • 全模式:把所有可能的词都切出来,速度慢
  • 搜索引擎模式:在精确模式基础上再切长词
import jieba

text = "我爱自然语言处理"
# 精确模式
words = jieba.lcut(text)
print(words)  # ['我', '爱', '自然语言', '处理']

# 添加自定义词典
jieba.add_word("自然语言处理")
words = jieba.lcut(text)
print(words)  # ['我', '爱', '自然语言处理']

个人习惯:做项目时,我一般先用Jieba的精确模式跑一遍,看看效果。如果领域词多,就加自定义词典。简单粗暴,但有效。

HanLP:工业级选手

HanLP功能更全,支持词性标注、命名实体识别、依存句法分析等。适合生产环境。

from hanlp import HanLP

text = "我爱自然语言处理"
# 分词+词性标注
result = HanLP.segment(text)
for word, pos in result:
    print(f"{word}/{pos}", end=" ")
# 输出:我/rr 爱/v 自然语言/n 处理/vn

HanLP的模型更大,效果更好,但部署成本也高。我一般在需要高精度时用HanLP,比如金融、医疗领域的文本分析。

对比项 Jieba HanLP
安装难度 简单 中等
分词速度 中等
功能丰富度 基础 全面
适用场景 快速原型、小项目 生产环境、高精度需求

1.5 停用词过滤:去掉噪音

停用词就是那些高频但没啥意义的词,比如“的”、“了”、“是”、“在”。去掉它们,模型能更关注核心内容。

我常用的停用词表来源:

  • 哈工大停用词表
  • 百度停用词表
  • 自己根据业务积累
def load_stopwords(filepath):
    with open(filepath, 'r', encoding='utf-8') as f:
        stopwords = set([line.strip() for line in f])
    return stopwords

def filter_stopwords(words, stopwords):
    return [w for w in words if w not in stopwords]

# 示例
stopwords = load_stopwords('stopwords.txt')
text = "我今天去了图书馆,然后学习了自然语言处理"
words = jieba.lcut(text)
filtered = filter_stopwords(words, stopwords)
print(filtered)  # ['今天', '图书馆', '学习', '自然语言', '处理']

避坑指南:我曾经把“不”也加进了停用词表,结果“不喜欢”变成了“喜欢”,情感分析全反了。停用词表一定要根据任务调整,别偷懒直接用网上的。

小结

文本预处理,说白了就是“把脏数据洗干净,把长句子切碎,把没用的词扔掉”。这一步做好了,后面的模型训练才能事半功倍。

我个人习惯是:先清洗,再分词,最后去停用词。每一步都检查一下中间结果,别等到模型训练完才发现数据有问题。

嗯,今天就聊到这儿。下一章咱们聊聊词向量和特征工程,那才是真正让机器“理解”文本的开始。