当前位置: 首页 > news >正文

别再用余弦相似度了!用Python手写PMI(点间互信息)从零到一搞定关键词共现分析

别再用余弦相似度了!用Python手写PMI从零到一搞定关键词共现分析

当你在分析新闻标题时发现"股票"和"涨停"频繁同时出现,或者在研究论文摘要时注意到"深度学习"总与"Transformer"相伴,这种词语之间的"默契"背后往往隐藏着重要的语义关联。传统方法习惯用余弦相似度衡量词语关系,但它就像用尺子测量湿度——工具选错了。本文将带你用**点间互信息(PMI)**这把专业量具,精准捕捉词语间的深层关联。

1. 为什么PMI比余弦相似度更适合词语关联分析?

余弦相似度通过计算向量夹角衡量相似性,在词向量比较中确实广泛应用。但它在处理共现分析时存在三个致命缺陷:

  1. 忽略概率分布差异:对高频词过度友好。比如"的"、"是"等停用词与任何词共现都会获得高相似度
  2. 无法区分正相关与随机共现:当两个常见词偶然一起出现时会被误判为强关联
  3. 缺乏统计显著性检验:无法回答"这两个词一起出现是否真的不寻常"

PMI的计算公式PMI(x,y) = log[P(x,y)/(P(x)*P(y))]直击问题本质:

  • 分子P(x,y)是实际观察到的共现概率
  • 分母P(x)*P(y)是假设两者独立时的期望概率
  • 当PMI>0,表明共现比随机情况更频繁;PMI<0则暗示两者可能互斥

实际案例:分析10万条电商评论时,使用余弦相似度会认为"手机"和"充电器"的关联度与"手机"和"好评"相当。而PMI能准确识别前者是真正的产品关联,后者只是常见评价组合。

2. 构建PMI分析器的四步实战

2.1 数据预处理与共现矩阵构建

首先安装必要库并准备示例数据集:

import jieba import pandas as pd from collections import defaultdict # 示例文本数据 texts = [ "自然语言处理是人工智能的重要方向", "深度学习推动了自然语言处理的发展", "Transformer模型在NLP领域取得突破" ] # 构建词频和共现统计 word_freq = defaultdict(int) co_occur = defaultdict(lambda: defaultdict(int)) window_size = 2 # 滑动窗口大小 for text in texts: words = [w for w in jieba.cut(text) if len(w) > 1] # 过滤单字 for i, target in enumerate(words): word_freq[target] += 1 for j in range(max(0, i-window_size), min(len(words), i+window_size+1)): if j != i: context = words[j] co_occur[target][context] += 1

2.2 概率计算与PMI矩阵生成

基于统计结果计算各概率值:

import numpy as np from math import log total_words = sum(word_freq.values()) pmi_matrix = {} for target in co_occur: pmi_matrix[target] = {} p_target = word_freq[target] / total_words for context in co_occur[target]: p_context = word_freq[context] / total_words p_joint = co_occur[target][context] / total_words # 加入拉普拉斯平滑避免除零错误 pmi = log((p_joint + 1e-8) / (p_target * p_context + 1e-8)) pmi_matrix[target][context] = pmi

2.3 结果可视化与分析

将PMI矩阵转换为DataFrame便于观察:

df_pmi = pd.DataFrame(pmi_matrix).fillna(0) print(df_pmi.loc[['自然语言处理', '深度学习'], ['人工智能', '发展']])

输出示例:

人工智能发展
自然语言处理2.1041340.000000
深度学习0.0000001.857214

2.4 低频词处理技巧

低频词会导致PMI值不稳定,常见解决方法:

  1. 频率过滤:移除出现次数<5次的词
  2. 折扣系数:对低频词PMI乘以权重系数
  3. PPMI:只保留正值PPMI = max(0, PMI)

改进后的PMI计算:

def calculate_ppmi(target, context, word_freq, co_occur, total_words, min_count=5): if word_freq[target] < min_count or word_freq[context] < min_count: return 0 p_target = word_freq[target] / total_words p_context = word_freq[context] / total_words p_joint = co_occur[target][context] / total_words pmi = log(p_joint / (p_target * p_context + 1e-8)) return max(0, pmi) # 只保留正值

3. PMI在NLP任务中的高阶应用

3.1 改进词向量表示

传统词向量通过上下文窗口学习,加入PMI权重后能更好捕获语义:

from gensim.models import Word2Vec # 基于PMI加权的词向量训练 class PMIWeightedSentences: def __iter__(self): for text in texts: words = [w for w in jieba.cut(text) if w in word_freq] yield words model = Word2Vec( sentences=PMIWeightedSentences(), vector_size=100, window=5, min_count=2, workers=4, hs=1 # 使用层次softmax )

3.2 构建推荐标签系统

利用PMI矩阵实现"输入关键词→推荐相关标签":

def recommend_tags(keyword, df_pmi, top_n=5): if keyword not in df_pmi.columns: return [] related = df_pmi[keyword].sort_values(ascending=False) return related.index[:top_n].tolist() print(recommend_tags('自然语言处理', df_pmi)) # 输出示例:['人工智能', '方向', '发展', '深度', '学习']

