com.itemanalysis.psychometrics.factoranalysis.ExploratoryFactorAnalysis.java Source code

Java tutorial

Introduction

Here is the source code for com.itemanalysis.psychometrics.factoranalysis.ExploratoryFactorAnalysis.java

Source

/**
 * Copyright 2014 J. Patrick Meyer
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.itemanalysis.psychometrics.factoranalysis;

import org.apache.commons.math3.linear.RealMatrix;

import java.util.Formatter;

/**
 * This class is the main entry point for conducting exploratory factor analysis. Users will focus on this class. 
 * All other classes in this package provide support for this class. All factor analysis methods require a 
 * correlation matrix and number indicating the number of factors.
 */
public class ExploratoryFactorAnalysis {

    private RealMatrix correlationMatrix = null;
    private int nVariables = 0;
    private int nFactors = 0;
    private int nParameters = 0;
    private FactorMethod factorMethod = null;
    private RotationMethod rotationMethod = RotationMethod.NONE;
    private double fmin = 0.0;
    private String title = "";

    /**
     * The constructor requires a correlation matrix and the number of factors.
     *
     * @param correlationMatrix correlation matrix
     * @param nFactors number of factor to use
     */
    public ExploratoryFactorAnalysis(RealMatrix correlationMatrix, int nFactors) {
        this.correlationMatrix = correlationMatrix;
        this.nFactors = Math.max(nFactors, 1);
        this.nVariables = correlationMatrix.getColumnDimension();
        this.nParameters = nVariables;
    }

    /**
     * The main method for estimating parameters. It will use the estimation method provided in the argument.
     *
     * @param fm estimation method for computing factor loadings
     * @param rotationMethod method of rotating factor loadings
     */
    public void estimateParameters(EstimationMethod fm, RotationMethod rotationMethod) {
        this.rotationMethod = rotationMethod;

        if (fm == EstimationMethod.PRINCOMP) {
            factorMethod = new PrincipalComponentsMethod(correlationMatrix, nFactors, rotationMethod);
            title = "Principal Components Analysis (" + rotationMethod.toString() + ")";
        } else if (fm == EstimationMethod.ML) {
            factorMethod = new MaximumLikelihoodMethod(correlationMatrix, nFactors, rotationMethod);
            title = "Maximum Likelihood Factor Analysis (" + rotationMethod.toString() + ")";
        } else if (fm == EstimationMethod.WLS) {
            factorMethod = new WeightedLeastSquaresMethod(correlationMatrix, nFactors, rotationMethod);
            title = "Weighted Least Squares Factor Analysis (" + rotationMethod.toString() + ")";
        } else if (fm == EstimationMethod.GLS) {
            factorMethod = new GeneralizedLeastSquaresMethod(correlationMatrix, nFactors, rotationMethod);
            title = "Generalized Least Squares Factor Analysis (" + rotationMethod.toString() + ")";
        } else {
            factorMethod = new MINRESmethod(correlationMatrix, nFactors, rotationMethod);
            title = "MINRES Factor Analysis (" + rotationMethod.toString() + ")";
        }

        fmin = factorMethod.estimateParameters();

    }

    public void estimateParameters(EstimationMethod fm) {
        estimateParameters(fm, RotationMethod.NONE);
    }

    public void rotateFactor(RotationMethod method) {

    }

    /**
     * Return s the factor method for obtaining values of the estimates and other information as indicated in the
     * FactorMethod interface.
     *
     * @return a FactorMethod
     */
    public FactorMethod getFactorMethod() {
        return factorMethod;
    }

    public String printOutput() {
        return printOutput(2);
    }

    /**
     * Formatted output of the results. It includes the factor loadings, communalities, and unqiuenesses.
     *
     * @param precision number of decimal places to report
     * @return string of result
     */
    public String printOutput(int precision) {
        StringBuilder sb = new StringBuilder();
        Formatter f = new Formatter(sb);

        int size = 24;
        String line1 = "=========================";
        String line2 = "-------------------------";
        for (int j = 0; j < nFactors; j++) {
            size = size + 10;
            line1 += "==========";
            line2 += "----------";
        }
        size = size + 10;
        line1 += "==========";
        line2 += "----------";
        size = size + 6;
        line1 += "======";
        line2 += "------";

        f.format("%36s", title);
        f.format("%n");
        f.format("%" + size + "s", line1);
        f.format("%n");
        f.format("%20s", "Name");
        f.format("%4s", "");
        for (int j = 0; j < nFactors; j++) {
            f.format("%6s", "F" + (j + 1));
            f.format("%4s", "");
        }
        f.format("%6s", "H2");
        f.format("%4s", "");
        f.format("%6s", "U2");
        f.format("%n");
        f.format("%" + size + "s", line2);
        f.format("%n");

        for (int i = 0; i < nVariables; i++) {
            f.format("%20s", "V" + (i + 1));
            f.format("%5s", "");
            for (int j = 0; j < nFactors; j++) {
                f.format("%6." + precision + "f", factorMethod.getFactorLoadingAt(i, j));
                f.format("%4s", "");
            }
            f.format("%6." + precision + "f", factorMethod.getCommunalityAt(i));
            f.format("%4s", "");
            f.format("%6." + precision + "f", factorMethod.getUniquenessAt(i));
            f.format("%n");
        }

        f.format("%" + size + "s", line1);
        f.format("%n");
        f.format("%30s", "Value of the objective function = ");
        f.format("%-8.4f", fmin);
        f.format("%n");
        f.format("%n");

        f.format("%20s", "");
        for (int j = 0; j < nFactors; j++) {
            f.format("%6s", "F" + (j + 1));
            f.format("%2s", "");
        }
        f.format("%n");

        f.format("%20s", "SS loadings");
        for (int j = 0; j < nFactors; j++) {
            f.format("%6." + precision + "f", factorMethod.getSumsOfSquaresAt(j));
            f.format("%2s", "");
        }
        f.format("%n");

        f.format("%20s", "Proportion Var");
        for (int j = 0; j < nFactors; j++) {
            f.format("%6." + precision + "f", factorMethod.getProportionOfVarianceAt(j));
            f.format("%2s", "");
        }
        f.format("%n");

        f.format("%20s", "Proportion Explained");
        for (int j = 0; j < nFactors; j++) {
            f.format("%6." + precision + "f", factorMethod.getProportionOfExplainedVarianceAt(j));
            f.format("%2s", "");
        }
        f.format("%n");

        return f.toString();
    }

}