Пример #1
0
        public static void Predict(
            IROMatrix <double> XU,             // unknown spectrum or spectra,  horizontal oriented
            IROMatrix <double> xLoads,         // x-loads matrix
            IROMatrix <double> yLoads,         // y-loads matrix
            IROMatrix <double> W,              // weighting matrix
            IROMatrix <double> V,              // Cross product vector
            int numFactors,                    // number of factors to use for prediction
            IMatrix <double> predictedY,       // Matrix of predicted y-values, must be same number of rows as spectra
            IMatrix <double> spectralResiduals // Matrix of spectral residuals, n rows x 1 column, can be zero
            )
        {
            // now predicting a "unkown" spectra
            var si = new MatrixMath.ScalarAsMatrix <double>(0);
            var Cu = new MatrixMath.MatrixWithOneRow <double>(yLoads.ColumnCount);

            var wi    = new MatrixMath.MatrixWithOneRow <double>(XU.ColumnCount);
            var cuadd = new MatrixMath.MatrixWithOneRow <double>(yLoads.ColumnCount);

            // xu holds a single spectrum extracted out of XU
            var xu = new MatrixMath.MatrixWithOneRow <double>(XU.ColumnCount);

            // xl holds temporarily a row of the xLoads matrix+
            var xl = new MatrixMath.MatrixWithOneRow <double>(xLoads.ColumnCount);

            int maxFactors = Math.Min(yLoads.RowCount, numFactors);

            for (int nSpectrum = 0; nSpectrum < XU.RowCount; nSpectrum++)
            {
                MatrixMath.Submatrix(XU, xu, nSpectrum, 0); // extract one spectrum to predict
                MatrixMath.ZeroMatrix(Cu);                  // Set Cu=0
                for (int i = 0; i < maxFactors; i++)
                {
                    //1. Calculate the unknown spectral score for a weighting vector
                    MatrixMath.Submatrix(W, wi, i, 0);
                    MatrixMath.MultiplySecondTransposed(wi, xu, si);
                    // take the y loading vector
                    MatrixMath.Submatrix(yLoads, cuadd, i, 0);
                    // and multiply it with the cross product and the score
                    MatrixMath.MultiplyScalar(cuadd, si * V[0, i], cuadd);
                    // Add it to the predicted y-values
                    MatrixMath.Add(Cu, cuadd, Cu);
                    // remove the spectral contribution of the factor from the spectrum
                    // TODO this is quite ineffective: in every loop we extract the xl vector, we have to find a shortcut for this!
                    MatrixMath.Submatrix(xLoads, xl, i, 0);
                    MatrixMath.SubtractProductFromSelf(xl, (double)si, xu);
                }
                // xu now contains the spectral residual,
                // Cu now contains the predicted y values
                if (null != predictedY)
                {
                    MatrixMath.SetRow(Cu, 0, predictedY, nSpectrum);
                }

                if (null != spectralResiduals)
                {
                    spectralResiduals[nSpectrum, 0] = MatrixMath.SumOfSquares(xu);
                }
            } // for each spectrum in XU
        }     // end partial-least-squares-predict
