繁体   English   中英

如何在Accord.net中正确使用SVD

[英]How to use SVD correctly in Accord.net

SVD代表奇异值分解,据说是在文本分类中进行特征减少的流行技术。 我知道这个链接的原理。

我一直在使用C#,使用Accord.Net库并且已经计算出TF-IDF的锯齿数组double[][]

我已经知道我的文档中有4个主题。 我想用簇数k = 4来测试Kmean方法。在使用Kmean之前,我想使用SVD进行特征缩减。 当结果显示时,将近90%的文档分组为1组,其他文档分组为3个其他群集。 这是一个非常糟糕的结果。 我试过多次重新运行,但结果没有太大变化。 如果我使用PCA而不是SDV,一切都按预期完成。

所以,我错了。 知道这一点的任何人都可以为我提供示例代码 非常感谢。


注意:我原来的TF-IDF有代表文档的行,代表术语的列

这是我的代码:

        //to matrix because the function SVD requiring input of matrix, not jagged array
        //transpose because the TF-IDF used for SVD has rows representing terms, columns representing documents; 
        var svd = new SingularValueDecomposition(tfidf.ToMatrix().Transpose());
        double[,] U = svd.LeftSingularVectors;
        double[,] S = svd.DiagonalMatrix;
        double[,] V = svd.RightSingularVectors;

        //find the optimal cutoff y so that we retain enough singular values to make up 90% of the energy in S
        //http://infolab.stanford.edu/~ullman/mmds/ch11.pdf, page 18-20
        double energy = 0;
        for (int i = 0; i < S.GetLength(0); i++)
        {
            energy += Math.Pow(S[i, i], 2);
        }

        double percent;
        int y = S.GetLength(0);
        do
        {
            y--;
            double test = 0;
            for (int i = 0; i < y; i++)
            {
                test += Math.Pow(S[i, i], 2);
            }

            percent = test / energy;
        } while (percent >= 0.9);
        y = y + 1;

        //Uk gets all rows, y first columns of U; Sk get y first rows, y first columns of S; Vk get y first rows, all columns of V
        double[,] Uk = U.Submatrix(0, U.GetLength(0) - 1, 0, y - 1);
        double[,] Sk = S.Submatrix(0, y - 1, 0, y - 1);
        double[,] Vk = V.Submatrix(0, y - 1, 0, V.GetLength(1) - 1);

        //reduce dimension according to http://stats.stackexchange.com/questions/107533/how-to-use-svd-for-dimensionality-reduction-to-reduce-the-number-of-columns-fea
        //we tranpose again to have the rows being document, columns being term as original TF-IDF
        //ToArray because the Kmean below acquiring input of jagged array
        tfidf = Uk.Multiply(Sk).Transpose().ToArray();
        // if tfidf = Uk.Multiply(Sk).Multiply(Vk).Transpose().ToArray()
        // result still bad

        // Create a K-Means algorithm using given k and a square Euclidean distance as distance metric.
        var kmeans = new KMeans(4, Distance.SquareEuclidean) { Tolerance = 0.05 };
        int[] labels = kmeans.Compute(tfidf);

之后,我们会根据标签了解哪些文档属于哪些组。

Accord.NET中的PCA已经使用SVD计算。 有关如何在没有PCA类帮助的情况下手动执行SVD的示例,您始终可以查看PrincipalComponentAnalysis.cs源代码

第一步是减去数据的平均值(存储在变量x ):

 int NumberOfInputs = x.Columns();
 this.Means = x.Mean(dimension: 0);
 z = x.Subtract(Means, dimension: 0);

现在,您可以选择按标准偏差划分数据,有效地将数据转换为z分数。 此步骤是严格可选的,但是当您的数据表示以不同数量级的单位收集的变量时(即一列代表以公里为单位的高度,另一列以厘米为单位),这可能是有意义的。

this.StandardDeviations = x.StandardDeviation(Means);
z = z.Divide(StandardDeviations, dimension: 0);

现在,'x'的主要成分是Cov(x)的特征向量。 因此,如果我们计算'z'的SVD(x标准化),矩阵V的列(SVD的右侧)将是x的主要分量。 有了这个,我们现在要做的是执行矩阵z的奇异值分解(SVD):

var svd = new JaggedSingularValueDecomposition(matrix,
    computeLeftSingularVectors: false,
    computeRightSingularVectors: true,
    autoTranspose: true);

var singularValues = svd.Diagonal;
var eigenvalues = SingularValues.Pow(2);
var eigenvalues.Divide(x.Rows() - 1);
var componentVectors = svd.RightSingularVectors.Transpose();

如果您想要执行白化,您还可以将矢量除以奇异值:

componentVectors = componentVectors.Divide(singularValues, dimension: 1);

现在,如果您想将数据投影到高达90%的方差,请计算与您所做的类似的eigenValues的累积总和:

// Calculate proportions
var componentProportions = eigenvalues.Abs().Divide(eigenValues.Abs().Sum());

// Calculate cumulative proportions
var componentCumulative = componentProportions.CumulativeSum();

现在,通过查看累积比例大于所需方差的比例来确定所需的维数。 知道这个数字后,只从特征向量矩阵中选择那些特征向量:

int numberOfVectors = // number of vectors that you need

for (int i = 0; i < rows; i++)
    for (int j = 0; j < numberOfVectors; j++)
        for (int k = 0; k < componentVectors[j].Length; k++)
            result[i][j] += z[i][k] * componentVectors[j][k];

在上面的例子中,我正在转换矩阵z,它已经意味着居中并且可选地标准化。 在转换另一组数据之前,不要忘记应用与原始矩阵相同的转换。

最后,请记住,手动完成上述所有操作都是完全可选的。 您应该真正使用PrincipalComponentAnalysis类为您完成所有这些繁重的工作!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM