% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/efa_hull.R
\name{efa_hull}
\alias{efa_hull}
\title{Hull method for determining the number of factors to retain}
\source{
Auerswald, M., & Moshagen, M. (2019). How to determine the number of
factors to retain in exploratory factor analysis: A comparison of extraction
methods under realistic conditions. Psychological Methods, 24(4), 468–491.
https://doi.org/10.1037/met0000200

Lorenzo-Seva, U., Timmerman, M. E., & Kiers, H. A. (2011).
The Hull method for selecting the number of common factors. Multivariate
Behavioral Research, 46(2), 340-364.
}
\usage{
efa_hull(
  x,
  N = NA,
  n_fac_theor = NA,
  estimator = c("PAF", "ULS", "ML"),
  gof = c("CAF", "CFI", "RMSEA"),
  eigen_type = c("SMC", "PCA", "EFA"),
  use = c("pairwise.complete.obs", "all.obs", "complete.obs", "everything",
    "na.or.complete"),
  cor_method = c("pearson", "spearman", "kendall", "poly", "tetra"),
  n_datasets = 1000,
  percent = 95,
  decision_rule = c("means", "percentile", "crawford"),
  n_factors = 1,
  estimate_control = NULL,
  ...
)
}
\arguments{
\item{x}{matrix or data.frame. Dataframe or matrix of raw data or matrix with
correlations.}

\item{N}{numeric. Number of cases in the data. This is passed to \link{efa_parallel}.
Only has to be specified if x is a correlation matrix, otherwise it is determined
based on the dimensions of x.}

\item{n_fac_theor}{numeric. Theoretical number of factors to retain. One plus
the larger of this number and the number of factors suggested by \link{efa_parallel}
is used as the upper bound \emph{J} of factors to extract in the Hull method.}

\item{estimator}{character. The estimator to use. One of  \code{"PAF"},
\code{"ULS"}, or  \code{"ML"}, for principal axis factoring, unweighted
least squares, and maximum likelihood, respectively. Default is \code{"PAF"}.}

\item{gof}{character. The goodness of fit index to use. Either \code{"CAF"},
\code{"CFI"}, or \code{"RMSEA"}, or any combination of them.
With the \code{"PAF"} estimator, only
the CAF can be used as goodness of fit index. For details on the CAF, see
Lorenzo-Seva, Timmerman, and Kiers (2011).}

\item{eigen_type}{character. On what the eigenvalues should be found in the
parallel analysis. Can be one of \code{"SMC"}, \code{"PCA"}, or \code{"EFA"}.
If using  \code{"SMC"} (default), the diagonal of the correlation matrices is
replaced by the squared multiple correlations (SMCs) of the indicators. If
using  \code{"PCA"}, the diagonal values of the correlation
matrices are left to be 1. If using  \code{"EFA"}, eigenvalues are found on the
correlation  matrices with the final communalities of an EFA solution as
diagonal. This is passed to  \code{\link[=efa_parallel]{efa_parallel()}}.}

\item{use}{character. Passed to \code{\link[stats:cor]{stats::cor()}} if raw data
is given as input. Default is \code{"pairwise.complete.obs"}.}

\item{cor_method}{character. One of \code{"pearson"}, \code{"spearman"}, or \code{"kendall"},
passed to \code{\link[stats:cor]{stats::cor()}}. \code{"poly"} and \code{"tetra"} are not supported because
\code{HULL} derives its factor-search bound from an internal parallel analysis
against continuous reference data.
Default is  \code{"pearson"}.}

\item{n_datasets}{numeric. The number of datasets to simulate. Must be at
least 1. Default is 1000. This is passed to \code{\link[=efa_parallel]{efa_parallel()}}.}

\item{percent}{numeric. The percentile to take from the simulated eigenvalues.
Default is 95. This is passed to \code{\link[=efa_parallel]{efa_parallel()}}.}

\item{decision_rule}{character. Which rule to use to determine the number of
factors to retain. Default is \code{"means"}, which will use the average
simulated eigenvalues. \code{"percentile"}, uses the percentiles specified
in percent. \code{"crawford"} uses the 95th percentile for the first factor
and the mean afterwards (based on Crawford et al, 2010). This is passed to \code{\link[=efa_parallel]{efa_parallel()}}.}

\item{n_factors}{numeric. Number of factors to extract if  \code{"EFA"} is
included in \code{eigen_type}. Default is 1. This is passed to
\code{\link[=efa_parallel]{efa_parallel()}}.}

\item{estimate_control}{an \code{\link[=estimate_control]{estimate_control()}} object with the estimation settings for the
\code{\link[=efa_fit]{efa_fit()}} fits of the 0 to \emph{J} factor solutions, and for the fit inside the internal
\code{\link[=efa_parallel]{efa_parallel()}} call. \code{NULL} (default) uses the \code{\link[=efa_fit]{efa_fit()}} defaults. This object carries
estimation settings only; the fits are always unrotated, which the hull statistics (CFI,
RMSEA, CAF) do not depend on.}

\item{...}{Further arguments passed to \code{\link[=efa_fit]{efa_fit()}}, also in
\code{\link[=efa_parallel]{efa_parallel()}}. The estimation tuning knobs are not passed here; they live in
\code{estimate_control}, a rotation setting is not accepted because the fits are unrotated, and
neither are the standard-error arguments (\code{se}, \code{b_boot}, \code{ci}, \code{seed}), because the fits
are internal steps whose standard errors are not reported.}
}
\value{
An object of class \code{efa_retention} (see \code{\link[=print.efa_retention]{print.efa_retention()}} and
\code{\link[=plot.efa_retention]{plot.efa_retention()}} for the print and plot methods). Its main fields are:
\item{n_factors}{A named numeric vector with the suggested number of factors
for each requested goodness-of-fit index (\code{"CAF"}, \code{"CFI"}, and/or
\code{"RMSEA"}).}
\item{results}{A list with one record per goodness-of-fit index, each holding
the goodness-of-fit values, the degrees of freedom, the hull membership, and
the retained solution used for printing and plotting. Each record also carries
\code{st}, the elbow sharpness of every solution (see details): the retained
solution has the largest value, and the runner-up shows how close the
selection was. \code{st} is \code{NA} for the solutions where it is undefined, that is
for those not on the hull and for the two hull endpoints, which have no
neighbouring hull solution on one side. When fewer than three solutions
remain on the hull, \code{st} is undefined throughout and the whole vector is \code{NA};
the retained solution is then the one with the highest goodness of fit, and a
warning says so.}
\item{settings}{A list of the settings used, including \code{n_fac_max}, the upper
bound \emph{J} of the number of factors to extract (see details). For backwards
compatibility the estimator is also repeated in \code{settings$method}.}

For backwards compatibility the per-index suggestions are additionally available
as the top-level fields \code{n_fac_CAF}, \code{n_fac_CFI} and \code{n_fac_RMSEA}, each \code{NA} if
that index was not requested in \code{gof}. New code should read them from
\code{n_factors} instead.
}
\description{
Implementation of the Hull method suggested by Lorenzo-Seva, Timmerman,
and Kiers (2011), with an extension to principal axis factoring. See details for
parallelization.
}
\details{
The Hull method aims to find a model with an optimal balance between
model fit and number of parameters, retaining only major factors
(Lorenzo-Seva, Timmerman, & Kiers, 2011). It fits 0 to \emph{J} factors -- where
\emph{J} is the number of factors suggested by parallel analysis (or \code{n_fac_theor},
if that is larger), plus one -- keeps the solutions on the upper boundary of
the convex hull of goodness-of-fit against degrees of freedom, and selects the
one at the sharpest elbow, i.e. with the highest \emph{st} value.

Because it trades fit against parsimony instead of testing against a null model
of uncorrelated variables, the Hull method does not lose accuracy for the
correlated-factor structures where parallel analysis (\code{\link[=efa_parallel]{efa_parallel()}}) tends to
under-extract; the CAF variant in particular was among the more accurate criteria
in Auerswald and Moshagen (2019). It needs at least six indicators and fits a
model at every candidate factor count, so it is comparatively slow and is not an
option for very short scales.

The \link{efa_parallel} function and the principal axis factoring of the
different number of factors can be parallelized using the future framework,
by calling the \code{\link[future:plan]{future::plan()}} function. The examples
provide example code on how to enable parallel processing.

The upper bound \emph{J} comes from \code{\link[=efa_parallel]{efa_parallel()}}, which compares against simulated
data, so the suggested number of factors varies slightly from run to run; a
criterion-based rotation passed through \code{...} adds its own random starts. Call
\code{\link[base:set.seed]{base::set.seed()}} beforehand to make a run reproducible; the result is then also
independent of the parallel plan.

Note that if \code{gof = "RMSEA"} is used, 1 - RMSEA is actually used to
compare the different solutions. This is necessary due to how the heuristic to
locate the elbow of the hull works.

The solutions are fitted without inequality constraints, so a solution can be
inadmissible (a Heywood case, or a fit that did not converge). Only the selected
solution is checked for this; if it is inadmissible a warning is raised and the
retained number of factors should be interpreted with caution.

The ML estimation method uses the \code{\link[psych:fa]{psych::fa()}}
starting values. See also the \link{efa_fit} documentation.
}
\examples{
\donttest{
# using PAF (this will print a message if gof is not specified manually
# and CAF will be used automatically)
efa_hull(test_models$baseline$cormat, N = 500, gof = "CAF", n_datasets = 100)

# using ML with all available fit indices (CAF, CFI, and RMSEA)
efa_hull(test_models$baseline$cormat, N = 500, estimator = "ML", n_datasets = 100)

# using ULS with only RMSEA
efa_hull(test_models$baseline$cormat, N = 500, estimator = "ULS", gof = "RMSEA",
         n_datasets = 100)
}

\dontrun{
# using parallel processing (Note: plans can be adapted, see the future
# package for details). future::plan() returns the plan it replaces, so
# on.exit() puts the session back as it was -- also if the call fails.
local({
  old_plan <- future::plan(future::multisession, workers = 2)
  on.exit(future::plan(old_plan), add = TRUE)
  efa_hull(test_models$baseline$cormat, N = 500, gof = "CAF")
})
}
}
\seealso{
\code{\link[=efa_retain]{efa_retain()}} as a wrapper function for this and the other factor
retention criteria.

Other factor retention criteria:
\code{\link[=efa_cd]{efa_cd()}},
\code{\link[=efa_ekc]{efa_ekc()}},
\code{\link[=efa_kgc]{efa_kgc()}},
\code{\link[=efa_map]{efa_map()}},
\code{\link[=efa_nest]{efa_nest()}},
\code{\link[=efa_parallel]{efa_parallel()}},
\code{\link[=efa_retain]{efa_retain()}},
\code{\link[=efa_scree]{efa_scree()}},
\code{\link[=efa_smt]{efa_smt()}}
}
\concept{factor retention criteria}
