/* * CLASS: PCA * * USAGE: Principlal Component Analysis * * This is a subclass of the superclass Scores * * * WRITTEN BY: Dr Michael Thomas Flanagan * * DATE: October 2008 * AMENDED: 17-18 October 2008, 4 January 2010, 13 November 2010, 29-30 November 2010, 4 December 2010, 18 January 2011, 17-18 July 2011 * * DOCUMENTATION: * See Michael Thomas Flanagan's Java library on-line web pages: * http://www.ee.ucl.ac.uk/~mflanaga/java/ * http://www.ee.ucl.ac.uk/~mflanaga/java/PCA.html * * Copyright (c) 2008 - 2011 Michael Thomas Flanagan * * PERMISSION TO COPY: * * Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, * provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies * and associated documentation or publications. * * Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions * and the following disclaimer and requires written permission from the Michael Thomas Flanagan: * * Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and * the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: * * Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. * Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software * or its derivatives. * ***************************************************************************************/ package flanagan.analysis; import java.util.*; import java.text.*; import java.awt.*; import flanagan.math.*; import flanagan.io.*; import flanagan.analysis.*; import flanagan.plot.*; public class PCA extends Scores{ private Matrix data = null; // data as row per item as a Matrix private Matrix dataMinusMeans = null; // data with row means subtracted as row per item as a Matrix private Matrix dataMinusMeansTranspose = null; // data with row means subtracted as row per item as a Matrix private Matrix covarianceMatrix = null; // variance-covariance Matrix private Matrix correlationMatrix = null; // correlation Matrix private Matrix partialCorrelationMatrix = null; // partial correlation Matrix private double kmo = 0.0; // overall Kaiser-Meyer-Olkin (KMO) statistic private double[] itemKMOs = null; // individual item KMOs private double chiSquareBartlett = 0.0; // Bartlett test of sphericity chi square private int dfBartlett = 0; // Bartlett test of sphericity degrees of freedom private double probBartlett = 0.0; // Bartlett test of sphericity chi square probability private double sign10Bartlett = 0.0; // Bartlett test of sphericity chi square value at 10% significance level private double sign05Bartlett = 0.0; // Bartlett test of sphericity chi square value at 5% significance level private double[] eigenValues = null; // eigenvalues private double[] orderedEigenValues = null; // eigenvalues sorted into a descending order private int[] eigenValueIndices = null; // indices of the eigenvalues before sorting into a descending order private double eigenValueTotal = 0.0; // total of all eigen values; private int[] rotatedIndices = null; // rearranged indices on ordering after rotation private double[] rotatedEigenValues = null; // scaled rotated eigenvalues private double[] usRotatedEigenValues = null; // unscaled rotated eigenvalues private int nMonteCarlo = 200; // number of Monte Carlo generated eigenvalue calculations private double[][] randomEigenValues = null; // Monte Carlo generated eigenvalues private double[] randomEigenValuesMeans = null; // means of the Monte Carlo generated eigenvalues private double[] randomEigenValuesSDs = null; // standard deviations of the Monte Carlo generated eigenvalues private double[] randomEigenValuesPercentiles = null; // percentiles of the Monte Carlo generated eigenvalues private double percentile = 95.0; // percentile used in parallel analysis private boolean gaussianDeviates = false; // = false: uniform random deviates used in Monte Carlo // = true: Gaussian random deviates used in Monte Carlo private double[] proportionPercentage = null; // eigenvalues expressesed as percentage of total private double[] cumulativePercentage = null; // cumulative values of the eigenvalues expressesed as percentage of total private double[] rotatedProportionPercentage = null; // scaled rotated eigenvalues expressesed as percentage of unrotated total private double[] rotatedCumulativePercentage = null; // scaled rotated cumulative values of the eigenvalues expressesed as percentage of unrotated total private double[][] eigenVectorsAsColumns = null; // eigenvectors as columns private double[][] eigenVectorsAsRows = null; // eigenvectors as rows private double[][] orderedEigenVectorsAsColumns = null; // eigenvectors, as columns, arranged to match a descending order of eigenvalues private double[][] orderedEigenVectorsAsRows = null; // eigenvectors, as rows, arranged to match a descending order of eigenvalues private double[][] loadingFactorsAsColumns = null; // loading factors as column per eigenvalue private double[][] loadingFactorsAsRows = null; // loading factors as row per eigenvalue private double[][] rotatedLoadingFactorsAsColumns = null; // scaled rotated loading factors as column per eigenvalue private double[][] rotatedLoadingFactorsAsRows = null; // scaled rotated loading factors as row per eigenvalue private double[][] usRotatedLoadingFactorsAsColumns = null; // unscaled rotated loading factors as column per eigenvalue private double[][] usRotatedLoadingFactorsAsRows = null; // unscaled rotated loading factors as row per eigenvalue private double[] communalities = null; // communalities private double[] communalityWeights = null; // communality weights private boolean covRhoOption = false; // = true: covariance matrix used // = false: correlation matrix used private int greaterThanOneLimit = 0; // number of components extracted using eigenvalue greater than one private int percentileCrossover = 0; // number of components extracted using percentile scree crossover private int meanCrossover = 0; // number of components extracted using mean scree crossover private int nVarimaxMax = 1000; // maximum iterations allowed by the varimax criterion private int nVarimax = 0; // number of iterations taken by the varimax criterion private double varimaxTolerance = 1.0E-8; // tolerance for terminatiing 2 criterion iteration private boolean varimaxOption = true; // = true: normal varimax, i.e. comunality weighted varimax // = false: raw varimax private boolean pcaDone = false; // = true when PCA performed private boolean monteCarloDone = false; // = true when parallel monte Carlo simultaion performed private boolean rotationDone = false; // = true when rotation performed // CONSTRUCTOR public PCA(){ super.trunc = 4; } // CHOICE OF MATRIX // Use covariance matrix (default option) public void useCovarianceMatrix(){ this.covRhoOption = true; } // Use correlation matrix (default option) public void useCorrelationMatrix(){ this.covRhoOption = false; } // CHOICE OF VARIMAX CRITERION // Use normal varimax rotation public void useNormalVarimax(){ this. varimaxOption = true; } // Use raw varimax rotation public void useRawVarimax(){ this. varimaxOption = false; } // Return varimax rotation option public String getVarimaxOption(){ if(this. varimaxOption){ return "normal varimax option"; } else{ return "raw varimax option"; } } // PARALLEL ANALYSIS OPTIONS // Reset number of Monte Carlo simulations public void setNumberOfSimulations(int nSimul){ this.nMonteCarlo = nSimul; } // Return number of Monte Carlo simulations public int getNumberOfSimulations(){ return this.nMonteCarlo; } // Use Gaussian random deviates in MontMonte Carlo simulations public void useGaussianDeviates(){ this.gaussianDeviates = true; } // Use uniform random deviates in MontMonte Carlo simulations public void useUniformDeviates(){ this.gaussianDeviates = false; } // Reset percentile percentage in parallel analysis (defalut option = 95%) public void setParallelAnalysisPercentileValue(double percent){ this.percentile = percent; } // Return percentile percentage in parallel analysis (defalut option = 95%) public double getParallelAnalysisPercentileValue(){ return this.percentile; } // PRINCIPAL COMPONENT ANALYSIS public void pca(){ if(!this.pcaDone){ if(this.nItems==1)throw new IllegalArgumentException("You have entered only one item - PCA is not meaningful"); if(this.nPersons==1)throw new IllegalArgumentException("You have entered only one score or measurement source - PCA is not meaningful"); // Check that data is preprocessed if(!this.dataPreprocessed)this.preprocessData(); // Store data as an instance of matrix this.data = new Matrix(super.scores0); // Subtract row means this.dataMinusMeans = this.data.subtractRowMeans(); // Transpose this.dataMinusMeansTranspose = this.dataMinusMeans.transpose(); // Covariance matrix this.covarianceMatrix = this.dataMinusMeans.times(this.dataMinusMeansTranspose); double denom = this.nPersons; if(!super.nFactorOption)denom -= 1.0; this.covarianceMatrix = this.covarianceMatrix.times(1.0/denom); // Correlation matrix boolean tinyCheck = false; double[][] cov = this.covarianceMatrix.getArrayCopy(); double[][] corr = new double[this.nItems][this.nItems]; for(int i=0; inVarimaxMax){ test=false; System.out.println("Method varimaxRotation: maximum iterations " + nVarimaxMax + " exceeded"); System.out.println("Tolerance = " + this.varimaxTolerance + ", Comparison value = " + Math.abs(va - vaLast)); System.out.println("Current values returned"); if(super.sameCheck>0){ System.out.println("Presence of identical element row/s and/or column/s in the data probably impeding convergence"); System.out.println("Returned values are likely to be correct"); } } } } // undo normalization of rotated loading factors this.usRotatedLoadingFactorsAsColumns = new double[nColumns][nRows]; for(int i=0; inIterMax){ test=false; System.out.println("Method varimaxRotation: maximum iterations " + nIterMax + " exceeded"); System.out.println("Current values returned"); } } } // undo normalization of loading factors for(int i=0; inDisplay)nDisplay = nDisplayLimit; for(int i=0; inDisplay)nDisplay = nDisplayLimit; for(int i=0; i