NLP基础2_文本分类

基于:NLP 教程 | 菜鸟教程

文本分类(Text Classification)目标是将给定的文本文档自动归类到一个或多个预定义的类别中。

应用场景:

  1. 情感分析:判断评论是正面还是负面

  2. 垃圾邮件过滤:区分正常邮件和垃圾邮件

  3. 新闻分类:将新闻归类到体育、财经、科技等板块

  4. 意图识别:理解用户查询的真实意图

  5. 医疗诊断:根据症状描述分类疾病类

1.文本预处理

目标是保留关键语义信息,去除冗余噪声。

分词

将连续的文本字符串拆分成有意义的单元(词、字、子词)。

  • 例如:"我爱自然语言处理!" -> ["我", "爱", "自然语言", "处理", "!"] (中文分词较复杂) 或 "I love NLP!" -> ["I", "love", "NLP", "!"]

工具: jieba (中文), nltk.word_tokenizespaCystr.split() (简单英文)。

去除噪声

删除对分类任务无用甚至有害的信息:

  • 特殊字符/标点: 如 ! @ # $ % ^ & * ( ) _ +(有时保留句号、问号可能对情感分析有用)。
  • HTML/XML标签: 如 <br><div>
  • 非文本内容: 图片、代码片段。
  • 停用词 (Stop Words Removal): 移除高频但信息量低的词(如 “的”, “是”, “在”, “the”, “is”, “and”, “of”)。注意: 并非所有任务都需去除停用词(如主题建模、某些情感分析词可能关键)。

文本规范化

  • 小写化 (Lowercasing): 将所有字母转换为小写,避免模型将“Apple”和“apple”视为不同词。注意: 某些场景(如命名实体识别)可能需保留大小写。

  • 词形还原 (Lemmatization): 将单词还原为词典中的基本形式(lemma),考虑词性。如 "running" -> "run" (动词)"better" -> "good" (形容词)

  • 词干提取 (Stemming): 更激进地去除词缀,得到词干(可能不是有效单词)。如 "running" -> "run""flies" -> "fli" (Porter Stemmer)。通常比Lemmatization快但结果粗糙。

  • 处理数字: 替换为统一token(如 [NUM])或直接移除(取决于数字是否重要)。

  • 处理稀有词/拼写纠错: 对低频词进行统一替换(如 [UNK])或尝试纠正拼写错误。

2.特征提取

特征提取就是将文本数据转换为机器可理解的数值向量(特征向量)。

词袋模型 (Bag-of-Words, BoW)

核心思想: 忽略词序和语法,只关心词是否在文本中出现以及出现的频率。

步骤:

  1. 构建整个数据集的词汇表 (Vocabulary):所有出现过的唯一词(或n-gram)的集合。

  2. 对于每一篇文档,创建一个长度等于词汇表大小的向量。

  3. 向量中的每个位置对应词汇表中的一个词。

  4. 该位置的值表示该词在当前文档中的权重(如:出现次数、TF-IDF值)。

  • 示例:

    • 词汇表:["我", "爱", "自然语言", "处理", "讨厌", "数学"] (size=6)

    • 文档1:"我爱自然语言处理" -> 向量: [1, 1, 1, 1, 0, 0] (计数)

    • 文档2:"我讨厌数学" -> 向量: [1, 0, 0, 0, 1, 1]

优点: 简单直观,易于理解和实现。

缺点: 完全丢失词序信息(“狗咬人” vs “人咬狗” 向量相同);高维稀疏(词汇表巨大,每篇文档只含少量词);无法捕获词义(同义词、多义词)。

TF-IDF (Term Frequency-Inverse Document Frequency)

对BoW的改进: 不仅考虑词在文档中的频率 (TF),还考虑词在整个语料库中的重要性 (IDF)。常见词(如“的”、“the”)的IDF值低,稀有且对文档区分度高的词IDF值高。

作用: 抑制常见词的权重,提升具有区分能力的词的权重。

优点: 比简单计数更能反映词的重要性,是传统方法中非常有效的特征表示。

缺点: 依然无法解决BoW的丢失词序和词义问题。

N-grams

核心思想: 将连续的N个词作为一个单元(token)加入到BoW或TF-IDF模型中。

示例: Bi-grams (2-grams): "我爱自然语言处理" -> ["我爱", "爱自然语言", "自然语言处理"] (实际分词后组合)。

优点: 部分捕获了局部词序信息(相邻词的组合)。

缺点: 特征维度爆炸式增长(词汇表大小^N),稀疏性更严重;只能捕获局部上下文,长距离依赖依然丢失。

词嵌入 (Word Embeddings)

核心思想: 将每个词映射到一个低维、稠密、连续的实数向量空间中。关键特性:语义相似的词在向量空间中距离相近。

代表方法:

  • Word2Vec (Mikolov et al.): 通过词的上下文预测目标词 (Skip-gram) 或通过目标词预测上下文 (CBOW),训练得到词向量。能捕捉到 King - Man + Woman ≈ Queen 这样的语义关系。

  • GloVe (Global Vectors): 基于全局词-词共现统计信息进行训练。

  • FastText: 由Facebook提出,将词表示为字符n-gram的向量和,能更好地处理未登录词(OOV)和形态学丰富的语言。

    • 平均词向量 (Averaging): 将文档中所有词的向量取平均(或加权平均如TF-IDF),得到文档向量。简单有效。

    • 作为深度学习模型的输入层: 这是现在最主流的方式。词向量作为初始表示输入到神经网络(如CNN, RNN, Transformer)中,网络能够自动学习更复杂的文本表示。

优点: 低维稠密;蕴含丰富的语义和语法信息;解决了稀疏性问题;预训练模型效果好。

缺点: 静态词嵌入(Word2Vec, GloVe)无法解决一词多义问题(“苹果”公司 vs “苹果”水果);平均词向量损失了词序信息(但后续神经网络可以捕捉)。

上下文相关的词嵌入 (Contextualized Word Embeddings) 

核心思想: 一个词的向量表示依赖于它出现的具体上下文。代表模型: ELMo, BERT, GPT 等基于Transformer架构的预训练语言模型。

模型在大量无标签文本上进行预训练,学习深层的双向语言表示。对于同一个词在不同的句子中,会生成不同的向量。

优点: 解决了多义词问题;捕捉了长距离依赖和复杂语义;在各种NLP任务上达到SOTA效果。

缺点: 模型巨大,计算资源消耗大;训练和推理速度慢;需要大量数据微调效果才好(虽然比从头训练少很多);可解释性差。

3.分类模型选择

传统机器学习模型 (适用于TF-IDF/BOW/N-gram特征)

  • 朴素贝叶斯 (Naive Bayes, NB): 基于贝叶斯定理,假设特征(词)之间相互独立。优点: 简单、训练和预测速度快,尤其适合高维数据;在小数据集上也能工作。缺点: “朴素”假设(特征独立)在现实中很少成立,会影响精度。

  • 支持向量机 (Support Vector Machine, SVM): 寻找一个最优超平面来最大化不同类别数据点之间的边界。优点: 在高维空间表现好,理论完备,泛化能力较强。缺点: 对大规模数据训练较慢;核函数和参数选择需要技巧;难以直接处理多分类(需要策略如OVR)。

  • 逻辑回归 (Logistic Regression, LR): 线性模型,输出是样本属于某一类别的概率。优点: 简单、可解释性强(可以分析特征权重),输出有概率意义,易于扩展到多分类。缺点: 本质上是一个线性分类器,难以捕捉复杂的非线性关系;特征工程很重要。

  • K近邻 (K-Nearest Neighbors, KNN): 根据待分类样本的K个最近邻样本的类别进行投票决定。优点: 简单直观,无需显式训练。缺点: 预测速度慢(需计算与所有样本的距离);对高维稀疏数据敏感;需要选择合适的K值和距离度量。

  • 决策树 (Decision Tree) / 随机森林 (Random Forest) / 梯度提升树 (Gradient Boosting Trees, e.g., XGBoost, LightGBM): 基于树结构的模型。优点: 可解释性较好(树模型);能自动处理特征间的交互;对数据分布要求不高;随机森林和GBM通常效果很好。缺点: 容易过拟合(需剪枝、设置深度等);随机森林训练可能较慢;特征重要性仅反映相关性而非因果。