Пример #2
0
        /// <summary>
        /// Partial least squares (PLS) decomposition of the matrizes X and Y.
        /// </summary>
        /// <param name="_X">The X ("spectrum") matrix, centered and preprocessed.</param>
        /// <param name="_Y">The Y ("concentration") matrix (centered).</param>
        /// <param name="numFactors">Number of factors to calculate.</param>
        /// <param name="xLoads">Returns the matrix of eigenvectors of X. Should be initially empty.</param>
        /// <param name="yLoads">Returns the matrix of eigenvectors of Y. Should be initially empty. </param>
        /// <param name="W">Returns the matrix of weighting values. Should be initially empty.</param>
        /// <param name="V">Returns the vector of cross products. Should be initially empty.</param>
        /// <param name="PRESS">If not null, the PRESS value of each factor is stored (vertically) here. </param>
        public static void ExecuteAnalysis(
            IROMatrix <double> _X,                   // matrix of spectra (a spectra is a row of this matrix)
            IROMatrix <double> _Y,                   // matrix of concentrations (a mixture is a row of this matrix)
            ref int numFactors,
            IBottomExtensibleMatrix <double> xLoads, // out: the loads of the X matrix
            IBottomExtensibleMatrix <double> yLoads, // out: the loads of the Y matrix
            IBottomExtensibleMatrix <double> W,      // matrix of weighting values
            IRightExtensibleMatrix <double> V,       // matrix of cross products
            IExtensibleVector <double> PRESS         //vector of Y PRESS values
            )
        {
            // used variables:
            // n: number of spectra (number of tests, number of experiments)
            // p: number of slots (frequencies, ..) in each spectrum
            // m: number of constitutents (number of y values in each measurement)

            // X : n-p matrix of spectra (each spectra is a horizontal row)
            // Y : n-m matrix of concentrations

            const int    maxIterations = 1500;  // max number of iterations in one factorization step
            const double accuracy      = 1E-12; // accuracy that should be reached between subsequent calculations of the u-vector

            // use the mean spectrum as first row of the W matrix
            var mean = new MatrixMath.MatrixWithOneRow <double>(_X.ColumnCount);
            //  MatrixMath.ColumnsToZeroMean(X,mean);
            //W.AppendBottom(mean);

            var X = new MatrixMath.LeftSpineJaggedArrayMatrix <double>(_X.RowCount, _X.ColumnCount);

            MatrixMath.Copy(_X, X);
            var Y = new MatrixMath.LeftSpineJaggedArrayMatrix <double>(_Y.RowCount, _Y.ColumnCount);

            MatrixMath.Copy(_Y, Y);

            IMatrix <double> u_prev = null;
            var w = new MatrixMath.MatrixWithOneRow <double>(X.ColumnCount); // horizontal vector of X (spectral) weighting
            var t = new MatrixMath.MatrixWithOneColumn <double>(X.RowCount); // vertical vector of X  scores
            var u = new MatrixMath.MatrixWithOneColumn <double>(X.RowCount); // vertical vector of Y scores
            var p = new MatrixMath.MatrixWithOneRow <double>(X.ColumnCount); // horizontal vector of X loads
            var q = new MatrixMath.MatrixWithOneRow <double>(Y.ColumnCount); // horizontal vector of Y loads

            int maxFactors = Math.Min(X.ColumnCount, X.RowCount);

            numFactors = numFactors <= 0 ? maxFactors : Math.Min(numFactors, maxFactors);

            if (PRESS != null)
            {
                PRESS.Append(new MatrixMath.ScalarAsMatrix <double>(MatrixMath.SumOfSquares(Y))); // Press value for not decomposed Y
            }

            for (int nFactor = 0; nFactor < numFactors; nFactor++)
            {
                //Console.WriteLine("Factor_{0}:",nFactor);
                //Console.WriteLine("X:"+X.ToString());
                //Console.WriteLine("Y:"+Y.ToString());

                // 1. Use as start vector for the y score the first column of the
                // y-matrix
                MatrixMath.Submatrix(Y, u); // u is now a vertical vector of concentrations of the first constituents

                for (int iter = 0; iter < maxIterations; iter++)
                {
                    // 2. Calculate the X (spectrum) weighting vector
                    MatrixMath.MultiplyFirstTransposed(u, X, w); // w is a horizontal vector

                    // 3. Normalize w to unit length
                    MatrixMath.NormalizeRows(w); // w now has unit length

                    // 4. Calculate X (spectral) scores
                    MatrixMath.MultiplySecondTransposed(X, w, t); // t is a vertical vector of n numbers

                    // 5. Calculate the Y (concentration) loading vector
                    MatrixMath.MultiplyFirstTransposed(t, Y, q); // q is a horizontal vector of m (number of constitutents)

                    // 5.1 Normalize q to unit length
                    MatrixMath.NormalizeRows(q);

                    // 6. Calculate the Y (concentration) score vector u
                    MatrixMath.MultiplySecondTransposed(Y, q, u); // u is a vertical vector of n numbers

                    // 6.1 Compare
                    // Compare this with the previous one
                    if (u_prev != null && MatrixMath.IsEqual(u_prev, u, accuracy))
                    {
                        break;
                    }
                    if (u_prev == null)
                    {
                        u_prev = new MatrixMath.MatrixWithOneColumn <double>(X.RowCount);
                    }
                    MatrixMath.Copy(u, u_prev); // stores the content of u in u_prev
                } // for all iterations

                // Store the scores of X
                //factors.AppendRight(t);

                // 7. Calculate the inner scalar (cross product)
                double length_of_t = MatrixMath.LengthOf(t);
                var    v           = new MatrixMath.ScalarAsMatrix <double>(0);
                MatrixMath.MultiplyFirstTransposed(u, t, (IVector <double>)v);
                if (length_of_t != 0)
                {
                    v = v / MatrixMath.Square(length_of_t);
                }

                // 8. Calculate the new loads for the X (spectral) matrix
                MatrixMath.MultiplyFirstTransposed(t, X, p); // p is a horizontal vector of loads
                                                             // Normalize p by the spectral scores

                if (length_of_t != 0)
                {
                    MatrixMath.MultiplyScalar(p, 1 / MatrixMath.Square(length_of_t), p);
                }

                // 9. Calculate the new residua for the X (spectral) and Y (concentration) matrix
                //MatrixMath.MultiplyScalar(t,length_of_t*v,t); // original t times the cross product

                MatrixMath.SubtractProductFromSelf(t, p, X);

                MatrixMath.MultiplyScalar(t, v, t);          // original t times the cross product
                MatrixMath.SubtractProductFromSelf(t, q, Y); // to calculate residual Y

                // Store the loads of X and Y in the output result matrix
                xLoads.AppendBottom(p);
                yLoads.AppendBottom(q);
                W.AppendBottom(w);
                V.AppendRight(v);

                if (PRESS != null)
                {
                    double pressValue = MatrixMath.SumOfSquares(Y);
                    PRESS.Append(new MatrixMath.ScalarAsMatrix <double>(pressValue));
                }
                // Calculate SEPcv. If SEPcv is greater than for the actual number of factors,
                // break since the optimal number of factors was found. If not, repeat the calculations
                // with the residual matrizes for the next factor.
            } // for all factors
        }