2016-01-12 1 views
3

SVD est l'abréviation de Singular Value Decomposition (Décomposition de la valeur singulière). Il est dit être la technique populaire pour effectuer la réduction des caractéristiques dans la classification des textes. Je connais le principe comme this link.Comment utiliser SVD correctement dans Accord.net

J'ai utilisé C#, en utilisant la bibliothèque Accord.Net et j'avais un tableau dentelé double[][] de calculer TF-IDF déjà.

Je sais déjà qu'il y a 4 sujets dans mes documents. Je veux tester la méthode Kmean avec le nombre de clusters k = 4. Avant d'utiliser Kmean, je veux utiliser SVD pour effectuer la réduction des fonctionnalités. Lorsque les résultats apparaissent, près de 90% des documents sont groupés en un groupe, d'autres sont regroupés en trois autres groupes. C'est un très mauvais résultat. J'ai essayé de relancer un certain nombre de fois mais les résultats ne changent pas beaucoup. Si j'utilise PCA au lieu de SDV, tout s'est bien passé comme prévu.

Donc, où je me trompe. Toute personne qui sait cela peut me guider un exemple de code. Merci beaucoup.


Note: mon original TF-IDF a des lignes représentant les documents, colonne représentant termes

Voici mon code:

 //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); 

Après cela, nous faisons quelques pas de savoir quels documents Appartient à quels groupes selon les étiquettes.

Répondre

2

La PCA dans Accord.NET est déjà calculée en utilisant le SVD. Pour un exemple sur la façon d'effectuer SVD manuellement, sans l'aide de la classe PCA, vous pouvez toujours regarder le PrincipalComponentAnalysis.cs source code.

La première étape consiste à soustraire la moyenne de vos données (stockées dans la variable x):

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

Maintenant, vous pouvez éventuellement diviser vos données par leurs écarts-types, transformant effectivelly vos données z-scores . Cette étape est strictement facultative, mais pourrait avoir du sens lorsque vos données représentent des variables collectées en unités d'ordres de grandeur très variables (c'est-à-dire qu'une colonne représente les hauteurs en kilomètres, l'autre en centimètres). Maintenant, les composants principaux de 'x' sont les vecteurs propres de Cov (x). Ainsi, si nous calculons le SVD de 'z' (qui est x standardisé), les colonnes de la matrice V (côté droit de SVD) seront les composantes principales de x. Avec cela, ce que nous devons faire maintenant est d'effectuer la décomposition en valeurs singulières (SVD) de la matrice z:

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(); 

Si vous souhaitez effectuer le blanchiment, vous pouvez également diviser vos vecteurs par les valeurs singulières:

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

maintenant, si vous souhaitez projeter vos données jusqu'à 90% de la variance, calculer la somme cumulée des valeurs propres similaire comme vous avez fait:

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

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

maintenant, détermi e le nombre de dimensions dont vous avez besoin en regardant où les proportions cumulatives deviennent plus grandes que la proportion de la variance que vous voulez.Une fois que vous connaissez ce numéro, sélectionnez uniquement les vecteurs propres de la matrice des vecteurs propres:

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]; 

Dans l'exemple ci-dessus je transformais la matrice z, qui était déjà moyenne centrée et éventuellement standardisée. N'oubliez pas d'appliquer les mêmes transformations que vous avez appliquées à la matrice d'origine avant de transformer un autre ensemble de données. Enfin, s'il vous plaît gardez à l'esprit que tout ce qui précède manuellement est complètement facultatif. Vous devriez vraiment utiliser la classe PrincipalComponentAnalysis pour faire tout ce gros effort pour vous, gratuitement!