深度学习模型 (尤其适用于词嵌入/上下文嵌入特征)

  • 卷积神经网络 (Convolutional Neural Networks, CNN): 最初用于图像,引入NLP后擅长捕捉文本中的局部特征(如关键短语)。在句子分类任务(如情感分析)中效果显著。优点: 能有效提取局部特征;并行度高,训练相对较快。缺点: 对长距离依赖捕捉能力有限;需要固定输入长度(Padding)。

  • 循环神经网络 (Recurrent Neural Networks, RNN) / 长短期记忆网络 (Long Short-Term Memory, LSTM) / 门控循环单元 (Gated Recurrent Unit, GRU): 天然适合序列数据(文本)。RNN按顺序处理词,能捕捉序列依赖关系。LSTM/GRU通过门控机制解决了RNN的梯度消失/爆炸问题,能更好地学习长距离依赖。优点: 建模序列能力强,能处理变长输入。缺点: 训练相对较慢(难以并行);早期的RNN单元(如Vanilla RNN)难以学习长依赖;LSTM/GRU结构较复杂。

  • Transformer (特别是基于Encoder的如BERT, RoBERTa): 当前NLP的绝对主流。利用自注意力机制(Self-Attention)计算序列中所有词之间的关联权重,能高效捕捉全局依赖关系。预训练+微调范式效果极佳。优点: 并行计算效率高;建模长距离依赖能力极强;预训练模型提供强大的通用语言理解能力。缺点: 模型参数量巨大,训练和推理成本高;需要大量数据微调才能发挥最佳性能;可解释性差。

  • 注意力机制 (Attention Mechanism): 本身不是独立模型,而是增强模块(常与RNN/CNN/Transformer结合)。让模型能够动态地关注输入序列中对当前预测任务更重要的部分,显著提升性能(尤其在机器翻译、文本摘要、分类任务中聚焦关键信息)。

实操例子

新闻分类:使用20 Newsgroups数据集,这是一个经典的新闻分类数据集。

1. 数据准备

from sklearn.datasets import fetch_20newsgroups# 选择4个类别作为示例
categories = ['alt.atheism', 'soc.religion.christian', 'comp.graphics', 'sci.med']# 加载训练集和测试集
newsgroups_train = fetch_20newsgroups(subset='train', categories=categories)
newsgroups_test = fetch_20newsgroups(subset='test', categories=categories)print(f"训练集样本数: {len(newsgroups_train.data)}")
print(f"测试集样本数: {len(newsgroups_test.data)}")

2.特征提取

from sklearn.feature_extraction.text import TfidfVectorizer# 创建TF-IDF向量化器
vectorizer = TfidfVectorizer(max_features=5000)# 转换训练集和测试集
X_train = vectorizer.fit_transform(newsgroups_train.data)
X_test = vectorizer.transform(newsgroups_test.data)y_train = newsgroups_train.target
y_test = newsgroups_test.target

3.模型训练

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report# 创建并训练模型
model = LogisticRegression(max_iter=1000)
model.fit(X_train, y_train)# 预测测试集
y_pred = model.predict(X_test)# 评估模型
print(f"准确率: {accuracy_score(y_test, y_pred):.2f}")
print("\n分类报告:")
print(classification_report(y_test, y_pred, target_names=newsgroups_test.target_names))