Example #1
0
        /// <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);
        }
Example #2
0
        /// <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>
    /// 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;
    }
Example #5
0
        public static void StatisticsOnRows(
            Altaxo.AltaxoDocument mainDocument,
            Altaxo.Data.DataTable srctable,
            IAscendingIntegerCollection selectedColumns,
            IAscendingIntegerCollection selectedRows
            )
        {
            bool bUseSelectedColumns = (null != selectedColumns && 0 != selectedColumns.Count);
            int  numcols             = bUseSelectedColumns ? selectedColumns.Count : srctable.DataColumns.ColumnCount;

            if (numcols == 0)
            {
                return; // nothing selected
            }
            bool bUseSelectedRows = (null != selectedRows && 0 != selectedRows.Count);
            int  numrows          = bUseSelectedRows ? selectedRows.Count : srctable.DataColumns.RowCount;

            if (numrows == 0)
            {
                return;
            }

            Altaxo.Data.DataTable table = new Altaxo.Data.DataTable();
            // add a text column and some double columns
            // note: statistics is only possible for numeric columns since
            // otherwise in one column doubles and i.e. dates are mixed, which is not possible

            // 1st column is the mean, and holds the sum during the calculation
            Data.DoubleColumn c1 = new Data.DoubleColumn();

            // 2rd column is the standard deviation, and holds the square sum during calculation
            Data.DoubleColumn c2 = new Data.DoubleColumn();

            // 3th column is the standard e (N)
            Data.DoubleColumn c3 = new Data.DoubleColumn();

            // 4th column is the sum
            Data.DoubleColumn c4 = new Data.DoubleColumn();

            // 5th column is the number of items for statistics
            Data.DoubleColumn c5 = new Data.DoubleColumn();

            table.DataColumns.Add(c1, "Mean");
            table.DataColumns.Add(c2, "sd");
            table.DataColumns.Add(c3, "se");
            table.DataColumns.Add(c4, "Sum");
            table.DataColumns.Add(c5, "N");

            table.Suspend();


            // first fill the cols c1, c2, c5 with zeros because we want to sum up
            for (int i = 0; i < numrows; i++)
            {
                c1[i] = 0;
                c2[i] = 0;
                c5[i] = 0;
            }


            for (int si = 0; si < numcols; si++)
            {
                Altaxo.Data.DataColumn col = bUseSelectedColumns ? srctable[selectedColumns[si]] : srctable[si];
                if (!(col is Altaxo.Data.INumericColumn))
                {
                    continue;
                }

                // now do the statistics
                Data.INumericColumn ncol = (Data.INumericColumn)col;
                for (int i = 0; i < numrows; i++)
                {
                    double val = bUseSelectedRows ? ncol[selectedRows[i]] : ncol[i];
                    if (Double.IsNaN(val))
                    {
                        continue;
                    }

                    c1[i] += val;
                    c2[i] += val * val;
                    c5[i] += 1;
                }
            } // for all selected columns


            // now calculate the statistics
            for (int i = 0; i < numrows; i++)
            {
                // now fill a new row in the worksheet
                double NN     = c5[i];
                double sum    = c1[i];
                double sumsqr = c2[i];
                if (NN > 0)
                {
                    double mean    = c1[i] / NN;
                    double ymy0sqr = sumsqr - sum * sum / NN;
                    if (ymy0sqr < 0)
                    {
                        ymy0sqr = 0; // if this is lesser zero, it is a rounding error, so set it to zero
                    }
                    double sd = NN > 1 ? Math.Sqrt(ymy0sqr / (NN - 1)) : 0;
                    double se = sd / Math.Sqrt(NN);

                    c1[i] = mean; // mean
                    c2[i] = sd;
                    c3[i] = se;
                    c4[i] = sum;
                    c5[i] = NN;
                }
            } // for all rows

            // if a table was created, we add the table to the data set and
            // create a worksheet
            if (null != table)
            {
                table.Resume();
                mainDocument.DataTableCollection.Add(table);
                // create a new worksheet without any columns
                Current.ProjectService.CreateNewWorksheet(table);
            }
        }
    /// <summary>
    /// Makes a PLS (a partial least squares) 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="selectedPropertyColumns">The selected property column(s).</param>
    /// <param name="bHorizontalOrientedSpectrum">True if a spectrum is a single row, False if a spectrum is a single column.</param>
    /// <param name="plsOptions">Provides information about the max number of factors and the calculation of cross PRESS value.</param>
    /// <param name="preprocessOptions">Provides information about how to preprocess the spectra.</param>
    /// <returns></returns>
    public virtual string ExecuteAnalysis(
      Altaxo.AltaxoDocument mainDocument,
      Altaxo.Data.DataTable srctable,
      IAscendingIntegerCollection selectedColumns,
      IAscendingIntegerCollection selectedRows,
      IAscendingIntegerCollection selectedPropertyColumns,
      bool bHorizontalOrientedSpectrum,
      MultivariateAnalysisOptions plsOptions,
      SpectralPreprocessingOptions preprocessOptions
      )
    {
      IMatrix matrixX, matrixY;
      IROVector xOfX;
      MultivariateContentMemento plsContent = new MultivariateContentMemento();
      plsContent.Analysis = this;

      // 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(this.AnalysisName + " of " + srctable.Name);
      // Fill the Table
      table.Suspend();
      table.SetTableProperty("Content",plsContent);
      plsContent.TableName = srctable.Name;

     

      // Get matrices
      GetXYMatrices(
        srctable,
        selectedColumns,
        selectedRows,
        selectedPropertyColumns,
        bHorizontalOrientedSpectrum,
        plsContent,
        out matrixX, out matrixY, out xOfX );

    

      StoreXOfX(xOfX,table);


      // Preprocess
      plsContent.SpectralPreprocessing = preprocessOptions;
      IVector meanX,scaleX,meanY,scaleY;
      MultivariateRegression.PreprocessForAnalysis(preprocessOptions,xOfX,matrixX,matrixY,
        out meanX, out scaleX, out meanY, out scaleY); 

      StorePreprocessedData(meanX,scaleX,meanY,scaleY,table);


      // Analyze and Store
      IROVector press;
      ExecuteAnalysis(
        matrixX,
        matrixY,        
        plsOptions,
        plsContent,
        table, out press);


      this.StorePRESSData(press,table);

      if(plsOptions.CrossPRESSCalculation!=CrossPRESSCalculationType.None)
        CalculateCrossPRESS(xOfX,matrixX,matrixY,plsOptions,plsContent,table);
      
      StoreFRatioData(table,plsContent);

      StoreOriginalY(table,plsContent);

      table.Resume();
      Current.Project.DataTableCollection.Add(table);
      // create a new worksheet without any columns
      Current.ProjectService.CreateNewWorksheet(table);

      return null;
    }
    public static void StatisticsOnRows(
      Altaxo.AltaxoDocument mainDocument,
      Altaxo.Data.DataTable srctable,
      IAscendingIntegerCollection selectedColumns,
      IAscendingIntegerCollection selectedRows
      )
    {
      bool bUseSelectedColumns = (null!=selectedColumns && 0!=selectedColumns.Count);
      int numcols = bUseSelectedColumns ? selectedColumns.Count : srctable.DataColumns.ColumnCount;
      if(numcols==0)
        return; // nothing selected

      bool bUseSelectedRows = (null!=selectedRows && 0!=selectedRows.Count);
      int numrows = bUseSelectedRows ? selectedRows.Count : srctable.DataColumns.RowCount;
      if(numrows==0)
        return;

      Altaxo.Data.DataTable table = new Altaxo.Data.DataTable();
      // add a text column and some double columns
      // note: statistics is only possible for numeric columns since
      // otherwise in one column doubles and i.e. dates are mixed, which is not possible

      // 1st column is the mean, and holds the sum during the calculation
      Data.DoubleColumn c1 = new Data.DoubleColumn();

      // 2rd column is the standard deviation, and holds the square sum during calculation
      Data.DoubleColumn c2 = new Data.DoubleColumn();

      // 3th column is the standard e (N)
      Data.DoubleColumn c3 = new Data.DoubleColumn();

      // 4th column is the sum
      Data.DoubleColumn c4 = new Data.DoubleColumn();

      // 5th column is the number of items for statistics
      Data.DoubleColumn c5 = new Data.DoubleColumn();
      
      table.DataColumns.Add(c1,"Mean");
      table.DataColumns.Add(c2,"sd");
      table.DataColumns.Add(c3,"se");
      table.DataColumns.Add(c4,"Sum");
      table.DataColumns.Add(c5,"N");

      table.Suspend();

      
      // first fill the cols c1, c2, c5 with zeros because we want to sum up 
      for(int i=0;i<numrows;i++)
      {
        c1[i]=0;
        c2[i]=0;
        c5[i]=0;
      }
  
      
      for(int si=0;si<numcols;si++)
      {
        Altaxo.Data.DataColumn col = bUseSelectedColumns ? srctable[selectedColumns[si]] : srctable[si];
        if(!(col is Altaxo.Data.INumericColumn))
          continue;

        // now do the statistics 
        Data.INumericColumn ncol = (Data.INumericColumn)col;
        for(int i=0;i<numrows;i++)
        {
          double val = bUseSelectedRows ? ncol[selectedRows[i]] : ncol[i];
          if(Double.IsNaN(val))
            continue;

          c1[i] += val;
          c2[i] += val*val;
          c5[i] += 1;
        }
      } // for all selected columns

      
      // now calculate the statistics
      for(int i=0;i<numrows;i++)
      {
        // now fill a new row in the worksheet
        double NN=c5[i];
        double sum=c1[i];
        double sumsqr=c2[i];
        if(NN>0)
        {
          double mean = c1[i]/NN;
          double ymy0sqr = sumsqr - sum*sum/NN;
          if(ymy0sqr<0) ymy0sqr=0; // if this is lesser zero, it is a rounding error, so set it to zero
          double sd = NN>1 ? Math.Sqrt(ymy0sqr/(NN-1)) : 0;
          double se = sd/Math.Sqrt(NN);

          c1[i] = mean; // mean
          c2[i] = sd;
          c3[i] = se;
          c4[i] = sum;
          c5[i] = NN;
        }
      } // for all rows
  
      // if a table was created, we add the table to the data set and
      // create a worksheet
      if(null!=table)
      {
        table.Resume();
        mainDocument.DataTableCollection.Add(table);
        // create a new worksheet without any columns
        Current.ProjectService.CreateNewWorksheet(table);

      }
    }