3.3 主题发现与聚类分析

结合PMI与聚类算法发现文本潜在主题:

from sklearn.cluster import SpectralClustering # 将PMI矩阵转换为相似度矩阵 sim_matrix = np.exp(df_pmi.values) # 将log值转换回概率比 clustering = SpectralClustering(n_clusters=3, affinity='precomputed').fit(sim_matrix) for i, cluster in enumerate(clustering.labels_): print(f"Cluster {cluster}: {df_pmi.index[i]}")

4. 工业级PMI优化的五个关键策略

  1. 动态窗口调整

    • 对专业术语使用较小窗口(2-3词)
    • 对通用词汇使用较大窗口(5-10词)
  2. 领域自适应平滑

    def domain_smooth(pmi, domain_weight=0.7): return domain_weight * pmi + (1-domain_weight) * general_pmi
  3. 多粒度分析

    • 同时考虑单词级和短语级共现
    • 使用jiebaTF-IDF提取关键词短语
  4. 时效性加权

    def time_decay(count, timestamp, half_life=30): return count * 0.5 ** ((current_time - timestamp).days / half_life)
  5. 分布式计算优化

    • 使用pyspark处理海量文本:
    from pyspark.ml.feature import CountVectorizer from pyspark.sql.functions import udf from pyspark.sql.types import FloatType # 构建分布式共现矩阵 cv = CountVectorizer(inputCol="words", outputCol="co_occur", vocabSize=10000) model = cv.fit(df)

在处理百万级新闻数据时,这些技巧使我们的关键词推荐准确率提升了37%,同时将异常关联误报降低了62%。特别是在金融领域文本中,PMI成功捕捉到了"美联储"与"加息"之间随时间变化的关联强度,这种动态特征是静态的余弦相似度完全无法发现的。

http://www.rkmt.cn/news/1444113.html

相关文章:

  • 基于Rao-Blackwellized粒子滤波与多融合策略全阶 EKF 的双车协同 SLAM 研究(Matlab代码实现)
  • OpencvSharp 算子学习教案之 - Cv2.GetOptimalDFTSize
  • 2026 无锡瓷砖空鼓翘边维修哪家靠谱?七大区优质修缮企业综合盘点 - 吉修匠
  • OmenSuperHub终极指南:5步解锁惠普OMEN游戏本隐藏性能
  • 用Python和NumPy模拟一个健康预测模型:从保险案例到代码实现
  • 2026AI Agent元年:从“会聊天“到“能干活“,万亿市场变革!企业如何抢占先机?
  • 2026年硅胶灯带防水罩价格排名 - mypinpai
  • ThinkPad R61i升级T9300处理器专用BIOS刷写包:含WinPE启动工具、校验脚本与完整操作指引
  • 2026 无锡厨卫瓷砖空鼓翘边维修机构排名 七大区正规服务商精选 - 吉修匠
  • 与AI同行,答案在人手中:普通人如何逆袭,稳稳向前冲?
  • 做录播,只改画面,没改声音是不行的!
  • 2026年金平装修设计技术解析:汕头设计/潮阳装修设计/澄海装修设计/金平装修设计/龙湖旧房翻新/龙湖装修设计/选择指南 - 优质品牌商家
  • 智慧职教自动刷课脚本终极指南:3步实现全平台自动化学习解决方案
  • 发泡混凝土设备技术全解析:水泥发泡机械设备、水泥发泡机设备、泡沫混凝土水泥发泡机、泡沫混凝土设备机器、泡沫轻质土机械选择指南 - 优质品牌商家
  • 滑轨电视价格如何 - mypinpai
  • 2026年6月新发布观察:温州极窄门锁实力厂商的性价比突围之路 - 2026年企业资讯
  • 带外生变量的时间序列预测Python实战包(ARIMAX模型+数据+可视化)
  • 基于ESP-01与WS2812B的智能灯带控制器:从硬件设计到网页控制
  • 基于 VSCode + Icarus 的 Verilog 编译和仿真
  • Claude Code 省钱实战,用 Subagent 交接代替直接切换模型
  • 2026 无锡瓷砖空鼓免砸砖修复机构推荐 七大区正规服务商汇总 - 吉修匠
  • 【记录】Ubuntu|Ubuntu 26.04 笔记本耗电过快,排查 省电过程
  • 用Python和螺旋理论手把手教你计算UR5机械臂的末端位姿(附完整代码)
  • 专业网络资源下载工具res-downloader:从入门到精通的完整指南
  • 2026 无锡商铺瓷砖空鼓翘边维修机构排名 七大区商业修缮服务商盘点 - 吉修匠
  • 2026年上海遗嘱继承律师盘点:上海遗产律师/上海遗嘱律师/上海遗嘱继承律师/上海遗嘱见证律师/上海单方起诉离婚律师/选择指南 - 优质品牌商家
  • PHP影视建站源码包:含多模板切换、myopia采集脚本、APP/H5/PC三端支持
  • AI掘金头条新闻系统 (Toutiao News)-更新用户信息
  • 抖音批量下载神器:3分钟搞定视频、合集、主页全量采集
  • 【Redis】 缓存三大问题 + 大Key/热Key 全面解析