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

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

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

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

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

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


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


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

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

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

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

image.png

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

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进行奇异值分解:

M = U Σ V ⊤ \boldsymbol{M}=\boldsymbol{U} \boldsymbol{\Sigma} \boldsymbol{V}^{\top}

M=UΣV

其中U和V都是正交矩阵,而Σ {\Sigma}Σ是由r个奇异值构成的对角矩阵。

(1)py就直接调用np.linalg.svd即可求得三个对应的矩阵;

(2)潜在语义分析LSA:通过截断奇异值分解得到的矩阵U中的每一行,则为相应词的d维向量表示(性质:连续、低维、稠密),由于U的各列相互正交,即词表示的每一维表达了该词的一种独立的“潜在语义”。

(3)Σ V ⊤ \Sigma V^{\top}ΣV

的每一列可以作为相应上下文的向量表示。

# 二、解决共现频次无法反应词之间高阶关系——奇异值分解,潜在语义分析
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维,从可视化图看出,上下文比较相近的词在空间上的距离比较接近,如“深度”和“学习”比较接近,而“我”、“。”等高频词和其他词语距离比较远。

image.png


(4)上面方法的毛病

(1)当共现矩阵很大时,SVD的运算速度很慢;

(2)在原来语料库上增加数据时,需要重新运行SVD算法;

(3)分布式表示适合表示较短的词或短语,而段落、句子与其共现的上下文会很少(无法获得有效的分布式表示),所以大佬们又想出新的词表示方法——词嵌入表示,见下文分解!


Reference

(1)《自然语言处理——基于预训练模型的方法》车万翔

(2)SVD(奇异值分解)与LSA(潜在语义分析)

(3)LSA,pLSA原理及其代码实现

(4)自然语言处理 - 潜在语义分析LSA背后的奇异值分解SVD


相关文章
|
3月前
|
存储 数据采集 分布式计算
Hadoop-17 Flume 介绍与环境配置 实机云服务器测试 分布式日志信息收集 海量数据 实时采集引擎 Source Channel Sink 串行复制负载均衡
Hadoop-17 Flume 介绍与环境配置 实机云服务器测试 分布式日志信息收集 海量数据 实时采集引擎 Source Channel Sink 串行复制负载均衡
72 1
|
5月前
|
算法
分布式锁设计问题之重建节点锁信息时要分为多个阶段如何解决
分布式锁设计问题之重建节点锁信息时要分为多个阶段如何解决
|
7月前
|
供应链 监控 物联网
区块链通过其独特的分布式账本技术和智能合约功能,确保供应链信息的实时更新
**区块链技术革新供应链:分布式账本确保信息实时一致,智能合约自动执行降低错误,物联网追踪增强透明度和信任。通过去中心化、不可篡改的特性,实现交易验证、货物追踪与业务规则自动化,提升供应链效率与安全性。**
|
存储 监控 数据可视化
使用Jaeger进行分布式跟踪:学习如何在服务网格中使用Jaeger来监控和分析请求的跟踪信息
使用Jaeger进行分布式跟踪:学习如何在服务网格中使用Jaeger来监控和分析请求的跟踪信息
143 0
|
算法
m半分布式JAC联合接纳控制与用户位置信息的垂直切换matlab仿真
m半分布式JAC联合接纳控制与用户位置信息的垂直切换matlab仿真
109 0
m半分布式JAC联合接纳控制与用户位置信息的垂直切换matlab仿真
|
存储 算法 安全
分布式服务器框架之Servers.Core库实现 DES对称加密算法;SHA1信息摘要算法;MD5信息摘要算法
通信双方(通信主体)同时掌握一个钥匙,加解密都由这一个钥匙完成。通信双方通信前共同拟定一个密钥,不向第三方公开,发送前加密和接受后解密都由此密钥完成。即钥匙如果泄露,将暴露自己的全部信息。
|
XML 缓存 NoSQL
分布式服务器框架之Server.Common中通过Xml配置渠道、服务器集群、热更新信息代码解析Xml缓存进内存
ChannelConfig.cs代码解析加载ChannelConfig.xml。使用了System.Xml.Linq的XDocument工具类来加载xml文件。其基本原理就是获取到Root节点下名为“Channel”的所有Element节点,然后使用迭代器循环,拿到每一个Element中的属性,先缓存ChannelEntity结构中,最后存到字典里。
|
分布式计算 Hadoop Java
CentOS 6.X Hadoop 2.7 分布式集群环境搭建 -- 适用于四川信息职业技术学院“Hadoop应用基础教程”课程
CentOS 6.X Hadoop 2.7 分布式集群环境搭建 -- 适用于四川信息职业技术学院“Hadoop应用基础教程”课程
|
Web App开发 数据采集 NoSQL
Scrapy-Redis分布式抓取麦田二手房租房信息与数据分析
试着通过抓取一家房产公司的全部信息,研究下北京的房价。文章最后用Pandas进行了分析,并给出了数据可视化。 准备工作 麦田房产二手房页面(http://bj.maitian.cn/esfall/PG1)。
1295 0
|
3月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?

热门文章

最新文章