Exemple #1
0
        /// <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);
        }
Exemple #2
0
        /// <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);
        }