【Python机器学习】NLP词频背后的含义——奇异值分解

目录

左奇异向量U

奇异值向量S

右奇异向量

SVD矩阵的方向

主题约简


奇异值分解是LSA背后的算法。我们从一个小规模的语料库开始:

python 复制代码
from nlpia.book.examples.ch04_catdog_lsa_sorted import lsa_models,prettify_tdm

bow_svd,tfidf_svd=lsa_models()
print(prettify_tdm(**bow_svd))

上面是一个文档-词项矩阵,其中的每一行都是文档对应的词袋向量。

这里我们限制了词汇表的大小,同时,我们将语料库限制为仅包含11篇使用了词汇表中的6个词的文档。但是,排序算法和大小有限的词汇表创建了几个完全相同的词袋向量。但是SVD应该能够"看到"这一点,并将主题分配给这对词。

下面首先在词项-文档矩阵(上述文档-词项矩阵的转置矩阵)上使用SVD,但是SVD也适用于TF-IDF矩阵或者任何其他向量空间模型:

python 复制代码
tdm=bow_svd['tdm']
print(tdm)

SVD是一种可以将任何矩阵分解成3个因子矩阵的算法,而这3个因子矩阵可以相乘来重建原始矩阵。这类似于为一个大整数找到恰好3个整数因子,但是这里的因子不是标量整数,而是具有特殊性质的二维实矩阵。通过SVD计算出的3个因子矩阵具有一些有用的数学性质,这些性质可以用于降维和LSA。在这里,我们将使用它为LSA计算出主题(相关词的组合)。

无论是在基于词袋的词项-文档矩阵还是基于TF-IDF的词项-文档矩阵上运行SVD,SVD都会找到属于同类的词组合。SVD通过计算词项-文档矩阵的列(词项)之间的相关度来寻找那些同时出现的词。SVD能同时发现文档间词项使用的相关性和文档之间的相关性。利用这两条信息,SVD还可以计算出语料库中方差最大的词项的线性组合。这些词项频率的线性组合将成为我们的主题。我们将只保留那些在语料库中包含信息最多、方差最大的主题。SVD同时也提供了词项-文档向量的一个线性变换(旋转),它可以将每篇文档的向量转换为更短的主题向量。

SVD(LSA的核心)用数学符号表示如下:

在上式中,m为词汇表中的处词项数量,n为语料库中的文档数量,p为语料库中的主题数量。我们希望最终得到比词数更少的主题,因此可以使用这些主题向量(主题-文档矩阵的行)最为原始TF-IDF向量的降维表示。最终我们会得到这个结果。

左奇异向量U

U矩阵包含词项-主题矩阵,它给出此所具有的上下文信息。这是NLP中最重要的用于语义分析的矩阵。U矩阵称为"左奇异向量",因为它包含一系列行向量,这些行向量必须左乘列向量组成的矩阵。基于词在同一文档中的共现关系,U给出了词与主题之间的相互关联。在截断(删除)之前,它是一个方阵,其行数和列数与词汇表中的次数(m)相同,在上面的例子中都是6。

以下面的代码,这里仍然得到6个主题(主题数目为p),因为我们还没有截断这个矩阵:

python 复制代码
import numpy as np
import pandas as pd
U,s,Vt=np.linalg.svd(tdm)
print(pd.DataFrame(U,index=tdm.index).round(2))

要注意,SVD算法是一个基本的numpy数学运算,并非一个精巧的scikit-learn机器学习算法。

U矩阵包含所有的主题向量,其中每一列主题向量对应语料库中的一个词。这意味着它可以用作一个转换因子,将词-文档向量(TF-IDF向量或词袋向量)转换为主题-文档向量。我们只需将U矩阵(主题-词矩阵)乘以任何词-文档列向量,就可以得到一个新的文档-主题向量,这是因为U矩阵中每个元素位置上的权重或得分,分别代表每个词对每个主题的重要程度。

奇异值向量S

Sigma或S矩阵是一个对角方阵,其对角线上的元素主题即"奇异值"。奇异值给出了在新的语义(主题)向量空间中每个维度所代表的信息量。对角矩阵只有在从左上角到右下角的对角线上才包含非零值,而S矩阵的其余元素都是0,因此,numpy通过以数组的形式返回奇异值来节省空间,但是也可以使用numpy.diag函数轻松将其转换为对角矩阵:

python 复制代码
print(s.round(1))
S=np.zeros((len(U),len(Vt)))
np.fill_diagonal(S,s)
print(pd.DataFrame(S).round(1))

同U矩阵一样,6个词6个主题的语料库的S矩阵有6行(p),但是它有很多列(n)都是0。每篇文档都需要一个列向量来表示,这样就可以将S乘以文档-文档矩阵。因为目前还没有通过截断该对角矩阵来降维,所以词汇表中的词项数就是主题数6(p)。这里的维度(主题)的构造:第一个维度包含关于语料库的最多信息,这样,当想要截断主题模型时,可以一开始将右下角的维度归零,然后往左上角移动。当截断主题模型造成的错误开始对整个NLP流水线错误产生显著影响时,就可以停止将这些奇异值归零。

