在潜在语义分析中,当截断奇异值后,你如何重新组合分解的矩阵?

7

我正在阅读《矩阵分解和潜在语义索引》(在线版 © 2009 Cambridge UP)Matrix decompositions and latent semantic indexing

我试图理解如何降低矩阵的维数。第13页上有一个例子,我正尝试使用Python's numpy重现它。

让我们将原始出现矩阵称为“a”,将三个SVD(奇异值分解)分解后的矩阵称为“U”、“S”和“V”。

问题在于,当我将“S”中较小的奇异值清零后,在使用numpy相乘“U”、“S”和“V”时,答案与pdf中给出的不同。底部3行并非全为0。有趣的是,当我只乘以“S”和“V”时,得到的答案是正确的。

这有点出人意料,但是曼宁和舒茨的书《统计自然语言处理基础》指出,将 "S" 和 "V" 相乘实际上是必须要做的。但是这并不是pdf文档第10页所说的。那么这里到底发生了什么?

减少维度是一个常见的应用数学问题,如果您能用简单的英语得到答案,那么您可能会在数学或编程网站上获得更好的答案。我个人无法理解矩阵。 - hippietrail
1
@hippietrail 在看了Russell的链接之后,我猜测截断SVD是一种数学运算,因此它应该与数学堆栈交换相关。 - mtanti
1
这个问题似乎不适合讨论,因为它是关于 NLP 的附属数学问题。它应该被移动到数学或编程 SE 网站之一。我已经投票关闭了,但我不确定哪个网站最适合迁移它。 - hippietrail
1
@mtanti:如果不是矩阵乘法/分解问题,那么听起来像是一个调试问题。在SO上,我看到了一些关于不同工具给出SVD不同结果的其他问题。不幸的是,尽管我曾经是一名专业程序员,现在是一名业余语言学家,但我无法理解那个PDF文件 -: 我只是想为您提供最好的答案,无论它是否与此处的主题相关 (-: - hippietrail
1
我对此没有任何问题 @hippietrail - mtanti
显示剩余11条评论
1个回答

4

SV相乘,就是使用SVD/LSA执行降维所必须做的操作。

>>> C = np.array([[1, 0, 1, 0, 0, 0],
...               [0, 1, 0, 0, 0, 0],
...               [1, 1, 0, 0, 0, 0],
...               [1, 0, 0, 1, 1, 0],
...               [0, 0, 0, 1, 0, 1]])
>>> from scipy.linalg import svd
>>> U, s, VT = svd(C, full_matrices=False)
>>> s[2:] = 0
>>> np.dot(np.diag(s), VT)
array([[ 1.61889806,  0.60487661,  0.44034748,  0.96569316,  0.70302032,
         0.26267284],
       [-0.45671719, -0.84256593, -0.29617436,  0.99731918,  0.35057241,
         0.64674677],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ]])

这将得到一个矩阵,其中除了最后几行以外都是零,因此它们可以被删除,在实际应用中,这就是您要使用的矩阵:
>>> np.dot(np.diag(s[:2]), VT[:2])
array([[ 1.61889806,  0.60487661,  0.44034748,  0.96569316,  0.70302032,
         0.26267284],
       [-0.45671719, -0.84256593, -0.29617436,  0.99731918,  0.35057241,
         0.64674677]])

第10页上PDF所描述的是获取输入C的低秩重建配方。 !=维数,重建矩阵的巨大尺寸和密度使其在LSA中不实用;它的主要目的是数学上的。您可以使用它来检查各个k值的重构效果如何:

>>> U, s, VT = svd(C, full_matrices=False)
>>> C2 = np.dot(U[:, :2], np.dot(np.diag(s[:2]), VT[:2]))
>>> from scipy.spatial.distance import euclidean
>>> euclidean(C2.ravel(), C.ravel())   # Frobenius norm of C2 - C
1.6677932876555255
>>> C3 = np.dot(U[:, :3], np.dot(np.diag(s[:3]), VT[:3]))
>>> euclidean(C3.ravel(), C.ravel())
1.0747879905228703

对scikit-learn的TruncatedSVD进行健全性检查(全面披露:本人撰写了该程序):

>>> from sklearn.decomposition import TruncatedSVD
>>> TruncatedSVD(n_components=2).fit_transform(C.T)
array([[ 1.61889806, -0.45671719],
       [ 0.60487661, -0.84256593],
       [ 0.44034748, -0.29617436],
       [ 0.96569316,  0.99731918],
       [ 0.70302032,  0.35057241],
       [ 0.26267284,  0.64674677]])

@mtanti:是哪一个,UΣVᵀ? - Fred Foo
他们找到C2的那一部分以及底部行都是零。那不是UΣVᵀ而是ΣVᵀ,对吗?PDF文件中有错误,对吗? - mtanti
1
@mtanti:18.4例子,对吧?是的,那似乎是一个错误。他们计算的不是C₂,低秩重构,而是压缩矩阵Σ₂Vᵀ。真正的重构没有这些零行。 - Fred Foo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接