Word2Vec 实战:让机器理解”小米”和”华为”为啥经常一起出现

老板们最神奇的需求:“让机器知道小米和华为是竞品”、”让 AI 找出一组词的相关词”

传统词频分析只能告诉你”小米”和”华为”各出现多少次,不能告诉你它们语义上相关。Word2Vec 把每个词变成高维向量(通常 100-300 维),向量距离 = 语义距离——“小米”和”华为”在向量空间里挨得很近,因为它们经常在相似的上下文出现。

我们的 Word2Vec 相似词拓展软件 封装了 Word2Vec 训练 + 相似词计算 + 关系图绘制全流程,下面拆解原理和实战。

一、Word2Vec 核心思想

核心假设:”相似的词有相似的上下文“(Distributional Hypothesis)。

Word2Vec 就是一个浅层神经网络,输入是词的 one-hot 编码,输出是该词在低维空间的稠密向量。训练完后,每个词都有一个唯一向量(100-300 维)。

二、CBOW vs Skip-gram:怎么选?

Word2Vec 有两种训练模式:

模式 思路 适用场景
CBOW (Continuous Bag-of-Words) 周围词预测中心词 语料大、词频高、想快速出向量
Skip-gram 中心词预测周围词 语料小、想抓罕见词的语义

经验

为什么 Skip-gram 在小语料更好:Skip-gram 的训练样本数 = 中心词 × 窗口大小,CBOW 的样本数 = 中心词(每个中心词只造 1 个样本)。Skip-gram 样本多,每个罕见词也能得到充分训练。

三、完整训练代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import jieba
import re
from gensim.models import Word2Vec

# ========== 1. 数据准备 ==========
with open('zh_comments.txt', encoding='utf-8') as f:
texts = [line.strip() for line in f if line.strip()]

# 加载自定义词典
jieba.load_userdict('custom_words.txt')

# 分词 + 清洗
sentences = []
for text in texts:
# 1. 分词
words = jieba.lcut(text)
# 2. 去停用词、单字、纯标点
cleaned = [
w for w in words
if len(w) > 1
and not re.match(r'^[\W\d]+$', w)
and w not in stopwords
]
sentences.append(cleaned)

# ========== 2. 训练模型 ==========
model = Word2Vec(
sentences=sentences,
vector_size=100, # 向量维度(常用 100-300)
window=5, # 上下文窗口(前后各 5 词)
min_count=5, # 忽略出现 < 5 次的词
workers=4, # 多线程
sg=1, # 1=Skip-gram, 0=CBOW
epochs=10, # 训练轮数
seed=42
)

# 保存模型
model.save('word2vec.model')
# 单独保存词向量(轻量)
model.wv.save_word2vec_format('vectors.txt', binary=False)

关键参数

四、相似词计算

1
2
3
4
5
6
7
8
9
10
11
# 单个词的相似词
similar = model.wv.most_similar('小米', topn=10)
for word, score in similar:
print(f'{word:8s} {score:.4f}')
# 华为 0.8234
# 手机 0.7891
# 苹果 0.7521
# OPPO 0.7109
# vivo 0.6923
# 性价比 0.6534
# ...

“小米”的 Top 10 相似词全部是手机品牌或相关词——Word2Vec 真的学到了”小米是手机品牌”这个语义。

批量相似词

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def batch_similar(target_words, topn=10):
"""批量计算多个词的相似词,导出 DataFrame"""
rows = []
for target in target_words:
if target not in model.wv:
rows.append({'目标词': target, '相似词': '(不在词表中)', '相似度': None})
continue
for word, score in model.wv.most_similar(target, topn=topn):
rows.append({'目标词': target, '相似词': word, '相似度': round(score, 4)})
return pd.DataFrame(rows)

# 找出"竞品词"的相似词
targets = ['小米', '华为', '苹果', 'OPPO', 'vivo', '三星']
df = batch_similar(targets, topn=20)
df.to_excel('similar_words.xlsx', index=False)

词-词相似度(两个词有多像)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 两个词的余弦相似度
sim = model.wv.similarity('小米', '华为')
print(f'小米 vs 华为 = {sim:.4f}') # 0.8234

# 三元类比: a - b = c - ?
# "国王" 减 "男人" 加 "女人" = "皇后"
# 例: "小米" 减 "手机" 加 "电脑" = ?
result = model.wv.most_similar(positive=['小米', '电脑'], negative=['手机'], topn=5)
for word, score in result:
print(f'{word:8s} {score:.4f}')
# 联想 0.6234
# 戴尔 0.5891
# 笔记本 0.5521

三元类比的业务价值:可以做”语义迁移”。比如想找”和手机一样体验好的电脑”,就 手机 - 小米 + 电脑

五、相似词关系图

把一批目标词的 Top 10 相似词画成网络图,连边粗细 = 相似度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import networkx as nx
import matplotlib.pyplot as plt

