阶段3
|
NLP传统 · 第17课/共30课
📖 第17课:文本特征工程
🎯 课程目标
特征工程是从原始文本提取有效数值特征的过程,是传统ML方法性能的关键。好的特征工程能让简单模型超越复杂模型。
- 掌握多种文本特征提取方法
- 理解字符级、词级、混合特征的优缺点
- 学会设计任务特定的自定义特征
- 掌握特征选择技术
📐 核心原理
特征工程层次
- 字符级:n-gram,不依赖分词,对拼写错误鲁棒
- 词级:TF-IDF等,需要分词,语义信息更丰富
- 统计特征:文本长度、标点比例等,领域知识驱动
- 外部特征:词向量平均、句向量等,利用预训练知识
💡 特征选择:不是越多特征越好!高维特征中大部分是噪声。卡方检验、互信息、L1正则化是常用的特征选择方法。
🔬 多策略特征工程对比
四种特征工程策略对比
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
import jieba
import numpy as np
# 原始文本
texts_raw = [
"这部电影非常好看,剧情精彩,演员演技出色",
"太差了,浪费时间,剧情无聊",
"还行吧,一般般,中规中矩",
"强烈推荐,超出预期,非常满意",
"演技尴尬,令人失望,不推荐",
"音乐优美,画面精致,经典之作",
"烂片无疑,别去看,后悔购票",
"温馨治愈,心情愉悦,百看不厌",
]
labels = ['pos', 'neg', 'neu', 'pos', 'neg', 'pos', 'neg', 'pos']
# 特征工程策略1: 字符级n-gram
vec_char = TfidfVectorizer(analyzer='char', ngram_range=(2,4), max_features=500)
X_char = vec_char.fit_transform(texts_raw)
scores_char = cross_val_score(LogisticRegression(max_iter=1000, random_state=42), X_char, labels, cv=3)
print(f"字符n-gram: {scores_char.mean():.4f} (±{scores_char.std():.4f})")
# 特征工程策略2: 词级TF-IDF
texts_seg = [' '.join(jieba.cut(t)) for t in texts_raw]
vec_word = TfidfVectorizer(token_pattern=r'(?u)\b\w+\b', max_features=200)
X_word = vec_word.fit_transform(texts_seg)
scores_word = cross_val_score(LogisticRegression(max_iter=1000, random_state=42), X_word, labels, cv=3)
print(f"词级TF-IDF: {scores_word.mean():.4f} (±{scores_word.std():.4f})")
# 特征工程策略3: 混合特征
vec_mix = TfidfVectorizer(token_pattern=r'(?u)\b\w+\b', ngram_range=(1,2), max_features=500)
X_mix = vec_mix.fit_transform(texts_seg)
scores_mix = cross_val_score(LogisticRegression(max_iter=1000, random_state=42), X_mix, labels, cv=3)
print(f"混合1-2gram: {scores_mix.mean():.4f} (±{scores_mix.std():.4f})")
# 自定义特征
def extract_features(text):
features = {}
features['len'] = len(text)
features['punct_count'] = sum(1 for c in text if c in '!?。,')
features['exclaim'] = text.count('!')
features['question'] = text.count('?')
features['comma'] = text.count(',')
return features
feat_dicts = [extract_features(t) for t in texts_raw]
from sklearn.feature_extraction import DictVectorizer
dv = DictVectorizer()
X_custom = dv.fit_transform(feat_dicts)
scores_custom = cross_val_score(LogisticRegression(max_iter=1000, random_state=42), X_custom, labels, cv=3)
print(f"自定义特征: {scores_custom.mean():.4f} (±{scores_custom.std():.4f})")
print("\n=== 特征工程总结 ===")
print(f" 字符n-gram: {scores_char.mean():.4f}")
print(f" 词级TF-IDF: {scores_word.mean():.4f}")
print(f" 混合n-gram: {scores_mix.mean():.4f}")
print(f" 自定义特征: {scores_custom.mean():.4f}")
字符n-gram: 0.3889 (±0.0786)
词级TF-IDF: 0.3889 (±0.0786)
混合1-2gram: 0.3889 (±0.0786)
自定义特征: 0.8889 (±0.1571)
=== 特征工程总结 ===
字符n-gram: 0.3889
词级TF-IDF: 0.3889
混合n-gram: 0.3889
自定义特征: 0.8889
✅ 验证通过:代码实机运行结果如上
📝 练习
动手练习
- 实现基于词向量的文档表示(词向量平均),与TF-IDF对比
- 用卡方检验进行特征选择,分析哪些特征最有区分力
- 设计5个针对情感分析的自定义特征,验证其有效性
⚙️
🏆 成就解锁:特征锻造师
掌握了文本特征工程的全套技术,能从原始文本锻造出强大的数值特征。
🧪 扩展:特征选择方法
过滤式方法
- 卡方检验:衡量特征与类别的独立性,值越大越相关
- 互信息:衡量特征对类别的信息增益
- 方差阈值:去除方差过小的特征(几乎所有文档都一样)
包裹式方法
- 递归特征消除(RFE):逐步去掉最不重要的特征
- 前向选择:逐步添加最有用的特征
嵌入式方法
- L1正则化:自动将不重要特征的权重压缩为0
- 树模型:feature_importances_天然提供特征重要性
📚 扩展阅读:自动化特征工程
AutoML for NLP
自动化特征工程的目标是减少人工设计:
- 特征搜索:自动组合基础特征生成高阶特征
- 特征选择:自动评估特征重要性并筛选
- 超参数优化:自动搜索最佳特征组合和模型参数
然而,在NLP领域,领域知识驱动的特征工程仍然有价值——因为人类对语言的理解远超自动搜索能发现的模式。
特征工程的未来
随着深度学习的普及,手工特征工程的重要性在下降,但并非消失:
- 数据不足时,好特征仍能显著提升效果
- 可解释性要求高的场景,特征比黑箱模型更可信
- 在线学习场景,特征更新比模型微调更灵活
🔬 扩展实践:特征工程实战案例
情感分析的特征工程
针对情感分析,以下特征特别有效:
- 否定词计数:不、没、别等否定词出现次数
- 程度词强度:很→2倍,非常→3倍,极其→4倍
- 感叹号数量:!!!表示强烈情绪
- 表情符号:😊→正面,😡→负面
- 转折词:但是、然而之后的内容更重要
- 标点组合:?!表示疑惑+不满
特征交叉
将两个特征组合为新特征(如"否定词×形容词"),可以捕获交互效应:
- "不好" = 否定词 + 形容词 → 负面
- "不错" = 否定词 + 负面词 → 正面(双重否定)
FM(Factorization Machine)和DeepFM专门处理特征交叉。
🧪 扩展:特征工程实战
情感分析的特征工程
针对情感分析,以下特征特别有效:
- 否定词计数:不、没、别等否定词出现次数
- 程度词强度:很→2倍,非常→3倍,极其→4倍
- 感叹号数量:!!!表示强烈情绪
- 表情符号:😊→正面,😡→负面
- 转折词:但是、然而之后的内容更重要
特征选择方法
- 卡方检验:衡量特征与类别的独立性
- 互信息:衡量特征对类别的信息增益
- L1正则化:自动将不重要特征的权重压缩为0
- 树模型:feature_importances_天然提供特征重要性
📚 参考文献
推荐阅读
- Jurafsky & Martin. Speech and Language Processing (3rd ed). 第17课相关章节
- Manning, Raghavan & Schutze. Introduction to Information Retrieval
- Goodfellow, Bengio & Courville. Deep Learning. 自然语言处理章节
在线资源
- NLTK文档: https://www.nltk.org/
- spaCy文档: https://spacy.io/
- gensim文档: https://radimrehurek.com/gensim/
- sklearn文本处理: https://scikit-learn.org/stable/modules/feature_extraction.html
特征工程 - 关键概念速查
| 概念 | 定义 | 应用 |
| Pipeline | 处理流水线,各步骤串行执行 | 文本处理系统 |
| Tokenization | 将文本切分为词/子词单元 | 分词、子词分割 |
| Embedding | 将离散符号映射到连续向量空间 | 词向量、句向量 |
| Feature Engineering | 从原始数据提取有效数值特征 | 传统ML模型输入 |
| Fine-tuning | 在预训练模型基础上微调 | BERT等模型适配 |
本课要点回顾
- 特征工程是NLP技术栈的重要组件
- 理解原理比调用API更重要——知道为什么比知道怎么做更有价值
- 代码验证是学习的好方法——动手跑一遍胜过读十遍
- 从简单方法开始,逐步过渡到复杂方法——简单方法的基线作用不可替代
- 实践出真知——用自己的数据跑一遍,发现课本上没写的问题
❓ 常见问题FAQ
- Q: 这个方法的数据需求量是多少?
- A: 传统方法通常需要几百到几千条标注数据。深度学习方法通常需要万级以上。数据量少时优先用传统方法。
- Q: 如何处理中文的特殊情况?
- A: 中文没有天然词边界,分词质量直接影响下游效果。建议:1)使用领域词典优化分词 2)比较不同分词工具的效果 3)对关键任务做分词错误分析。
- Q: 传统方法和深度学习如何选择?
- A: 考虑三个因素:1)数据量——少数据用传统方法 2)可解释性——需要解释选传统方法 3)计算资源——资源受限选传统方法。深度学习在大数据+强算力场景下优势明显。
- Q: 如何评估和调优?
- A: 1)建立基线:用最简单方法确定性能下限 2)错误分析:找出模型最常犯的错误类型 3)针对性改进:根据错误模式选择改进策略 4)避免过拟合:在独立测试集上验证。
- Q: 生产环境部署要注意什么?
- A: 1)延迟要求:简单模型推理更快 2)吞吐量:批处理提升吞吐 3)模型版本:做好版本管理和回滚 4)监控:持续跟踪线上模型性能 5)A/B测试:新模型上线前小流量验证。
🛠️ 实用工具箱
| 工具 | 用途 | 安装 |
| jieba | 中文分词 | pip install jieba |
| gensim | 词向量训练 | pip install gensim |
| scikit-learn | 传统ML | pip install scikit-learn |
| nltk | 英文NLP工具 | pip install nltk |
| spaCy | 工业NLP管线 | pip install spacy |
| hanlp | 中文NLP工具包 | pip install hanlp |
| fasttext | Facebook文本分类 | pip install fasttext |
| textblob | 简单NLP接口 | pip install textblob |