/// <summary> /// Performs a principal component analysis of the data. /// </summary> /// <returns>The result of the principal component analysis.</returns> /// <exception cref="InsufficientDataException">The number of data entries (<see cref="Count"/>) is /// less than the number of variables (<see cref="Dimension"/>).</exception> /// <seealso cref="PrincipalComponentAnalysis"/> public PrincipalComponentAnalysis PrincipalComponentAnalysis() { if (Count < Dimension) { throw new InsufficientDataException(); } // construct a (Count X Dimension) matrix of mean-centered data double[] store = MatrixAlgorithms.AllocateStorage(Count, Dimension); int i = 0; for (int c = 0; c < Dimension; c++) { double mu = storage[c].Mean; for (int r = 0; r < Count; r++) { store[i] = storage[c][r] - mu; i++; } } // bidiagonalize it double[] a, b; MatrixAlgorithms.Bidiagonalize(store, Count, Dimension, out a, out b); // form the U and V matrices double[] left = MatrixAlgorithms.AccumulateBidiagonalU(store, Count, Dimension); double[] right = MatrixAlgorithms.AccumulateBidiagonalV(store, Count, Dimension); // find the singular values of the bidiagonal matrix MatrixAlgorithms.ExtractSingularValues(a, b, left, right, Count, Dimension); // sort them MatrixAlgorithms.SortValues(a, left, right, Count, Dimension); PrincipalComponentAnalysis pca = new PrincipalComponentAnalysis(left, a, right, Count, Dimension); return(pca); }
/// <summary> /// Performs a principal component analysis of the multivariate sample. /// </summary> /// <returns>The result of the principal component analysis.</returns> /// <param name="columns">The set of columns to analyze.</param> /// <exception cref="ArgumentNullException"><paramref name="columns"/> or one of its members is <see langword="null"/>.</exception> /// <exception cref="DimensionMismatchException">The columns do not all have the same number of entries.</exception> /// <exception cref="InsufficientDataException">The number of entries is less than the number of columns.</exception> /// <remarks> /// <para>For background on principal component analysis, see the remarks at <see cref="Meta.Numerics.Statistics.PrincipalComponentAnalysis"/>.</para> /// <para>Note that the <paramref name="columns"/> argument is column-oriented, i.e. it is a list of columns, /// not row-oriented, i.e. a list of rows. Either of these would match the method signature, but only /// column-oriented inputs will produce correct results.</para> /// </remarks> /// <exception cref="ArgumentNullException"><paramref name="columns"/>, or one of the columns in it, is <see langword="null"/>.</exception> /// <exception cref="DimensionMismatchException">Not all of the columns in <paramref name="columns"/> have the same length.</exception> /// <exception cref="InsufficientDataException">There are fewer rows than columns.</exception> /// <seealso href="https://en.wikipedia.org/wiki/Principal_component_analysis"/> public static PrincipalComponentAnalysis PrincipalComponentAnalysis(this IReadOnlyList <IReadOnlyList <double> > columns) { if (columns == null) { throw new ArgumentNullException(nameof(columns)); } int dimension = columns.Count; int count = -1; for (int c = 0; c < dimension; c++) { IReadOnlyList <double> column = columns[c]; if (column == null) { throw new ArgumentNullException(nameof(columns)); } if (count < 0) { count = column.Count; } else { if (column.Count != count) { throw new DimensionMismatchException(); } } } if (count < dimension) { throw new InsufficientDataException(); } // construct a (Count X Dimension) matrix of mean-centered data double[] store = MatrixAlgorithms.AllocateStorage(count, dimension); int i = 0; for (int c = 0; c < dimension; c++) { IReadOnlyList <double> column = columns[c]; double mu = column.Mean(); for (int r = 0; r < count; r++) { store[i] = column[r] - mu; i++; } } // bidiagonalize it double[] a, b; MatrixAlgorithms.Bidiagonalize(store, count, dimension, out a, out b); // form the U and V matrices double[] left = MatrixAlgorithms.AccumulateBidiagonalU(store, count, dimension); double[] right = MatrixAlgorithms.AccumulateBidiagonalV(store, count, dimension); // find the singular values of the bidiagonal matrix MatrixAlgorithms.ExtractSingularValues(a, b, left, right, count, dimension); // sort them MatrixAlgorithms.SortValues(a, left, right, count, dimension); PrincipalComponentAnalysis pca = new PrincipalComponentAnalysis(left, a, right, count, dimension); return(pca); }