Skip to contents

This vignette documents the algorithm behind mspca(), the implementation choices that make it fast, and how to set its parameters. Readers who want the theoretical analysis should consult Cory-Wright and Pauphilet (2026).

The problem

The goal of sparse PCA is to identify rr loading vectors 𝒖1,…,𝒖rβˆˆβ„p\boldsymbol{u}_1, \ldots, \boldsymbol{u}_r \in \mathbb{R}^p that collectively explain a large share of the variance in the data, while each vector involves only a small number of the pp original features. In the single-component case (r=1r = 1) this is

maxπ’–βˆˆβ„pπ’–βŠ€πšΊπ’–s.t.βˆ₯𝒖βˆ₯2=1,βˆ₯𝒖βˆ₯0≀k,\max_{\boldsymbol{u} \in \mathbb{R}^p} \ \boldsymbol{u}^\top \boldsymbol{\Sigma} \boldsymbol{u} \quad \text{s.t.} \quad \|\boldsymbol{u}\|_2 = 1, \ \|\boldsymbol{u}\|_0 \leq k,

for which many efficient algorithms exist (d’Aspremont et al. 2007; Yuan and Zhang 2013; Bertsimas et al. 2022). The challenge in the rr-component case is coordinating the components so that they are non-redundant.

In standard dense PCA, non-redundancy is ensured by requiring the rr leading eigenvectors of 𝚺\boldsymbol{\Sigma} to be mutually orthogonal and their projections to be uncorrelated. These two properties hold simultaneously for eigenvectors but generally cannot both be enforced in the sparse setting. msPCA therefore supports either type of coupling constraint, selected with feasibilityConstraintType:

  • Orthogonality (feasibilityConstraintType = 0, the default): the loading vectors are required to be mutually orthogonal, 𝒖tβŠ€π’–tβ€²=0\boldsymbol{u}_t^\top \boldsymbol{u}_{t'} = 0 for all tβ‰ tβ€²t \neq t'. This is the direct geometric analogue of standard PCA.
  • Zero pairwise correlation (feasibilityConstraintType = 1): the projected components are required to be uncorrelated in the data, 𝒖tβŠ€πšΊπ’–tβ€²=0\boldsymbol{u}_t^\top \boldsymbol{\Sigma} \boldsymbol{u}_{t'} = 0 for all tβ‰ tβ€²t \neq t'. This ensures each component captures statistically distinct information.

Writing π‘ͺ∈{𝕀,𝚺}\boldsymbol{C} \in \{\mathbb{I}, \boldsymbol{\Sigma}\} to encode the constraint type, the rr-component problem solved by msPCA is

maxπ‘Όβˆˆβ„pΓ—rβˆ‘t=1r𝒖tβŠ€πšΊπ’–ts.t.𝒖t⊀π‘ͺ𝒖tβ€²=0βˆ€tβ‰ tβ€²,βˆ₯𝒖tβˆ₯2=1,βˆ₯𝒖tβˆ₯0≀ktβˆ€t∈[r].\max_{\boldsymbol{U} \in \mathbb{R}^{p \times r}} \ \sum_{t=1}^r \boldsymbol{u}_t^\top \boldsymbol{\Sigma} \boldsymbol{u}_t \quad \text{s.t.} \quad \boldsymbol{u}_t^\top \boldsymbol{C} \boldsymbol{u}_{t'} = 0 \ \ \forall t \neq t', \quad \|\boldsymbol{u}_t\|_2 = 1, \ \|\boldsymbol{u}_t\|_0 \leq k_t \ \ \forall t \in [r]. \tag{1}

Orthogonality corresponds to π‘ͺ=𝕀\boldsymbol{C} = \mathbb{I} and zero correlation to π‘ͺ=𝚺\boldsymbol{C} = \boldsymbol{\Sigma}. In the zero-correlation case the implementation uses 𝚺\boldsymbol{\Sigma} divided by the total variance tr(𝚺)\mathrm{tr}(\boldsymbol{\Sigma}). This leaves the feasible set unchanged and makes the violation measure invariant to a rescaling of the data.

The objective is the sum of per-component variances. Most approaches for sparse PCA with multiple PCs use this objective (Zou et al. 2006; JournΓ©e et al. 2010; Lu and Zhang 2012; Vu et al. 2013; Benidis et al. 2016; Cory-Wright and Pauphilet 2026). It corresponds to the variance of the orthogonal projection onto the span of 𝑼\boldsymbol{U} only when the loading vectors are orthogonal; in general it is the sum of the marginal variances of the sparse components.

Evaluation metrics

Variance explained. The cumulative fraction of total variance explained by 𝑼=[𝒖1,…,𝒖r]\boldsymbol{U} = [\boldsymbol{u}_1, \ldots, \boldsymbol{u}_r] is

FVE(𝑼)=1tr(𝚺)βˆ‘t=1r𝒖tβŠ€πšΊπ’–t,\mathrm{FVE}(\boldsymbol{U}) = \frac{1}{\mathrm{tr}(\boldsymbol{\Sigma})} \sum_{t=1}^r \boldsymbol{u}_t^\top \boldsymbol{\Sigma} \boldsymbol{u}_t,

computed by fraction_variance_explained(). Because loading vectors may not be orthogonal, interpret this as a cumulative component-variance score rather than the variance of the orthogonal projection onto the span of 𝑼\boldsymbol{U}. Per-component contributions are returned by fraction_variance_explained_perPC() and, unnormalized, by variance_explained_perPC().

Feasibility. The constraint violation measures how far the returned solution is from satisfying the coupling constraints. Under orthogonality it is

violoff(𝑼)=βˆ‘t>tβ€²|𝒖tβŠ€π’–tβ€²|,\mathrm{viol}_{\mathrm{off}}(\boldsymbol{U}) = \sum_{t > t'} \left| \boldsymbol{u}_t^\top \boldsymbol{u}_{t'} \right|,

and under zero pairwise correlation

violoff(π‘ͺ,𝑼)=1tr(π‘ͺ)βˆ‘t>tβ€²|𝒖t⊀π‘ͺ𝒖tβ€²|,\mathrm{viol}_{\mathrm{off}}(\boldsymbol{C}, \boldsymbol{U}) = \frac{1}{\mathrm{tr}(\boldsymbol{C})} \sum_{t > t'} \left| \boldsymbol{u}_t^\top \boldsymbol{C} \boldsymbol{u}_{t'} \right|,

both computed by feasibility_violation_off(). The second is normalized by the total variance tr(π‘ͺ)\mathrm{tr}(\boldsymbol{C}): the loading vectors are unit-norm, so |𝒖t⊀π‘ͺ𝒖tβ€²||\boldsymbol{u}_t^\top \boldsymbol{C} \boldsymbol{u}_{t'}| is homogeneous of degree one in π‘ͺ\boldsymbol{C} and the unnormalized sum would depend on the units of the data. After normalization each pairwise term reads as a fraction of the total variance, hence is scale-invariant. The same convention is used inside the solver, and for the nonredundancy matrices stored on the fitted object.

Lagrangian alternating maximization

The key algorithmic idea is to handle the coupling constraints in (1) via a quadratic penalty in the objective. Introducing non-negative penalty parameters λt,t′\lambda_{t,t'} for each pair t≠t′t \neq t' (with λt,t′=λt′,t\lambda_{t,t'} = \lambda_{t',t}) gives the penalized objective

maxπ‘Όβˆ‘t=1r𝒖tβŠ€πšΊπ’–tβˆ’βˆ‘tβ‰ tβ€²Ξ»t,tβ€²(𝒖t⊀π‘ͺ𝒖tβ€²)2s.t.βˆ₯𝒖tβˆ₯2=1,βˆ₯𝒖tβˆ₯0≀ktβˆ€t.\max_{\boldsymbol{U}} \ \sum_{t=1}^r \boldsymbol{u}_t^\top \boldsymbol{\Sigma} \boldsymbol{u}_t - \sum_{t \neq t'} \lambda_{t,t'} \left( \boldsymbol{u}_t^\top \boldsymbol{C} \boldsymbol{u}_{t'} \right)^2 \quad \text{s.t.} \quad \|\boldsymbol{u}_t\|_2 = 1, \ \|\boldsymbol{u}_t\|_0 \leq k_t \ \ \forall t. \tag{2}

For fixed components 𝒖tβ€²\boldsymbol{u}_{t'}, tβ€²β‰ tt' \neq t, and fixed penalties, the subproblem for 𝒖t\boldsymbol{u}_t reduces to a non-convex single-component sparse PCA problem against the perturbed covariance matrix

πšΊΜƒt=πšΊβˆ’βˆ‘tβ€²β‰ tΞ»t,tβ€²π‘ͺ𝒖t′𝒖tβ€²βŠ€π‘ͺ.\tilde{\boldsymbol{\Sigma}}_t = \boldsymbol{\Sigma} - \sum_{t' \neq t} \lambda_{t,t'} \boldsymbol{C} \boldsymbol{u}_{t'} \boldsymbol{u}_{t'}^\top \boldsymbol{C}. \tag{3}

This decomposition holds for both constraint types: with π‘ͺ=𝕀\boldsymbol{C} = \mathbb{I} the perturbation is Ξ»t,t′𝒖t′𝒖tβ€²βŠ€\lambda_{t,t'} \boldsymbol{u}_{t'} \boldsymbol{u}_{t'}^\top, and with π‘ͺ=𝚺\boldsymbol{C} = \boldsymbol{\Sigma} it is Ξ»t,tβ€²πšΊπ’–t′𝒖tβ€²βŠ€πšΊ\lambda_{t,t'} \boldsymbol{\Sigma} \boldsymbol{u}_{t'} \boldsymbol{u}_{t'}^\top \boldsymbol{\Sigma}.

Most methods for computing the leading sparse eigenvector require the matrix to be positive semidefinite. If πšΊΜƒt\tilde{\boldsymbol{\Sigma}}_t is not, we add a diagonal shift Ξ»0𝕀\lambda_0 \mathbb{I}, which does not change the optimal solution because all feasible vectors have unit norm. The shift used is Ξ»0=βˆ‘tβ€²β‰ tΞ»t,tβ€²βˆ₯π‘ͺ𝒖tβ€²βˆ₯22\lambda_0 = \sum_{t' \neq t} \lambda_{t,t'} \|\boldsymbol{C} \boldsymbol{u}_{t'}\|_2^2, which bounds the deflation term by Ξ»0βˆ₯𝜷βˆ₯22\lambda_0 \|\boldsymbol{\beta}\|_2^2 for every 𝜷\boldsymbol{\beta} and so guarantees πšΊΜƒtβ‰½πŸŽ\tilde{\boldsymbol{\Sigma}}_t \succeq \boldsymbol{0}. It is the smallest shift of this form, which preserves the eigengap the power method relies on, and it is recomputed at each inner step from the current components, so no estimate of the spectrum of 𝚺\boldsymbol{\Sigma} is needed. Under orthogonality βˆ₯𝒖tβ€²βˆ₯2=1\|\boldsymbol{u}_{t'}\|_2 = 1 and it reduces to βˆ‘tβ€²β‰ tΞ»t,tβ€²\sum_{t' \neq t} \lambda_{t,t'}.

Iterating over t=1,…,rt = 1, \ldots, r and progressively increasing the penalties to drive constraint violations toward zero yields the following scheme.

Algorithm 1: Lagrangian alternating maximization for problem (1)

Require: covariance matrix 𝚺\boldsymbol{\Sigma}, number of components rr, sparsity budgets k1,…,krk_1, \ldots, k_r, constraint matrix π‘ͺ∈{𝕀,𝚺}\boldsymbol{C} \in \{\mathbb{I}, \boldsymbol{\Sigma}\}, iterations LL, feasibility tolerance Ξ·\eta

  1. Initialize 𝒖t(0)β†πŸŽ\boldsymbol{u}_t^{(0)} \leftarrow \boldsymbol{0} for all t∈[r]t \in [r]; set Ξ»t,t′←0\lambda_{t,t'} \leftarrow 0 for all tβ‰ tβ€²t \neq t'
  2. for β„“=1,…,L\ell = 1, \ldots, Ldo
  3. Β Β  for t=1,…,rt = 1, \ldots, rdo
  4. Β Β Β Β  Compute πšΊΜƒtβ†πšΊβˆ’βˆ‘tβ€²β‰ tΞ»t,tβ€²π‘ͺ𝒖tβ€²(β„“βˆ’1)𝒖tβ€²(β„“βˆ’1)⊀π‘ͺ+Ξ»0𝕀\tilde{\boldsymbol{\Sigma}}_t \leftarrow \boldsymbol{\Sigma} - \sum_{t' \neq t} \lambda_{t,t'} \boldsymbol{C} \boldsymbol{u}_{t'}^{(\ell-1)} \boldsymbol{u}_{t'}^{(\ell-1)\top} \boldsymbol{C} + \lambda_0 \mathbb{I}
  5. Β Β Β Β  Compute 𝒖t(β„“)\boldsymbol{u}_t^{(\ell)} via Algorithm 2 applied to (πšΊΜƒt,kt)(\tilde{\boldsymbol{\Sigma}}_t, k_t)
  6. Β Β  end for
  7. Β Β  if βˆ‘t|βˆ₯𝒖t(β„“)βˆ₯2βˆ’1|+βˆ‘t>tβ€²|𝒖t(β„“)⊀π‘ͺ𝒖tβ€²(β„“)|≀η\sum_t \left| \|\boldsymbol{u}_t^{(\ell)}\|^2 - 1 \right| + \sum_{t > t'} \left| \boldsymbol{u}_t^{(\ell)\top} \boldsymbol{C} \boldsymbol{u}_{t'}^{(\ell)} \right| \leq \etathen
  8. Β Β Β Β  Record {𝒖t(β„“)}\{\boldsymbol{u}_t^{(\ell)}\} as feasible; update best solution if the objective improves
  9. Β Β  end if
  10. Β Β  Increase the Ξ»t,tβ€²\lambda_{t,t'} values (see below)
  11. end for
  12. return best feasible solution found, or the last iterate if none was found

Each single-component subproblem is solved via the truncated power method (TPM, Yuan and Zhang 2013), which alternates between a power step (multiplying by πšΊΜƒt\tilde{\boldsymbol{\Sigma}}_t) and a truncation step (retaining only the ktk_t largest-magnitude entries). In practice TPM often finds high-quality solutions around two orders of magnitude faster than certifiably optimal methods (Berk and Bertsimas 2019; Behdin and Mazumder 2026). Each call starts from the current iterate and then draws random restarts, which guard against poor local optima.

Algorithm 2: truncated power method with random restarts (Yuan and Zhang 2013)

Require: matrix πšΊΜƒ\tilde{\boldsymbol{\Sigma}}, sparsity budget kk, iteration limit LTPML_{\mathrm{TPM}}, time limit TT

  1. 𝒖bestβ†πŸŽ\boldsymbol{u}_{\mathrm{best}} \leftarrow \boldsymbol{0}
  2. repeat
  3. Β Β  Draw π’–βˆΌπ’©(𝟎,𝕀)\boldsymbol{u} \sim \mathcal{N}(\boldsymbol{0}, \mathbb{I})
  4. Β Β  repeat
  5. Β Β Β Β  π’–β†πšΊΜƒπ’–/βˆ₯πšΊΜƒπ’–βˆ₯2\boldsymbol{u} \leftarrow \tilde{\boldsymbol{\Sigma}} \boldsymbol{u} / \|\tilde{\boldsymbol{\Sigma}} \boldsymbol{u}\|_2 Β  (power step)
  6. Β Β Β Β  Zero out all but the kk entries of 𝒖\boldsymbol{u} largest in absolute value Β  (truncation step)
  7. Β Β Β Β  𝒖←𝒖/βˆ₯𝒖βˆ₯2\boldsymbol{u} \leftarrow \boldsymbol{u} / \|\boldsymbol{u}\|_2
  8. Β Β  until 𝒖\boldsymbol{u} converges
  9. Β Β  if π’–βŠ€πšΊΜƒπ’–>𝒖bestβŠ€πšΊΜƒπ’–best\boldsymbol{u}^\top \tilde{\boldsymbol{\Sigma}} \boldsymbol{u} > \boldsymbol{u}_{\mathrm{best}}^\top \tilde{\boldsymbol{\Sigma}} \boldsymbol{u}_{\mathrm{best}}then 𝒖best←𝒖\boldsymbol{u}_{\mathrm{best}} \leftarrow \boldsymbol{u}; reset iteration count
  10. until time limit TT exceeded or no improvement after LTPML_{\mathrm{TPM}} iterations
  11. return 𝒖best\boldsymbol{u}_{\mathrm{best}}

The scheme resembles an iterative deflation procedure (Mackey 2008) in which a single-component sparse PCA problem is solved against a surrogate matrix at each iteration. The key difference is that the deflated matrix is induced by an explicit penalty on the non-redundancy constraints, which is progressively increased throughout the algorithm.

Implementation details

Penalty update. The penalty parameters Ξ»t,tβ€²\lambda_{t,t'} are initialized to zero and increased progressively across outer iterations, letting the algorithm explore freely at first and gradually tightening the feasibility requirement. During the first 15% of iterations the increment is proportional to the total constraint violation βˆ‘t>tβ€²|𝒖t⊀π‘ͺ𝒖tβ€²|\sum_{t > t'} |\boldsymbol{u}_t^\top \boldsymbol{C} \boldsymbol{u}_{t'}|; for the remaining iterations we switch to a ratio-based update proportional to the ratio of the current objective to the current constraint violation, which produces larger and more decisive increases; during the last 25% of iterations the step-size coefficient is further increased by a factor of 5 to accelerate final convergence to feasibility. See Cory-Wright and Pauphilet (2026) for a full description and theoretical justification of the update rule.

Penalty weights. We write Ξ»t,tβ€²=Ξ»wtβ€²\lambda_{t,t'} = \lambda \, w_{t'}, with a single scalar Ξ»\lambda carrying the schedule above and a per-component weight wtβ€²w_{t'} fixed at the first iteration. The weight is

wt=𝒖tβŠ€πšΊπ’–tβˆ₯π‘ͺ𝒖tβˆ₯22,w_{t} = \frac{\boldsymbol{u}_t^\top \boldsymbol{\Sigma} \boldsymbol{u}_t} {\|\boldsymbol{C} \boldsymbol{u}_t\|_2^2},

the same expression for both constraint types. Its effect is that the penalty a component can contribute is bounded by Ξ»wtβ€²βˆ₯π‘ͺ𝒖tβ€²βˆ₯22=λ𝒖tβ€²βŠ€πšΊπ’–tβ€²\lambda \, w_{t'} \|\boldsymbol{C} \boldsymbol{u}_{t'}\|_2^2 = \lambda \, \boldsymbol{u}_{t'}^\top \boldsymbol{\Sigma} \boldsymbol{u}_{t'}, i.e.Β Ξ»\lambda times the variance that component explains, whichever π‘ͺ\boldsymbol{C} is in force. The scalar Ξ»\lambda is thus a dimensionless penalty-to-objective ratio and the schedule behaves the same way under both constraints. Under orthogonality π‘ͺ=𝕀\boldsymbol{C} = \mathbb{I} and βˆ₯𝒖tβˆ₯2=1\|\boldsymbol{u}_t\|_2 = 1, so wtw_t is simply the variance explained by component tt; under zero correlation π‘ͺ=𝚺/tr(𝚺)\boldsymbol{C} = \boldsymbol{\Sigma}/\mathrm{tr}(\boldsymbol{\Sigma}) and the 1/βˆ₯π‘ͺ𝒖tβˆ₯221/\|\boldsymbol{C} \boldsymbol{u}_t\|_2^2 factor offsets the shrinkage that normalizing 𝚺\boldsymbol{\Sigma} by its trace would otherwise apply to the penalty. Numerator and denominator are homogeneous of the same degree in 𝚺\boldsymbol{\Sigma}, so the weights are invariant to a rescaling of the data. With this weight the PSD shift of the previous section also takes the common form Ξ»0=Ξ»βˆ‘tβ€²β‰ t𝒖tβ€²βŠ€πšΊπ’–tβ€²\lambda_0 = \lambda \sum_{t' \neq t} \boldsymbol{u}_{t'}^\top \boldsymbol{\Sigma} \boldsymbol{u}_{t'}.

Termination. Algorithm 1 stops when the number of outer iterations reaches maxIter (default 200), or earlier at any iteration where the current solution is feasible and the change in objective value since the previous iteration falls below stallingTolerance (default 1e-8).

Feasibility tracking. At each iteration Algorithm 1 checks whether the current solution satisfies the coupling constraint up to feasibilityTolerance (default 1e-4). The best feasible solution encountered across all iterations is returned. If no feasible solution is found within the iteration budget, the algorithm returns the solution with the smallest observed constraint violation.

Software implementation. All computations are carried out in C++ via the Rcpp (Eddelbuettel and FranΓ§ois 2011) and RcppEigen (Bates and Eddelbuettel 2013) interfaces, with a lightweight R wrapper providing the user-facing API. To avoid materializing the pΓ—pp \times p perturbed matrix πšΊΜƒt\tilde{\boldsymbol{\Sigma}}_t at each inner-loop step, the C++ back-end represents it implicitly: each product πšΊΜƒt𝜷\tilde{\boldsymbol{\Sigma}}_t \boldsymbol{\beta} is evaluated as

πšΊπœ·βˆ’π‘Ύ(π’…βŠ™π‘ΎβŠ€πœ·)+Ξ»0𝜷,\boldsymbol{\Sigma}\boldsymbol{\beta} - \boldsymbol{W}(\boldsymbol{d} \odot \boldsymbol{W}^\top \boldsymbol{\beta}) + \lambda_0 \boldsymbol{\beta},

where 𝑾\boldsymbol{W} collects the previously computed components (𝒖tβ€²\boldsymbol{u}_{t'}, tβ€²β‰ tt' \neq t for orthogonal loadings; π‘ͺ𝒖tβ€²=πšΊπ’–tβ€²/tr(𝚺)\boldsymbol{C} \boldsymbol{u}_{t'} = \boldsymbol{\Sigma} \boldsymbol{u}_{t'} / \mathrm{tr}(\boldsymbol{\Sigma}), tβ€²β‰ tt' \neq t, for uncorrelated PCs) and 𝒅\boldsymbol{d} contains the corresponding scaled penalty coefficients. This eliminates the O(rp2)O(r p^2) matrix-build cost per component update while keeping the per-step cost at O(p2)O(p^2).

When the raw data matrix 𝑿\boldsymbol{X} is provided (type = "X"), the product 𝚺𝜷\boldsymbol{\Sigma}\boldsymbol{\beta} is replaced by the two-pass evaluation π‘ΏβŠ€(π‘Ώπœ·)/(nβˆ’1)\boldsymbol{X}^\top(\boldsymbol{X}\boldsymbol{\beta})/(n-1) at cost O(np)O(np) instead of O(p2)O(p^2), which is substantially more scalable when nβ‰ͺpn \ll p and avoids forming the pΓ—pp \times p covariance matrix entirely. After the first outer iteration the previous iterate serves as a warm start for Algorithm 2, substantially reducing the number of random restarts required.

Computational complexity

The dominant cost of Algorithm 1 per outer iteration is rr calls to Algorithm 2. With the implicit matrix-vector representation above, applying πšΊΜƒt\tilde{\boldsymbol{\Sigma}}_t to a vector costs O(p2+rp)O(p^2 + rp) with type = "Sigma" and O(np+rp)O(np + rp) with type = "X". In both cases the O(rp)O(rp) deflation term is negligible for moderate rr. Each call performs at most LTPML_{\mathrm{TPM}} such products, giving a worst-case per-outer-iteration cost of O(rmin⁑(n,p)pβ‹…LTPM)O(r \min(n,p) p \cdot L_{\mathrm{TPM}}). In practice, warm-start initialization and early convergence detection reduce the effective number of TPM iterations substantially, so the empirical cost is much closer to O(rmin⁑(n,p)p)O(r \min(n,p) p) per outer iteration.

Guidance on parameter choices

Choosing the sparsity budgets ks

The budgets k1,…,krk_1, \ldots, k_r are the primary tuning parameters. A practical approach is to run mspca() over a range of values and plot the trade-off between FVE and sparsity:

library("msPCA")
Sigma <- cor(datasets::mtcars)

ks_grid <- seq(2, 10, by = 1)
trade_off <- sapply(ks_grid, function(k) {
  set.seed(42)
  res <- mspca(Sigma, r = 3, ks = rep(k, 3), verbose = FALSE)
  fraction_variance_explained(Sigma, res$x_best)
})
plot(ks_grid, trade_off, type = "b",
     xlab = "sparsity budget k", ylab = "fraction of variance explained")

Domain knowledge often provides a natural guide: if each PC is expected to represent a distinct thematic cluster of features, setting ktk_t to the anticipated cluster size is a good starting point.

Choosing the constraint type

Orthogonality (feasibilityConstraintType = 0) is appropriate when the loading vectors are to be used as a projection basis, or when the geometric structure of the components matters. Zero pairwise correlation (feasibilityConstraintType = 1) is preferable when the primary goal is statistical decorrelation of the projected data. In our experience the two options yield similar results when 𝚺\boldsymbol{\Sigma} is close to the identity, but can differ noticeably for strongly correlated datasets. See vignette("case-study-snp500", package = "msPCA") for a worked comparison.

Both sets of pairwise violations are computed at fit time and stored in nonredundancy, so a solution can be scored under the definition that was not enforced without a refit:

res <- mspca(Sigma, r = 3, ks = rep(5, 3), feasibilityConstraintType = 1, verbose = FALSE)
summary(res)                            # zero-correlation violations, as fitted
res$nonredundancy$orthogonality         # how far the same solution is from orthogonal

Iteration and restart budgets

maxIter (default 200) caps the number of outer iterations. Lowering it speeds up large problems at some risk of returning a less-refined solution; the case study uses maxIter = 100 on a 423-variable problem without noticeable loss. maxRestartTPM and minRestartTPM control the number of random restarts in the inner TPM call at the first and subsequent outer iterations respectively; the defaults (30 and 20) are conservative and can be reduced when runtime matters more than guarding against poor local optima.

References

Bates, Douglas, and Dirk Eddelbuettel. 2013. β€œFast and Elegant Numerical Linear Algebra Using the RcppEigen Package.” Journal of Statistical Software 52 (5): 1–24.
Behdin, Kayhan, and Rahul Mazumder. 2026. β€œSparse PCA: A New Scalable Estimator Based on Integer Programming.” Annals of Statistics.
Benidis, Konstantinos, Ying Sun, Prabhu Babu, and Daniel P. Palomar. 2016. β€œOrthogonal Sparse PCA and Covariance Estimation via Procrustes Reformulation.” IEEE Transactions on Signal Processing 64 (23): 6211–26.
Berk, Lauren, and Dimitris Bertsimas. 2019. β€œCertifiably Optimal Sparse Principal Component Analysis.” Mathematical Programming Computation 11 (3): 381–420.
Bertsimas, Dimitris, Ryan Cory-Wright, and Jean Pauphilet. 2022. β€œSolving Large-Scale Sparse PCA to Certifiable (Near) Optimality.” Journal of Machine Learning Research 23 (13): 1–35.
Cory-Wright, Ryan, and Jean Pauphilet. 2026. β€œSparse PCA with Multiple Components.” Operations Research. https://doi.org/10.1287/opre.2023.0598.
d’Aspremont, Alexandre, Laurent El Ghaoui, Michael I. Jordan, and Gert R. G. Lanckriet. 2007. β€œA Direct Formulation for Sparse PCA Using Semidefinite Programming.” SIAM Review 49 (3): 434–48.
Eddelbuettel, Dirk, and Romain FranΓ§ois. 2011. β€œRcpp: Seamless R and C++ Integration.” Journal of Statistical Software 40 (8): 1–18.
JournΓ©e, Michel, Yurii Nesterov, Peter RichtΓ‘rik, and Rodolphe Sepulchre. 2010. β€œGeneralized Power Method for Sparse Principal Component Analysis.” Journal of Machine Learning Research 11 (2): 517–53.
Lu, Zhaosong, and Yong Zhang. 2012. β€œAn Augmented Lagrangian Approach for Sparse Principal Component Analysis.” Mathematical Programming 135: 149–93.
Mackey, Lester. 2008. β€œDeflation Methods for Sparse PCA.” Advances in Neural Information Processing Systems 21.
Vu, Vincent Q., Juhee Cho, Jing Lei, and Karl Rohe. 2013. β€œFantope Projection and Selection: A Near-Optimal Convex Relaxation of Sparse PCA.” Advances in Neural Information Processing Systems 26.
Yuan, Xiao-Tong, and Tong Zhang. 2013. β€œTruncated Power Method for Sparse Eigenvalue Problems.” Journal of Machine Learning Research 14 (4): 899–925.
Zou, Hui, Trevor Hastie, and Robert Tibshirani. 2006. β€œSparse Principal Component Analysis.” Journal of Computational and Graphical Statistics 15 (2): 265–86.