训练 LDA:困惑度选 K 值
Train LDA: Choosing K via Perplexity
LDA 主题数 K 选多少,是老板们问得最多的问题。答案是没有"标准答案" — 但有 2 个客观指标可以参考:困惑度(perplexity) 和 主题一致性(coherence)。
1. 准备语料(接着上一节)
import pandas as pd
import gensim
from gensim import corpora
df = pd.read_pickle('comments_processed.pkl')
texts = df['tokens'].tolist()
# 1. 词典
dictionary = corpora.Dictionary(texts)
dictionary.filter_extremes(no_below=10, no_above=0.5)
# 2. 语料(词袋)
corpus = [dictionary.doc2bow(t) for t in texts]
print(f'词典: {len(dictionary)} 个词,语料: {len(corpus)} 篇文档')
2. 训练 LDA 模型
from gensim.models import LdaModel
lda = LdaModel(
corpus=corpus,
id2word=dictionary,
num_topics=10, # 主题数(先猜一个)
passes=15, # 训练轮数(15-20 即可)
iterations=200,
random_state=42,
alpha='auto',
eta='auto',
)
# 看主题
for i in range(10):
print(f'主题 {i}: {lda.print_topic(i, topn=8)}')
3. 困惑度(perplexity)选 K
import matplotlib.pyplot as plt
perplexities = []
K_range = range(2, 21)
for K in K_range:
lda = LdaModel(corpus=corpus, id2word=dictionary, num_topics=K, passes=10, random_state=42)
p = lda.log_perplexity(corpus)
perplexities.append(p)
print(f'K={K}, perplexity={p:.2f}')
# 画图
plt.plot(K_range, perplexities, 'o-')
plt.xlabel('主题数 K')
plt.ylabel('困惑度(越低越好)')
plt.title('困惑度选 K')
plt.savefig('perplexity.png', dpi=150)
困惑度陷阱:困惑度会随 K 增大持续下降,选 K 大的困惑度永远最小。实际中要找"拐点" — 困惑度下降速度变缓的位置。
4. 主题一致性(coherence)— 更推荐的指标
from gensim.models import CoherenceModel
coherences = []
for K in K_range:
lda = LdaModel(corpus=corpus, id2word=dictionary, num_topics=K, passes=10, random_state=42)
cm = CoherenceModel(model=lda, texts=texts, dictionary=dictionary, coherence='c_v')
c = cm.get_coherence()
coherences.append(c)
print(f'K={K}, coherence={c:.3f}')
plt.plot(K_range, coherences, 'o-', color='red')
plt.xlabel('主题数 K')
plt.ylabel('一致性 c_v(越高越好)')
plt.title('一致性选 K')
plt.savefig('coherence.png', dpi=150)
5. 双指标对比,取交叉点
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
axes[0].plot(K_range, perplexities, 'o-')
axes[0].set_title('困惑度(越低越好)')
axes[1].plot(K_range, coherences, 'o-', color='red')
axes[1].set_title('一致性(越高越好)')
for ax in axes:
ax.set_xlabel('主题数 K')
ax.grid(True, alpha=.3)
plt.tight_layout()
plt.savefig('k_selection.png', dpi=150)
# 找最佳 K
best_K = list(K_range)[coherences.index(max(coherences))]
print(f'推荐 K = {best_K} (一致性最高)')
选好 K 值,下一节我们把它可视化 — 主题气泡图 + 主题词云。