/// <summary> /// Creates an analyis from preprocessed spectra and preprocessed concentrations. /// </summary> /// <param name="matrixX">The spectral matrix (each spectrum is a row in the matrix). They must at least be centered.</param> /// <param name="matrixY">The matrix of concentrations (each experiment is a row in the matrix). They must at least be centered.</param> /// <param name="maxFactors">Maximum number of factors for analysis.</param> /// <returns>A regression object, which holds all the loads and weights neccessary for further calculations.</returns> protected override void AnalyzeFromPreprocessedWithoutReset(IROMatrix matrixX, IROMatrix matrixY, int maxFactors) { int numberOfFactors = _calib.NumberOfFactors = Math.Min(matrixX.Columns, maxFactors); MatrixMath.BEMatrix _xLoads = new MatrixMath.BEMatrix(0, 0); MatrixMath.BEMatrix _yLoads = new MatrixMath.BEMatrix(0, 0); MatrixMath.BEMatrix _W = new MatrixMath.BEMatrix(0, 0); MatrixMath.REMatrix _V = new MatrixMath.REMatrix(0, 0); _PRESS = VectorMath.CreateExtensibleVector(0); ExecuteAnalysis(matrixX, matrixY, ref numberOfFactors, _xLoads, _yLoads, _W, _V, _PRESS); _calib.NumberOfFactors = Math.Min(_calib.NumberOfFactors, numberOfFactors); _calib.XLoads = _xLoads; _calib.YLoads = _yLoads; _calib.XWeights = _W; _calib.CrossProduct = _V; }
/// <summary> /// Multiplies selected columns to form a matrix. /// </summary> /// <param name="mainDocument"></param> /// <param name="srctable"></param> /// <param name="selectedColumns"></param> /// <returns>Null if successful, else the description of the error.</returns> /// <remarks>The user must select an even number of columns. All columns of the first half of the selection /// must have the same number of rows, and all columns of the second half of selection must also have the same /// number of rows. The first half of selected columns form a matrix of dimensions(firstrowcount,halfselected), and the second half /// of selected columns form a matrix of dimension(halfselected, secondrowcount). The resulting matrix has dimensions (firstrowcount,secondrowcount) and is /// stored in a separate worksheet.</remarks> public static string MultiplyColumnsToMatrix( Altaxo.AltaxoDocument mainDocument, Altaxo.Data.DataTable srctable, IAscendingIntegerCollection selectedColumns ) { // check that there are columns selected if (0 == selectedColumns.Count) { return("You must select at least two columns to multiply!"); } // selected columns must contain an even number of columns if (0 != selectedColumns.Count % 2) { return("You selected an odd number of columns. Please select an even number of columns to multiply!"); } // all selected columns must be numeric columns for (int i = 0; i < selectedColumns.Count; i++) { if (!(srctable[selectedColumns[i]] is Altaxo.Data.INumericColumn)) { return(string.Format("The column[{0}] (name:{1}) is not a numeric column!", selectedColumns[i], srctable[selectedColumns[i]].Name)); } } int halfselect = selectedColumns.Count / 2; // check that all columns from the first half of selected colums contain the same // number of rows int rowsfirsthalf = int.MinValue; for (int i = 0; i < halfselect; i++) { int idx = selectedColumns[i]; if (rowsfirsthalf < 0) { rowsfirsthalf = srctable[idx].Count; } else if (rowsfirsthalf != srctable[idx].Count) { return("The first half of selected columns have not all the same length!"); } } int rowssecondhalf = int.MinValue; for (int i = halfselect; i < selectedColumns.Count; i++) { int idx = selectedColumns[i]; if (rowssecondhalf < 0) { rowssecondhalf = srctable[idx].Count; } else if (rowssecondhalf != srctable[idx].Count) { return("The second half of selected columns have not all the same length!"); } } // now create the matrices to multiply from the MatrixMath.REMatrix firstMat = new MatrixMath.REMatrix(rowsfirsthalf, halfselect); for (int i = 0; i < halfselect; i++) { Altaxo.Data.INumericColumn col = (Altaxo.Data.INumericColumn)srctable[selectedColumns[i]]; for (int j = 0; j < rowsfirsthalf; j++) { firstMat[j, i] = col[j]; } } MatrixMath.BEMatrix secondMat = new MatrixMath.BEMatrix(halfselect, rowssecondhalf); for (int i = 0; i < halfselect; i++) { Altaxo.Data.INumericColumn col = (Altaxo.Data.INumericColumn)srctable[selectedColumns[i + halfselect]]; for (int j = 0; j < rowssecondhalf; j++) { secondMat[i, j] = col[j]; } } // now multiply the two matrices MatrixMath.BEMatrix resultMat = new MatrixMath.BEMatrix(rowsfirsthalf, rowssecondhalf); MatrixMath.Multiply(firstMat, secondMat, resultMat); // and store the result in a new worksheet Altaxo.Data.DataTable table = new Altaxo.Data.DataTable("ResultMatrix of " + srctable.Name); table.Suspend(); // first store the factors for (int i = 0; i < resultMat.Columns; i++) { Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn(); for (int j = 0; j < resultMat.Rows; j++) { col[j] = resultMat[j, i]; } table.DataColumns.Add(col, i.ToString()); } table.Resume(); mainDocument.DataTableCollection.Add(table); // create a new worksheet without any columns Current.ProjectService.CreateNewWorksheet(table); return(null); }
/// <summary> /// Makes a PCA (a principal component analysis) of the table or the selected columns / rows and stores the results in a newly created table. /// </summary> /// <param name="mainDocument">The main document of the application.</param> /// <param name="srctable">The table where the data come from.</param> /// <param name="selectedColumns">The selected columns.</param> /// <param name="selectedRows">The selected rows.</param> /// <param name="bHorizontalOrientedSpectrum">True if a spectrum is a single row, False if a spectrum is a single column.</param> /// <param name="maxNumberOfFactors">The maximum number of factors to calculate.</param> /// <returns></returns> public static string PrincipalComponentAnalysis( Altaxo.AltaxoDocument mainDocument, Altaxo.Data.DataTable srctable, IAscendingIntegerCollection selectedColumns, IAscendingIntegerCollection selectedRows, bool bHorizontalOrientedSpectrum, int maxNumberOfFactors ) { bool bUseSelectedColumns = (null != selectedColumns && 0 != selectedColumns.Count); int prenumcols = bUseSelectedColumns ? selectedColumns.Count : srctable.DataColumns.ColumnCount; // check for the number of numeric columns int numcols = 0; for (int i = 0; i < prenumcols; i++) { int idx = bUseSelectedColumns ? selectedColumns[i] : i; if (srctable[i] is Altaxo.Data.INumericColumn) { numcols++; } } // check the number of rows bool bUseSelectedRows = (null != selectedRows && 0 != selectedRows.Count); int numrows; if (bUseSelectedRows) { numrows = selectedRows.Count; } else { numrows = 0; for (int i = 0; i < numcols; i++) { int idx = bUseSelectedColumns ? selectedColumns[i] : i; numrows = Math.Max(numrows, srctable[idx].Count); } } // check that both dimensions are at least 2 - otherwise PCA is not possible if (numrows < 2) { return("At least two rows are neccessary to do Principal Component Analysis!"); } if (numcols < 2) { return("At least two numeric columns are neccessary to do Principal Component Analysis!"); } // Create a matrix of appropriate dimensions and fill it MatrixMath.BEMatrix matrixX; if (bHorizontalOrientedSpectrum) { matrixX = new MatrixMath.BEMatrix(numrows, numcols); int ccol = 0; // current column in the matrix for (int i = 0; i < prenumcols; i++) { int colidx = bUseSelectedColumns ? selectedColumns[i] : i; Altaxo.Data.INumericColumn col = srctable[colidx] as Altaxo.Data.INumericColumn; if (null != col) { for (int j = 0; j < numrows; j++) { int rowidx = bUseSelectedRows ? selectedRows[j] : j; matrixX[j, ccol] = col[rowidx]; } ++ccol; } } } // end if it was a horizontal oriented spectrum else // if it is a vertical oriented spectrum { matrixX = new MatrixMath.BEMatrix(numcols, numrows); int ccol = 0; // current column in the matrix for (int i = 0; i < prenumcols; i++) { int colidx = bUseSelectedColumns ? selectedColumns[i] : i; Altaxo.Data.INumericColumn col = srctable[colidx] as Altaxo.Data.INumericColumn; if (null != col) { for (int j = 0; j < numrows; j++) { int rowidx = bUseSelectedRows ? selectedRows[j] : j; matrixX[ccol, j] = col[rowidx]; } ++ccol; } } } // if it was a vertical oriented spectrum // now do PCA with the matrix MatrixMath.REMatrix factors = new MatrixMath.REMatrix(0, 0); MatrixMath.BEMatrix loads = new MatrixMath.BEMatrix(0, 0); MatrixMath.BEMatrix residualVariances = new MatrixMath.BEMatrix(0, 0); MatrixMath.HorizontalVector meanX = new MatrixMath.HorizontalVector(matrixX.Columns); // first, center the matrix MatrixMath.ColumnsToZeroMean(matrixX, meanX); MatrixMath.NIPALS_HO(matrixX, maxNumberOfFactors, 1E-9, factors, loads, residualVariances); // now we have to create a new table where to place the calculated factors and loads // we will do that in a vertical oriented manner, i.e. even if the loads are // here in horizontal vectors: in our table they are stored in (vertical) columns Altaxo.Data.DataTable table = new Altaxo.Data.DataTable("PCA of " + srctable.Name); // Fill the Table table.Suspend(); // first of all store the meanscore { double meanScore = MatrixMath.LengthOf(meanX); MatrixMath.NormalizeRows(meanX); Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn(); for (int i = 0; i < factors.Rows; i++) { col[i] = meanScore; } table.DataColumns.Add(col, "MeanFactor", Altaxo.Data.ColumnKind.V, 0); } // first store the factors for (int i = 0; i < factors.Columns; i++) { Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn(); for (int j = 0; j < factors.Rows; j++) { col[j] = factors[j, i]; } table.DataColumns.Add(col, "Factor" + i.ToString(), Altaxo.Data.ColumnKind.V, 1); } // now store the mean of the matrix { Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn(); for (int j = 0; j < meanX.Columns; j++) { col[j] = meanX[0, j]; } table.DataColumns.Add(col, "MeanLoad", Altaxo.Data.ColumnKind.V, 2); } // now store the loads - careful - they are horizontal in the matrix for (int i = 0; i < loads.Rows; i++) { Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn(); for (int j = 0; j < loads.Columns; j++) { col[j] = loads[i, j]; } table.DataColumns.Add(col, "Load" + i.ToString(), Altaxo.Data.ColumnKind.V, 3); } // now store the residual variances, they are vertical in the vector { Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn(); for (int i = 0; i < residualVariances.Rows; i++) { col[i] = residualVariances[i, 0]; } table.DataColumns.Add(col, "ResidualVariance", Altaxo.Data.ColumnKind.V, 4); } table.Resume(); mainDocument.DataTableCollection.Add(table); // create a new worksheet without any columns Current.ProjectService.CreateNewWorksheet(table); return(null); }