在大多数情况下,最好将S矩阵的对角线元素设置为1,从而创建一个矩阵单位矩阵,它只是重塑了文档-文档矩阵,使之兼容于U词-主题矩阵。这样,如果将这个S矩阵乘以一些新的文档向量集,就不会使主题向量向原始主题组合(分布)倾斜。

右奇异向量

是一个文档-文档矩阵,其中每一列式"右奇异向量"。该矩阵将在文档之间提供共享语义,因为它度量了文档在新的文档语义模型中使用相同主题的频率。它的行数(p)和列数与小型语料库中的文档数相同,都是11:

python 复制代码
print(pd.DataFrame(Vt).round(2))

就像S矩阵一样,当把新的词-文档向量转换成主题向量空间时,可以忽略矩阵。我们仅仅使用来检查主题向量的准确性,以重建用于"训练"该矩阵的原始词-文档向量。

SVD矩阵的方向

相对于在scikit-learn和其他软件包中的内容,这里的词项-文档矩阵时"翻转"(转置)的。

在朴素贝叶斯情感模型和TF-IDF向量中,我们将训练集创建为一个文档-词项矩阵,这就是scikit-learn模型所需要的方向。机器学习训练集对应的样本-特征矩阵中的每一行都是一篇文档,而每一列都代表该文档的一个词或特性。但是要直接进行SVD线性代数运算时,矩阵需要转换成词项-文档格式。

在训练机器学习模型之前,要将词项-文档矩阵或主题-文档矩阵转回到scikit-learn中规定的方向。在scikit-learn中,NLP训练集中的每一行都应该包含和文档(电子邮件、短消息等)相关的特征向量。在NLP训练集中,向量是行向量,而在传统的线性代数运算中,向量通常被认为是列向量。

主题约简

现在有一个主题模型,它可以将词频向量转换为主题权重向量。但是因为主题数和词数一样多,所以得到的向量空间模型的维数和原来的词袋向量一样多。刚刚创建了一些新词并把它们命名为主题,因为它们以不同的比例将词组合在一起。到目前为止,还没有减少维数。

这里可以忽略S矩阵,因为U矩阵的行和列已经排列妥当,以使最重要的主题(具有最大的奇异值)都在左边,可以忽略S矩阵的另一个原因是:将在此模型中使用的大部分词-文档向量(如TF-IDF向量),都已经进行了归一化处理。最后,如果这样设置的话,它只会生成更好的主题模型。

因此,我们开始砍掉U右边的列。度量LSA精确率的一种方法是看从主题-文档矩阵重构词项-文档矩阵的精确率如何。下面代码演示了SVD的9词项11文档矩阵的重构精确率:

python 复制代码
err=[]
for numdim in range(len(s),0,-1):
    S[numdim-1,numdim-1]=0
    reconstructed_tdm=U.dot(S).Dot(Vt)
    err.append(np.sqrt(((reconstructed_tdm-tdm).values.flatten()**2).sum()/np.product(tdm.shape)))
print(np.array(err).round(2))

当使用奇异向量为11篇文档重构词项-文档矩阵时,截断的内容越多,误差就越大。

下图展示了随着主题模型丢弃的维度越来越多,精确率不断下降的情况:

无论在模型中使用TF-IDF向量还是词袋向量,精确率下降的趋势都非常相似。但是,如果计划在模型中只保留几个主题的话,使用TF-IDF向量的效果会稍好一些。

在某些情况下,在去掉了词项-文档矩阵中的几个维度之后,可能会获得完美的准确率。

LSA背后的SVD算法会"注意"到某些词总在一起使用,并将它们放在一个主题中。这就是它可以"无偿"获得几个维度的原因。即使不打算在流水线中使用主题模型,LSA(SVD)也可以是为流水线压缩词-文档矩阵已经识别潜在复合词或n-gram的一种好方法。

相关推荐
Jaly_W8 分钟前
用于航空发动机故障诊断的深度分层排序网络
人工智能·深度学习·故障诊断·航空发动机
CodeClimb10 分钟前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
小嗷犬10 分钟前
【论文笔记】Cross-lingual few-shot sign language recognition
论文阅读·人工智能·多模态·少样本·手语翻译
夜幕龙17 分钟前
iDP3复现代码数据预处理全流程(二)——vis_dataset.py
人工智能·python·机器人
CT随20 分钟前
Redis内存碎片详解
java·开发语言
anlog29 分钟前
C#在自定义事件里传递数据
开发语言·c#·自定义事件
吃个糖糖34 分钟前
36 Opencv SURF 关键点检测
人工智能·opencv·计算机视觉
奶香臭豆腐42 分钟前
C++ —— 模板类具体化
开发语言·c++·学习
AI慧聚堂1 小时前
自动化 + 人工智能:投标行业的未来是什么样的?
运维·人工智能·自动化
盛世隐者1 小时前
【pytorch】循环神经网络
人工智能·pytorch