在scikit-learn中从截断SVD获取U、Sigma和V*矩阵

38

我正在使用scikit-learn包中的截断SVD。

在SVD定义中,原始矩阵A可以近似表示为一个乘积AUΣV*,其中UV具有正交列,而Σ是非负对角线矩阵。

我需要获取UΣV*矩阵。

查看这里的源代码后,我发现在调用fit_transform后,V*存储在self.components_字段中。

是否可能获得UΣ矩阵?

我的代码:

import sklearn.decomposition as skd
import numpy as np

matrix = np.random.random((20,20))
trsvd = skd.TruncatedSVD(n_components=15)
transformed = trsvd.fit_transform(matrix)
VT = trsvd.components_
7个回答

61

看了你提供的链接,TruncatedSVD本质上是围绕着sklearn.utils.extmath.randomized_svd构建的包装器;你可以像下面这样手动调用它:

from sklearn.utils.extmath import randomized_svd

U, Sigma, VT = randomized_svd(X, 
                              n_components=15,
                              n_iter=5,
                              random_state=None)

11

可以使用scipy.sparse.svds(对于密集矩阵,可以使用svd )。

import numpy as np
from scipy.sparse.linalg import svds

matrix = np.random.random((20, 20))
num_components = 2
u, s, v = svds(matrix, k=num_components)
X = u.dot(np.diag(s))  # output of TruncatedSVD

如果你正在处理非常大的稀疏矩阵(比如自然文本),甚至使用 scipy.sparse.svds 也可能会使您的计算机内存溢出。在这种情况下,考虑使用 sparsesvd 包,它使用 SVDLIBC,以及 gensim底层所使用的

import numpy as np
from sparsesvd import sparsesvd


X = np.random.random((30, 30))
ut, s, vt = sparsesvd(X.tocsc(), k)
projected = (X * ut.T)/s

2
这是正确的,但对于常规的numpy.linalg.svd方法,您无法将组件数量作为参数传递,因此必须自己提取前K个。这只是一个小不便。 - Felipe
X = u.dot(np.diag(s))。由于缺少“v”,这将不会重新创建X。 - Regi Mathew

9

作为一则说明:

svd.transform(X)

并且

svd.fit_transform(X)

生成 U * Sigma
svd.singular_values_

生成以向量形式表示的Sigma。
svd.components_

生成VT。也许我们可以使用。
svd.transform(X).dot(np.linalg.inv(np.diag(svd.singular_values_)))

获取 U 的原因是 U * Sigma * Sigma ^ -1 = U * I = U


8

从源代码中,我们可以看到X_transformed是由U * Sigma(这里Sigma是一个向量)返回的fit_transform方法。因此,我们可以得到

svd = TruncatedSVD(k)
X_transformed = svd.fit_transform(X)

U = X_transformed / svd.singular_values_
Sigma_matrix = np.diag(svd.singular_values_)
VT = svd.components_

注意

截断SVD是一种近似方法。X ≈ X' = UΣV*。我们有X'V = UΣ。但是XV怎么办?有一个有趣的事实是XV = X'V。通过比较X的完整SVD形式和X'的截断SVD形式可以证明这一点。请注意,XV就是transform(X),因此我们也可以通过transform(X)获取U

U = svd.transform(X) / svd.singular_values_

0
如果您的矩阵不是很大,由于numpy通过按顺序排序奇异值来计算SVD,因此可以直接使用np.linalg.svd进行计算,只需从Σ中取前k个奇异值,从U的前k列和Vh的前k行即可。(如果您的某个维度非常大,请使用full_matrices=False以获取薄SVD。)
m = np.random.random((5,5))
u, s, vh = np.linalg.svd(m)
u2, s2, vh2 = u[:,:2], s[:2], vh[:2,:]
m2 = u2 @ np.diag(s2) @ vh2  # rank-2 approx

如果您的矩阵很大,那么sklearn.decomposition.TruncatedSVD提供的随机算法将更有效地计算截断SVD。

-2

我知道这是一个比较旧的问题,但正确的版本应该是-

U = svd.fit_transform(X)
Sigma = svd.singular_values_
VT = svd.components_

然而,需要记住的一件事是U和VT被截断了,因此如果没有剩余值,就无法重新创建X。

3
U 绝对不是 svd.fit_transform(X)。这是错误的。 - DukeLover

-5

5
我认为这个答案是不正确的:SVD.fit_transform(X) = U*np.diag(Sigma) != USVD.explained_variance_ratio_ = np.var(X_transformed, axis=0) / np.var(X, axis=0).sum() != Sigma - rth
这个答案是不正确的,正如rth所提到的那样。 - JRun

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