| Title: | Identify Loading Vectors under Sparsity in Factor Models |
|---|---|
| Description: | Simplify the loading matrix in factor models using the l1 criterion as proposed in Freyaldenhoven (2025) <doi:10.21799/frbp.wp.2020.25>. Given a data matrix, find the rotation of the loading matrix with the smallest l1-norm and/or test for the presence of local factors with main function local_factors(). |
| Authors: | Simon Freyaldenhoven [aut, cph], Ryan Kobler [aut, cre] |
| Maintainer: | Ryan Kobler <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.0.2 |
| Built: | 2026-05-19 05:58:23 UTC |
| Source: | https://github.com/simonfreyaldenhoven/l1rotation |
Example data with two factors from the replication files of Freyaldenhoven (2025).
example_dataexample_data
example_dataA matrix with 224 rows and 207 columns.
Dataset available as a .mat file can be found under local_factors.zip at https://simonfreyaldenhoven.github.io/software/
local_factors(), with additional flexibility.Find the most sparse rotation of an orthonormal basis of the loading space of a t by n matrix X. Additional flexibility with the initial_loadings argument allows the user to specify any orthonormal basis rather than defaulting to PCA.
find_local_factors(X, r, initial_loadings, parallel = FALSE, n_cores = NULL)find_local_factors(X, r, initial_loadings, parallel = FALSE, n_cores = NULL)
X |
A (usually standardized) t by n matrix of observations. |
r |
An integer denoting the number of factors in X. |
initial_loadings |
Matrix that represents an orthonormal basis of the loading space. If not supplied, PCA is used by default in this function and also in |
parallel |
A logical denoting whether the algorithm should be run in parallel. |
n_cores |
An integer denoting how many cores should be used, if parallel == TRUE. |
Returns a list with the following components:
initial_loadings Principal Component estimate of the loading matrix (if not supplied).
rotated_loadings Matrix that is the rotation of the loading matrix that produces the smallest l1-norm.
rotation_diagnostics A list containing 3 components:
R Rotation matrix that when used to rotate initial_loadings produces the smallest l1-norm.
l1_norm Vector of length r containing the value of the l1 norm each solution generates.
sol_frequency Vector of length r containing the frequency in the initial grid of each solution.
# Minimal example with 2 factors, where X is a 224 by 207 matrix r <- 2 M <- nrow(example_data) n <- ncol(example_data) # Compute PCA estimates basis <- svd(example_data / sqrt(M), nu = M, nv = n) initial_loadings <- sqrt(n) * basis$v[, 1:r] # Find minimum rotation using orthonormal basis initial_loadings rotation_result <- find_local_factors(X = example_data, r = r, initial_loadings = initial_loadings)# Minimal example with 2 factors, where X is a 224 by 207 matrix r <- 2 M <- nrow(example_data) n <- ncol(example_data) # Compute PCA estimates basis <- svd(example_data / sqrt(M), nu = M, nv = n) initial_loadings <- sqrt(n) * basis$v[, 1:r] # Find minimum rotation using orthonormal basis initial_loadings rotation_result <- find_local_factors(X = example_data, r = r, initial_loadings = initial_loadings)
local_factors tests whether local factors are present and returns both the Principal Component estimate of the loadings and the rotation of the loadings with the smallest l1-norm. It also produces graphical illustrations of the results.
local_factors(X, r, parallel = FALSE, n_cores = NULL)local_factors(X, r, parallel = FALSE, n_cores = NULL)
X |
A (usually standardized) t by n matrix of observations. |
r |
An integer denoting the number of factors in X. |
parallel |
A logical denoting whether the algorithm should be run in parallel. |
n_cores |
An integer denoting how many cores should be used, if parallel == TRUE. |
Returns a list with the following components:
has_local_factors A logical equal to TRUE if local factors are present.
initial_loadings Principal component estimate of the loading matrix.
rotated_loadings Matrix that is the rotation of the loading matrix that produces the smallest l1-norm.
rotation_diagnostics A list containing 3 components:
R Rotation matrix that when used to rotate initial_loadings produces the smallest l1-norm.
l1_norm Vector of length r containing the value of the l1 norm each solution generates.
sol_frequency Vector of length r containing the frequency in the initial grid of each solution.
pc_plot Tile plot of the Principal Component estimate of the loading matrix.
rotated_plot Tile plot of the l1-rotation of the loading matrix estimate.
small_loadings_plot Plot of the number of small loadings for each column of the l1-rotation of the loading matrix estimate.
# Minimal example with 2 factors, where X is a 224 by 207 matrix lf <- local_factors(X = example_data, r = 2) # Visualize Principal Component estimate of the loadings lf$pc_plot # Visualize l1-rotation loadings lf$pc_rotated_plot# Minimal example with 2 factors, where X is a 224 by 207 matrix lf <- local_factors(X = example_data, r = 2) # Visualize Principal Component estimate of the loadings lf$pc_plot # Visualize l1-rotation loadings lf$pc_rotated_plot
local_factors(), with additional flexibility.Test for the presence of local factors, as in local_factors(), with additional flexibility.
test_local_factors(X, r, loadings = NULL)test_local_factors(X, r, loadings = NULL)
X |
A (usually standardized) t by n matrix of observations. |
r |
An integer denoting the number of factors in X. |
loadings |
(optional) Matrix that represents a sparse basis of the loading space. |
Returns a list with the following components:
has_local_factors Logical equal to TRUE if local factors are present.
n_small Integer denoting the number of small loadings in sparse rotation.
gamma_n Integer denoting the critical value to compare n_small to.
h_n Number denoting the cutoff used to determine which loadings are small.
loadings Matrix that is the rotation of the loadings that produces the smallest l1-norm (if not supplied).
# Minimal example with 2 factors, where X is a 224 by 207 matrix r <- 2 M <- nrow(example_data) n <- ncol(example_data) # Find minimum rotation rotation_result <- find_local_factors(X = example_data, r) # Test if sparse basis has local factors test_result <- test_local_factors( X = example_data, r = r, loadings = rotation_result$rotated_loadings ) test_result$has_local_factors# Minimal example with 2 factors, where X is a 224 by 207 matrix r <- 2 M <- nrow(example_data) n <- ncol(example_data) # Find minimum rotation rotation_result <- find_local_factors(X = example_data, r) # Test if sparse basis has local factors test_result <- test_local_factors( X = example_data, r = r, loadings = rotation_result$rotated_loadings ) test_result$has_local_factors