def plot_similar_network(model, target_words, topn=8, threshold=0.5):
G = nx.Graph()

for target in target_words:
if target not in model.wv:
continue
for word, score in model.wv.most_similar(target, topn=topn):
if score >= threshold:
G.add_edge(target, word, weight=score)

# 布局
pos = nx.spring_layout(G, k=0.8, iterations=50, seed=42)

# 画图
fig, ax = plt.subplots(figsize=(14, 10))
node_sizes = [800 if n in target_words else 200 for n in G.nodes()]
edge_widths = [G[u][v]['weight'] * 3 for u, v in G.edges()]

nx.draw_networkx_nodes(G, pos, node_size=node_sizes,
node_color=['#ff5cb3' if n in target_words else '#6e5cff'
for n in G.nodes()],
alpha=0.85, ax=ax)
nx.draw_networkx_edges(G, pos, width=edge_widths,
edge_color='rgba(0, 212, 255, 0.4)', ax=ax)
nx.draw_networkx_labels(G, pos, font_size=10,
font_color='#fff', ax=ax)

ax.set_title('Word2Vec 相似词关系图', fontsize=15)
ax.axis('off')
plt.tight_layout()
plt.savefig('similar_words_network.png', dpi=150)

return G

# 画手机品牌的相似词关系
G = plot_similar_network(
model,
target_words=['小米', '华为', '苹果', 'OPPO', 'vivo', '三星'],
topn=8, threshold=0.5
)

怎么看:粉色节点 = 目标词,紫色节点 = 相似词。边的粗细 = 相似度。一眼看出”小米/华为/OPPO/vivo 抱团”——Word2Vec 把它们识别成同一类。

六、4 种结果导出

我们的软件同时导出 4 种分析结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. 词频统计表(训练数据中每个词的出现次数)
word_freq = pd.DataFrame(
[(w, model.wv.get_vecattr(w, 'count')) for w in model.wv.index_to_key],
columns=['词', '出现次数']
).sort_values('出现次数', ascending=False)
word_freq.to_excel('word_frequency.xlsx', index=False)

# 2. 相似词统计表(每个目标词的 Top N 相似词)
df = batch_similar(target_words, topn=20)
df.to_excel('similar_words.xlsx', index=False)

# 3. 模型文件(.model 格式,gensim 可加载)
model.save('word2vec.model')

# 4. 相似词关系图(PNG/SVG)
G = plot_similar_network(model, target_words)

七、踩坑大全

1. OOV 词(Out-of-Vocabulary)min_count=5 砍掉了罕见词,输入”遥遥领先”如果只出现 2 次,词表里没有,most_similar 会报错。if word in model.wv 提前判断

2. 训练数据太少:<1 万条评论训出来的 Word2Vec 几乎是噪声。建议至少 5 万条。实在不够可以用预训练模型

1
2
3
4
# 加载中文预训练 Word2Vec(300 维, 知乎 + 微博语料)
from gensim.models import KeyedVectors
# 实际下载: https://github.com/Embedding/Chinese-Word-Vectors
wv = KeyedVectors.load_word2vec_format('chinese_word_vectors.txt', binary=False)

3. window 大小选错:评论文本短,window=3 合适;论文摘要长,window=7-10 合适。经验值:评论用 3-5,资讯用 5-7,论文用 7-10。

4. sg 参数搞反:sg=1 是 Skip-gram,sg=0 是 CBOW。网上好多教程写反了,记不住就 sg=1 走 Skip-gram(语料小时更准)。

5. 模型加载慢:大模型(几 GB)加载几分钟。建议只用词向量部分

1
2
3
# 只加载词向量,不要 .model(节省 60% 内存)
from gensim.models import KeyedVectors
wv = KeyedVectors.load_word2vec_format('vectors.txt', binary=False)

6. 评估模型质量:训练完用 model.wv.evaluate_word_analogies('questions.txt') 做类比任务评估,准确率 60%+ 算不错。

八、典型业务应用

九、Word2Vec vs BERT:什么时候用哪个?

维度 Word2Vec BERT
训练速度 快(分钟级) 慢(小时-天)
资源需求 低(CPU 可训) 高(必须 GPU)
一词多义 ❌ 静态向量 ✅ 动态向量(”苹果”水果 vs 品牌)
OOV 词 ❌ 砍掉 ✅ subword 拆分
业务场景 找相似词、关系图、推荐 文本分类、问答、NER

业务建议:80% 的”找相似词”场景,Word2Vec 够了。要处理”苹果”既指水果又指公司这种一词多义,上 BERT。


我们的 Word2Vec 相似词拓展软件 封装了上面所有功能:导入 EXCEL/TXT → 一键训练 Word2Vec → 4 大结果输出(词频表、相似词表、模型文件、关系图)。支持中英文、CBOW/Skip-gram 切换、参数自定义——业务人员不用学深度学习也能用上 Google 同款词嵌入技术。