0
点赞
收藏
分享

微信扫一扫

【词的分布式表示】点互信息PMI和基于SVD的潜在语义分析


学习心得

(1)为了解决高频词误导计算机结果的问题(如“我”、“。”与其他词的共现频次很高,以至于有些木有关系的词语之间也会产生联系,即相似度)——用PMI
(2)为了解决共现频次无法反应词之间高阶关系的问题(如a和b共现,b和c共现,c和d共现,通过共现频次,可能只能获得a和c共现,而不能得到a和d共现)——用大名鼎鼎的SVD。

文章目录

  • ​​学习心得​​
  • ​​(1)计算词语共现频次矩阵​​
  • ​​(2)点互信息PMI​​
  • ​​(3)奇异值分解​​
  • ​​(4)上面方法的毛病​​
  • ​​Reference​​


我们熟悉的词的独热表示(One-hot Encoding,独热编码)即对第i个词向量——在第i个维度上设置为1,其余维均为0,这里有两个问题:


(1)即使两个词在语义上相似,但是通过余弦函数度量两者之间的相似度时可能值为0;


(2)容易导致数据稀疏问题,ex:如果在训练集中见过“机智”,而在测试集中出现了“聪明”,虽然两个词语语义相似,但是系统无法对“聪明”进行加权——即当训练数据有限时,不能充分地学习语言现象。

为了解决上面的数据稀疏问题,传统的方法是引入特征(提取更多和词相关的泛化特征,如词性特征、词义特征和词聚类特征等),但是这类做法耗时耗力;所以到了我们今天的主题——词的分布式表示:

John在1957年提出分布式语义假设:词的含义可以通过上下文的分布进行表示,我们举个例子:

(1)计算词语共现频次矩阵

首先假设语料库有三句话:

 喜欢 自然 语言 处理
深度 学习
喜欢 机器 学习

我们根据上面的3个句子创建一个如下的【共现矩阵】,即词与词之间在同一个句子中同时出现——即共现,这种矩阵的构造就能“喜欢”和“爱”之间由于有共同的上下文“我”和“学习”,从而之间有一定的相似性,不至于啥关系都木有。

【词的分布式表示】点互信息PMI和基于SVD的潜在语义分析_自然语言处理


上面矩阵的元素即如下所示:

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]])

(2)点互信息PMI

为了解决高频词误导计算机结果的问题(如“我”、“。”与其他词的共现频次很高,以至于有些木有关系的词语之间也会产生联系,即相似度),有一种做法:如果一个词和很多词共现,则降低权重;反之,如果一个词与个别词共现,则提高其权重。信息论的【点互信息】Pointwise Mutual Information, PMI就能完成这事:

# -*- coding: utf-8 -*-
"""
Created on Fri Sep 24 10:24:30 2021

@author: 86493
"""
# 一、解决高频词误导计算结果问题——PMI点互信息
from matplotlib import font_manager as fm, rcParams
import matplotlib.pyplot as plt

# 以下代码从全局设置字体为SimHei(黑体),解决显示中文问题【Windows】
# 设置font.sans-serif 或 font.family 均可
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文标签
# plt.rcParams['font.family']=['SimHei']
# 解决中文字体下坐标轴负数的负号显示问题
plt.rcParams['axes.unicode_minus'] = False


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) # 按行求和
total = col_totals.sum() # 总频次
# 获得每个元素的分子
expected = np.outer(row_totals, col_totals) / total
M = M / expected
# Silence distracting warnings about log(0):
# 不显示log(0)的警告
with np.errstate(divide='ignore'):
M = np.log(M)
M[np.isinf(M)] = 0.0 # log(0) = 0,将log(0)置为0
if positive:
M[M < 0] = 0.0
return M

M_pmi = pmi(M)
# 将打印结果保留两位小数
np.set_printoptions(precision=2)
print(M_pmi)

输出的处理后的新矩阵为:

[[0.   0.18 0.07 0.07 0.07 0.3  0.3  0.3  0.3  0.22]
[0.18 0. 0.44 0.44 0.44 0. 0. 0. 0.66 0.18]
[0.07 0.44 0. 1.03 1.03 0. 0. 0. 0. 0.07]
[0.07 0.44 1.03 0. 1.03 0. 0. 0. 0. 0.07]
[0.07 0.44 1.03 1.03 0. 0. 0. 0. 0. 0.07]
[0.3 0. 0. 0. 0. 0. 1.48 0.78 0. 0.3 ]
[0.3 0. 0. 0. 0. 1.48 0. 0.78 0. 0.3 ]
[0.3 0. 0. 0. 0. 0.78 0.78 0. 0.78 0.3 ]
[0.3 0.66 0. 0. 0. 0. 0. 0.78 0. 0.3 ]
[0.22 0.18 0.07 0.07 0.07 0.3 0.3 0.3 0.3 0. ]]

(3)奇异值分解

为了解决共现频次无法反应词之间高阶关系的问题(如a和b共现,b和c共现,c和d共现,通过共现频次,可能只能获得a和c共现,而不能得到a和d共现),有一种方法是:大名鼎鼎的SVD(Singular Value Decompsition,奇异值分解):
对上一步的共现矩阵M进行奇异值分解:
其中U和V都是正交矩阵,而是由r个奇异值构成的对角矩阵。
(1)py就直接调用​​​np.linalg.svd​​​即可求得三个对应的矩阵;
(2)潜在语义分析LSA:通过截断奇异值分解得到的矩阵U中的每一行,则为相应词的d维向量表示(性质:连续、低维、稠密),由于U的各列相互正交,即词表示的每一维表达了该词的一种独立的“潜在语义”。
(3)的每一列可以作为相应上下文的向量表示。

# 二、解决共现频次无法反应词之间高阶关系——奇异值分解,潜在语义分析
U, s, Vh = np.linalg.svd(M_pmi)

import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']

words = ["我", "喜欢", "自然", "语言", "处理", "爱", "深度", "学习", "机器", "。"]

my_font = FontProperties(fname=r"D:\anaconda1\envs\tensorflow\Lib\site-packages\matplotlib\mpl-data\fonts\ttf\SimHei.ttf",
size=12)

for i in range(len(words)):
plt.text(U[i, 0], U[i, 1], words[i], fontproperties=my_font)
#print(U[i, 0])
#print(U[i, 1])
plt.xlim(-0.5, 0.0)
plt.ylim(-0.5, 0.6)
plt.savefig('svd.pdf')
plt.show()

SVD分解得到的正交矩阵U的每一行:相应词经过奇异值分解后的向量表示。如果仅保留前2维,从可视化图看出,上下文比较相近的词在空间上的距离比较接近,如“深度”和“学习”比较接近,而“我”、“。”等高频词和其他词语距离比较远。

【词的分布式表示】点互信息PMI和基于SVD的潜在语义分析_自然语言处理_05

(4)上面方法的毛病

(1)当共现矩阵很大时,SVD的运算速度很慢;
(2)在原来语料库上增加数据时,需要重新运行SVD算法;
(3)分布式表示适合表示较短的词或短语,而段落、句子与其共现的上下文会很少(无法获得有效的分布式表示),所以大佬们又想出新的词表示方法——词嵌入表示,见下文分解!

Reference

(1)《自然语言处理——基于预训练模型的方法》车万翔
(2)​​​SVD(奇异值分解)与LSA(潜在语义分析)​​​ (3)​​LSA,pLSA原理及其代码实现​​ (4)​​自然语言处理 - 潜在语义分析LSA背后的奇异值分解SVD​​


举报

相关推荐

0 条评论