文本表示与词向量
一、初级分词技术
1. 分词(Tokenization)在NLP工程中的核心地位
- 定义:将连续文本切分成有语义的“词”或“Token”的过程,是几乎所有NLP任务(搜索、推荐、情感分析、机器翻译、LLM预处理等)的第一步。
- 重要性:分词错误会产生级联效应(Cascading Effect),直接影响下游模型效果。在工业界,高质量分词是提升系统精准度的“性价比最高”的环节之一。
- 中英文差异:英文靠空格,中文无天然边界 → 需要专门算法。
2. 传统分词主流方法(面试/工作必问)
- 基于词典 + 规则(jieba默认精确模式):
- 核心技术:前缀词典 + Trie树 → 构建DAG(有向无环图) → 动态规划找最大概率路径。
- 使用Log概率避免数值下溢。
- 公式本质:寻找使 ∑ log P(wi) 最大的路径。
- 优势:速度快、效果稳定、可解释性强。
- 缺点:依赖词典,OOV(未登录词)问题严重。
- 统计学习方法(HMM):
- 把分词转为序列标注(B/M/E/S标签)。
- jieba中HMM用于二次加工未登录词,能发现新词(如“直聘”)。
- 优点:一定程度解决OOV;缺点:假设太强,复杂歧义场景弱于CRF。
- 混合策略(jieba实际采用):
- 词典DAG + HMM后处理 → 兼顾精度与新词发现。
3. jieba实用技能(就业最常用)
- 安装与加载:pip install jieba、jieba.load_userdict()
- 三种模式:
- cut_all=False:精确模式(推荐生产使用)
- HMM=True/False:控制是否启用HMM识别新词
- 自定义词典:解决领域专有名词OOV(人名、地名、产品名、黑话等)。
- 格式:词语 [词频] [词性]
- 高词频可“强制”分词,低词频可拆分。
- 词性标注:jieba.posseg(ICTCLAS标记集),业务中常用于实体提取、关键词过滤。
4. 现代分词趋势(大模型时代必知)
- 字粒度(BERT中文):简单、无OOV,但序列长、丢失词语义。
- 子词(Subword)(GPT/BPE):当前主流,平衡词表大小与语义表达,是工业界标配。
- 传统jieba仍广泛用于数据预处理、搜索召回、规则系统等场景。
就业价值:
- 掌握jieba能让你快速处理中文文本清洗、构建领域词典、做Baseline系统。
- 理解DAG+DP、HMM、OOV处理,是NLP工程师面试常考点。
- 在搜索、推荐、客服机器人、内容审核等岗位中,直接影响上线效果和迭代速度。
练习
练习1:修改 user_pos_dict.txt 中“九”和“头”的词频
原词典示例:
text
九 10000000 n
头 1000000 n
奔波儿灞 nr
实验结果与解释:
- 高词频(如上面):动态规划时“九”和“头”单独成词的概率远高于“九头”,强制拆分为 ['九', '头', '虫']。
- 降低词频(例如改成 九 1 n、头 1 n):
- jieba更倾向于把“九头”当作一个词(如果词典里有或HMM认为合理),或仍按原有路径处理。
- 若完全删除“九”和“头”的词条,恢复默认行为,可能切成 ['九头', '虫'] 或 ['九头虫'](取决于是否加载其他词)。
- 结论:词频是“人工干预概率路径”的关键杠杆。生产中常用此技巧处理公司专有名词、品牌名、容易歧义的组合。
练习2:更换不同text短句的输出观察
以下是几个典型例子(使用精确模式 + 加载自定义词典后):
- text = "南京市长江大桥"
- 结果:['南京市', '长江大桥'](正确,避免“南京市长”歧义)
- text = "苹果手机销量很好"
- 结果:['苹果', '手机', '销量', '很', '好'](“苹果”会被识别为公司/水果,上下文决定)
- text = "我爱北京天安门"
- 结果:['我', '爱', '北京', '天安门']
- text = "奔波儿灞和九头虫大战"
- 结果:['奔波儿灞', '和', '九头虫', '大战'](自定义词典生效)
- 新词测试:text = "小米SU7汽车发布"
- 未加词典可能切成 ['小米', 'SU', '7', '汽车', '发布']
- 加入 小米SU7 nr 后 → ['小米SU7', '汽车', '发布']
二、词向量表示
1. 为什么需要词向量?(面试高频问题)
- 计算机无法直接处理文本字符串,必须把文本转换为数值向量才能输入机器学习/深度学习模型。
- 核心目标:弥合符号世界(自然语言) 与 向量空间(数学模型) 之间的鸿沟。
- 理想词向量要求:
- 能唯一标识每个词
- 蕴含语义信息(语义相近的词向量距离近,如“国王”≈“女王”,远于“香蕉”)
就业价值:这是所有NLP任务(文本分类、搜索、推荐、情感分析、LLM微调)的数据预处理基础,理解词向量演进是面试必考点。
2. 传统离散表示(经典机器学习时代)
2.1 独热编码(One-Hot Encoding)
- 原理:词典大小 = 向量维度,每个词对应位置为1,其余为0。
- 优点:简单、易实现、无歧义。
- 致命缺点:
- 维度灾难(词典10万词 → 10万维)
- 极度稀疏
- 语义鸿沟:任意两个不同词的向量正交(点积=0),完全无法表达相似性。
2.2 词袋模型(Bag-of-Words, BoW)
- 核心思想:忽略词序和语法,只统计词的出现频次 → 把文档看成“装满词的袋子”。
- 实现:对文档中所有词的One-Hot向量进行求和(或直接统计频次)。
- 相似度计算:常用余弦相似度(Cosine Similarity):
- 优点:简单有效,适合早期文本分类、垃圾邮件过滤等“看文档里有什么词”的任务。
- 缺点:完全丢失词序(“我爱你” = “你爱我”),停用词干扰大。
2.3 TF-IDF(最重要传统特征工程)
- 核心理念:一个词的重要性 = 在当前文档中越频繁 × 在整个语料库中越稀有。
- 公式:
其中:
:词t在文档d中的词频(常用归一化:次数 / 文档总词数)
:用于衡量一个词的"稀有"程度或"信息量",(log(总文档数/(1+包含词t的文档数量)))越大越稀有
就业应用:
- 关键词提取(jieba.analyse.extract_tags)
- 传统搜索引擎相关性排序
- 文本相似度计算
- 作为机器学习模型(SVM、XGBoost)的特征输入
3. N-gram 模型(词序 + 统计语言模型的开端)
- 核心思想:基于马尔可夫假设 —— 当前词只依赖前面 N−1 N-1 N−1 个词。
- 作用:引入局部词序信息,弥补BoW的缺陷。
- 常见类型:
- Unigram(1-gram):等同BoW
- Bigram(2-gram)
- Trigram(3-gram)
- 现代意义:大语言模型(GPT等)的理论鼻祖 —— 本质是超大规模N-gram(通过神经网络实现)。
挑战:维度爆炸 + 数据稀疏 → 推动了神经词向量的发展。
4. 现代深度学习时代的序号化表示(当前主流)
- 核心变化:不再手工设计复杂特征(TF-IDF、N-gram),而是把“学习语义”交给模型。
- 流程(非常重要,生产必用):
- 分词(或直接字符/子词)
- 构建/使用预训练词典(vocab.txt)
- 映射为整数ID序列
- Padding 对齐长度([PAD] = 0)
- 处理未知词([UNK] = 1)
- 输入Embedding Layer → 自动学习稠密词向量
示例(面试常考):
- 句子 → ID序列 → Padding → Tensor → Embedding
优势:
- 维度低(Embedding维度通常256~4096)
- 端到端学习语义
- 支持变长序列(Transformer)
总结
| 技术 | 适用场景 | 优缺点关键点 | 面试/工作出现频率 |
|---|---|---|---|
| One-Hot | 玩具级演示 | 维度灾难、无语义 | ★★ |
| BoW | 简单分类、Baseline | 快、丢失词序 | ★★★ |
| TF-IDF | 关键词提取、搜索、传统ML | 区分度高、仍丢失语义 | ★★★★★(高频) |
| N-gram | 语言模型、小数据场景 | 捕捉词序,但稀疏 | ★★★★ |
| 序号化+Embedding | 所有现代NLP/LLM项目 | 端到端、可迁移 | ★★★★★(核心) |
三、从主题模型到Word2Vec
1. 分布式表示(Distributed Representation)—— 词向量的理想形态
- 核心目标:将词映射到低维、稠密、蕴含语义的连续向量空间。
- 两大关键特性:
- 语义蕴含:语义相近的词向量距离近(基于分布式假设:相似上下文 → 相似向量)。
- 低维稠密:维度通常 100~300 维(远小于词典大小),每一维都有实际意义。
- 解决的问题:彻底告别 One-Hot 的维度灾难与语义鸿沟。
就业意义:这是从传统特征工程转向神经网络 NLP 的分水岭,几乎所有现代 NLP 系统(搜索、推荐、情感分析、LLM)都建立在分布式词向量基础上。
2. 主题模型(Topic Model)—— 基于全局统计的早期方案
- 代表方法:LSA(Latent Semantic Analysis) / SVD 矩阵分解。
- 核心思想:文档由多个潜在主题混合而成,词语通过主题建立关联。
SVD 矩阵分解公式(核心)
- X:词-文档矩阵(通常用 TF-IDF 填充)
- m:词典大小,n n n:文档数量
- k :主题数量(远小于 m,n,典型 100~300)
:词-主题矩阵 → 每一行就是一个词向量
:文档-主题矩阵
优点:
- 能捕捉同义词(“番茄”与“西红柿”向量接近)
- 实现简单(sklearn 的 TruncatedSVD 即可)
局限性(面试常问):
- 计算代价高(大矩阵 SVD)
- 依赖全局文档共现,忽略局部上下文和词序
- 静态,无法端到端训练
3. Word2Vec —— 现代词嵌入的真正开端(2013 Google)
- 提出者:Mikolov et al.
- 核心思想:用局部上下文预测词语(预测任务只是手段,最终目标是学到高质量词向量表)。
- 本质:浅层神经网络 + 可学习的词向量查找表(Embedding 矩阵)。
3.1 词向量获取机制(面试必考)
输入 One-Hot(或 ID) → 直接查 Embedding 矩阵 Win W_{in} Win(大小 ∣V∣×D |V| \times D ∣V∣×D) 在 PyTorch 中即 nn.Embedding(vocab_size, embed_dim)
3.2 两种经典架构
(1)CBOW(Continuous Bag-of-Words)
- 任务:根据上下文预测中心词(速度快,适合大语料)
- 流程:
- 上下文词向量求平均(或求和)得到 h h h
- h h h 与输出矩阵 Wout W_{out} Wout 相乘得得分
- Softmax + 交叉熵
核心损失函数:
(2)Skip-gram
- 任务:根据中心词预测上下文(对低频词效果更好)
- 特点:一个中心词产生多个训练样本(多标签分类)
- 核心损失函数:
CBOW vs Skip-gram 对比(就业必知):
| 维度 | CBOW | Skip-gram | 推荐场景 |
|---|---|---|---|
| 训练速度 | 快 | 慢 | 大语料选 CBOW |
| 低频词效果 | 一般 | 优秀 | 小语料/专有名词选 Skip-gram |
| 语义质量 | 较平滑 | 更精细 | 多数情况 Skip-gram 更好 |
| 资源消耗 | 较低 | 较高 | - |
3.3 训练技巧(加速关键)
- Hierarchical Softmax
- Negative Sampling(最常用,极大提升训练速度)
4. Word2Vec 的局限性(现代模型对比基础)
- 静态词向量(Static Embedding):一个词永远只有一个固定向量
- 上下文无关:无法解决一词多义(e.g. “小米”在农业 vs 手机公司)
- 无法捕捉更长距离依赖
这直接推动了后续 ELMo(上下文相关)、BERT(双向)、GPT 等动态词向量的诞生。
高频问题:
- One-Hot 与 Word2Vec 的本质区别是什么?One-Hot 是“给每个词一个独一无二的编号”,Word2Vec 是“让含义相似的词住在向量空间的同一个小区”。One-Hot 属于局部表示(Localist Representation),Word2Vec 属于分布式表示,这是 NLP 从传统机器学习走向深度学习的最重要转变之一。
- CBOW 和 Skip-gram 的区别及适用场景?
- Word2Vec 是如何让语义相近的词向量靠近的?(滑动窗口 + 点积最大化)Word2Vec 通过大量重叠上下文的预测任务,让分布式假设(相似上下文 → 相似含义)变成了向量空间中的几何距离。
- SVD 和 Word2Vec 分别捕捉哪种共现信息?SVD 是“看整篇文章里词一起出现的频率”,Word2Vec 是“看同一个句子窗口里词的邻居是谁”。
生产中常用技能:
- Gensim 快速训练 Word2Vec:Word2Vec(sentences, vector_size=300, window=5, sg=1)
- 加载预训练词向量(腾讯、智谱、百度等中文版)
- 在下游任务中 冻结或微调 Embedding 层
- 解决 OOV:用 subword(如 FastText)或 [UNK]
四、基于Gensim的词向量实践
1. Gensim 核心概念与工作流(生产必备)
Gensim 是工业界处理非结构化文本最常用、最高效的 Python 库之一,支持 TF-IDF、LSA、LDA、Word2Vec、FastText 等经典算法。
关键概念(面试常问):
| 概念 | 含义 | 实际用途 |
|---|---|---|
| 语料(Corpus) | list[list[str]](分词后的文档列表) | 所有模型的原始输入 |
| 词典(Dictionary) | token → integer ID 的映射表 | 构建 BoW、过滤 OOV |
| BoW 稀疏向量 | [(token_id, freq), ...] | 节省内存,TF-IDF/LDA 输入 |
| 模型(Model) | 训练好的转换器(如 TfidfModel、LdaModel) | 可持久化,用于新文档推理 |
标准三步工作流(几乎所有 BoW 类模型通用):
- 分词 → tokenized = [jieba.lcut(doc) for doc in docs]
- 创建词典 → dictionary = corpora.Dictionary(tokenized)
- 转为 BoW → corpus_bow = [dictionary.doc2bow(doc) for doc in tokenized]
注意:以上三步适用于 TF-IDF、LSA、LDA、NMF 等基于 BoW 的模型;Word2Vec / FastText / Doc2Vec 不需要 BoW,直接使用 list[list[str]] 即可。
import jieba
from gensim import corpora
# Step 1: 准备分词后的语料 (新闻标题)
raw_headlines = [
"央行降息,刺激股市反弹",
"球队赢得总决赛冠军,球员表现出色"
]
tokenized_headlines = [jieba.lcut(doc) for doc in raw_headlines]
print(f"分词后语料: {tokenized_headlines}")
# Step 2: 创建词典
dictionary = corpora.Dictionary(tokenized_headlines)
print(f"词典: {dictionary.token2id}")
# Step 3: 转换为 BoW 向量语料库
corpus_bow = [dictionary.doc2bow(doc) for doc in tokenized_headlines]
print(f"BoW语料库: {corpus_bow}")
输出如下:
分词后语料: [['央行', '降息', ',', '刺激', '股市', '反弹'], ['球队', '赢得', '总决赛', '冠军', ',', '球员', '表现出色']]
词典: {'刺激': 0, '反弹': 1, '央行': 2, '股市': 3, '降息': 4, ',': 5, '冠军': 6, '总决赛': 7, '球员': 8, '球队': 9, '表现出色': 10, '赢得': 11}
BoW语料库: [[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1)], [(5, 1), (6, 1), (7, 1), (8, 1), (9, 1), (10, 1), (11, 1)]]
2. TF-IDF 实战(最常用传统特征)
- 作用:给词赋予重要性权重(文档内高频 × 语料库中稀有)。
- Gensim 实现:
tfidf_model = models.TfidfModel(corpus_bow) corpus_tfidf = tfidf_model[corpus_bow] # 稀疏 TF-IDF 向量
TF-IDF 是衡量一个词在文档中重要性的经典加权方法。下面将继续使用新闻标题的例子,演示如何计算其 TF-IDF 向量。
import jieba
from gensim import corpora, models
# 1. 准备语料 (新闻标题,包含财经和体育两个明显主题)
headlines = [
"央行降息,刺激股市反弹",
"球队赢得总决赛冠军,球员表现出色",
"国家队公布最新一期足球集训名单",
"A股市场持续震荡,投资者需谨慎",
"篮球巨星刷新历史得分记录",
"理财产品收益率创下新高"
]
tokenized_headlines = [jieba.lcut(title) for title in headlines]
# 2. 创建词典和 BoW 语料库
dictionary = corpora.Dictionary(tokenized_headlines)
corpus_bow = [dictionary.doc2bow(doc) for doc in tokenized_headlines]
# 3. 训练 TF-IDF 模型
tfidf_model = models.TfidfModel(corpus_bow)
# 4. 将BoW语料库转换为 TF-IDF 向量表示
corpus_tfidf = tfidf_model[corpus_bow]
# 辅助函数:把 (token_id, weight) 转成 (token, weight),并按权重降序展示
def tfidf_with_words(tfidf_vec, id2word):
pairs = [(id2word[token_id], weight) for token_id, weight in tfidf_vec]
return sorted(pairs, key=lambda x: x[1], reverse=True)
# 打印第一篇标题的 TF-IDF 向量
first_tfidf = list(corpus_tfidf)[0]
print("第一篇标题的 TF-IDF 向量:")
print(first_tfidf)
print("第一篇标题的 TF-IDF 向量(带词语):")
print(tfidf_with_words(first_tfidf, dictionary))
# 5. 对新标题应用模型
new_headline = "股市大涨,牛市来了"
new_headline_bow = dictionary.doc2bow(jieba.lcut(new_headline))
new_headline_tfidf = tfidf_model[new_headline_bow]
print("\n新标题的 TF-IDF 向量:")
print(new_headline_tfidf)
输出如下:
第一篇标题的 TF-IDF 向量:
[(0, 0.44066740566370055), (1, 0.44066740566370055), (2, 0.44066740566370055), (3, 0.44066740566370055), (4, 0.44066740566370055), (5, 0.1704734229377651)]
第一篇标题的 TF-IDF 向量(带词语):
[("刺激", 0.44066740566370055), ("反弹", 0.44066740566370055), ("央行", 0.44066740566370055), ("股市", 0.44066740566370055), ("降息", 0.44066740566370055), (",", 0.1704734229377651)]
新标题的 TF-IDF 向量:
[(3, 0.9326446771245245), (5, 0.360796211497975)]
应用:
- 关键词提取
- 文档相似度计算(余弦相似度)
- 传统机器学习(XGBoost、SVM)的文本特征
- 搜索召回 Baseline
新文档处理:必须先转 BoW,再传入模型(OOV 词会被自动忽略)。
3. LDA 主题模型(无监督主题挖掘)
- 核心思想:每篇文档是多个主题的混合,每个主题是词的概率分布。
- Gensim 实现:
lda_model = models.LdaModel( corpus=corpus_bow, id2word=dictionary, num_topics=10, # 关键超参 random_state=42 )
实用价值:
- 自动文档聚类
- 内容分析、用户画像、推荐系统冷启动
- 可视化主题分布
输出:
- lda_model.print_topics() → 每个主题的 Top 词
- lda_model[new_doc_bow] → 文档的主题概率分布(稀疏)
4. Word2Vec 实战(分布式词向量核心)
这是本节最重要内容。
4.1 训练代码(背诵版)
from gensim.models import Word2Vec
model = Word2Vec(
sentences=tokenized_corpus, # list[list[str]]
vector_size=100, # 词向量维度(50-300 常用)
window=5, # 上下文窗口大小
min_count=2, # 忽略低频词(非常重要)
sg=1, # 1=Skip-gram(推荐),0=CBOW
hs=0, # 0=Negative Sampling(推荐)
negative=5, # 负采样数量
epochs=10, # 训练轮数
workers=4 # 多线程
)
4.2 核心参数
| 参数 | 含义 | 推荐值 / 建议 |
|---|---|---|
| vector_size | 词向量维度 | 100~300 |
| window | 上下文窗口 | 5(新闻),8~10(长文本) |
| min_count | 最小词频 | 2~5(过滤噪声) |
| sg | 算法选择 | 1(Skip-gram) 更常用 |
| negative | 负采样数 | 5~20 |
| epochs | 迭代次数 | 5~30(视语料大小) |
4.3 使用方式
# 最相似词
model.wv.most_similar('股市', topn=10)
# 相似度
model.wv.similarity('球队', '球员')
# 获取向量
vec = model.wv['市场'] # shape: (vector_size,)
# 保存(推荐只存 wv)
model.wv.save("word2vec.kv")
loaded = KeyedVectors.load("word2vec.kv")
5. 要点总结
生产中常用组合:
- Baseline:TF-IDF + XGBoost / Logistic
- 语义增强:Word2Vec 平均池化句子向量 → 全连接分类
- 主题分析:LDA → 内容标签 / 舆情分析
- 推荐系统:Word2Vec 做 Item Embedding(物品相似召回)
优势与局限:
- Gensim 训练快、内存低,适合中小规模自有语料训练领域词向量。
- 缺点:Word2Vec 是静态向量,无法解决一词多义(后续 BERT 解决)。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)