在词的向量化表示中,简单的One-Hot会遇到数据稀疏和无法计算词之间距离的问题;分布式频次表示会遇到高频词误导计算结果的问题。基于点互信息的词向量表示方式恰好可以解决上述问题。
点互信息(Pointwise Mutual Information,PMI)是信息轮中用来衡量两个事物之间的相关性的一个指标。例如对于词A和词B的点互信息为:
其中,表示词A和词B共同出现的频率,
表示词A出现的频率,
表示词B出现的频率。
我 喜欢 游泳。
我 爱 游泳。
相同词计为0,所有词一共出现6次数。
我 | 喜欢 | 爱 | 游泳 | |
我 | 0 | 1 | 1 | 2 |
喜欢 | 1 | 0 | 0 | 1 |
爱 | 1 | 0 | 0 | 1 |
游泳 | 2 | 1 | 1 | 0 |
设(公式无法输入中文,汗):w1表示“我”,w2表示“喜欢”,w3表示“爱”,w4表示“游泳”
将共现矩阵中所以值替换为对应的PMI值便可以得到使用PMI方法表示的词向量了——每一行对应该词的词向量。
当词A和词B的共现次数过低时,对于的PMI值很可能为负数(理论可到负无穷),这通常会造成PMI的不稳定。为了解决这个问题,可以采用对负PMI转换为0的方式解决——PPMI(Positive PMI):
import numpy as np
# 单词共现矩阵
M = np.array([[0, 2, 1, 1, 1, 1, 1, 2, 1, 3],
[2, 0, 1, 1, 1, 0, 0, 1, 1, 2],
[1, 1, 0, 1, 1, 0, 0, 0, 0, 1],
[1, 1, 1, 0, 1, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 0, 1, 0, 1],
[2, 1, 0, 0, 0, 1, 1, 0, 1, 2],
[1, 1, 0, 0, 0, 0, 0, 1, 0, 1],
[3, 2, 1, 1, 1, 1, 1, 2, 1, 0]])
# 点互信息函数
def pmi(M, positive=True):
col_totals = M.sum(axis=0)
row_totals = M.sum(axis=1)
expected = np.outer(col_totals, row_totals) / M.sum()
with np.errstate(divide="ignore"):
res_log = np.log(M / expected)
# 将inf转换为0.0
res_log[np.isinf(res_log)] = 0.0
# 转换负数,PPMI
if positive:
res_log[res_log < 0] = 0.0
return res_log
M_pmi = pmi(M)
np.set_printoptions(precision=2)
print(M_pmi)