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

Get U, Sigma, V* matrix from Truncated SVD in scikit-learn

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

在SVD的定义中,原始矩阵A近似为乘积AUΣV* 其中 UV 具有正交列,并且 Σ 是非负对角线。

我需要得到 UΣV* 矩阵。

查看源码here发现调用fit_transformV*存储在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_

可以使用 scipy.sparse.svds (for dense matrices you can use 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 package which uses SVDLIBC, and what gensim uses under-the-hood.

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

通过您提供的 link 查看源代码,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)

让我们假设 X 是我们希望在其上执行截断 SVD 的输入矩阵。 下面的命令有助于找出 U、Sigma 和 VT:

    from sklearn.decomposition import TruncatedSVD

    SVD = TruncatedSVD(n_components=r) 
    U = SVD.fit_transform(X)
    Sigma = SVD.explained_variance_ratio_
    VT = SVD.components_
    #r corresponds to the rank of the matrix

以上条款的理解,请参考http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.TruncatedSVD.html

如注:

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.

从源码中可以看出返回的是X_transformed也就是U * Sigma(这里Sigma是一个vector) 来自 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 = X'V。这可以通过比较 X 的完整 SVD 形式和 X' 的截断 SVD 形式来证明。注意 XV 就是 transform(X),所以我们也可以通过

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

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

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

但是,要记住的一件事是 U 和 VT 被截断,因此没有其余值就不可能重新创建 X。

如果您的矩阵不大,因为 numpy 通过按顺序对奇异值进行排序来计算 SVD,这可以直接使用 np.linalg.svd 计算,只需从 Σ 中获取前 k 个奇异值,即 U 的前 k 列,以及前 k 行的 Vh。 (如果您的维度之一很大,请使用 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。