| Title: | Mixture-Based Muscle Synergy Analysis |
|---|---|
| Description: | Provides tools for analyzing muscle synergy using various statistical methods including MPCA and MFA. Enables researchers to identify distinct subgroups within populations that exhibit different muscle synergy patterns, rather than forcing all subjects into a single global model. |
| Authors: | Yusuke Matsui [aut, cre] |
| Maintainer: | Yusuke Matsui <[email protected]> |
| License: | GPL-3 + file LICENSE |
| Version: | 1.0.0 |
| Built: | 2026-10-11 16:08:15 UTC |
| Source: | https://github.com/matsui-lab/synergyMixR |
Collects and combines results from individual PBS array job tasks.
aggregate_partial_results( output_dir, pattern = "result_.*\\.rds$", remove_partial = FALSE, verbose = TRUE )aggregate_partial_results( output_dir, pattern = "result_.*\\.rds$", remove_partial = FALSE, verbose = TRUE )
output_dir |
Character. Directory containing partial results. |
pattern |
Character. Regex pattern for result files. |
remove_partial |
Logical. If TRUE, remove partial result files after aggregation. |
verbose |
Logical. Print progress messages. |
Data frame with combined results, or NULL if no results found.
## Not run: # After PBS jobs complete results <- aggregate_partial_results("results_sweep_modelsel") # View results head(results) ## End(Not run)## Not run: # After PBS jobs complete results <- aggregate_partial_results("results_sweep_modelsel") # View results head(results) ## End(Not run)
Finds the optimal mapping from estimated cluster labels to true cluster labels using the Hungarian algorithm. This resolves the label switching problem inherent in clustering.
align_clusters_to_truth(z_true, z_hat)align_clusters_to_truth(z_true, z_hat)
z_true |
Integer vector of true cluster assignments (1 to K_true). |
z_hat |
Integer vector of estimated cluster assignments (1 to K_hat). |
The Hungarian algorithm (via clue::solve_LSAP) finds the assignment
that maximizes the overlap between estimated and true clusters. This is
essential for fair evaluation of clustering methods where label identities
are arbitrary.
When K_hat != K_true, the algorithm handles the mismatch by:
If K_hat < K_true: Some true clusters may not have a match
If K_hat > K_true: Some estimated clusters map to the same true cluster
A list with:
mappingNamed integer vector where names are estimated labels and values are corresponding true labels.
z_alignedInteger vector of aligned estimated labels (same length as z_hat, with labels remapped to match z_true).
accuracyNumeric scalar: proportion of correctly matched assignments after alignment.
Returns a list with all NA values if inputs are invalid.
## Not run: z_true <- c(1, 1, 1, 2, 2, 2, 3, 3, 3) z_hat <- c(3, 3, 3, 1, 1, 1, 2, 2, 2) # Labels are permuted result <- align_clusters_to_truth(z_true, z_hat) result$accuracy # Should be 1.0 (perfect after alignment) ## End(Not run)## Not run: z_true <- c(1, 1, 1, 2, 2, 2, 3, 3, 3) z_hat <- c(3, 3, 3, 1, 1, 1, 2, 2, 2) # Labels are permuted result <- align_clusters_to_truth(z_true, z_hat) result$accuracy # Should be 1.0 (perfect after alignment) ## End(Not run)
After running rotate_mfa_model or any rotation, each factor's
sign can be arbitrary. This function enforces a rule such as:
"The variable with the largest absolute loading in each factor must be positive."
Then, if that factor's column is flipped, we also flip the corresponding column
in the factor scores, to keep the model consistent.
align_factor_signs_mfa(mfa_fit, method = c("max_abs"), cluster_ids = NULL)align_factor_signs_mfa(mfa_fit, method = c("max_abs"), cluster_ids = NULL)
mfa_fit |
A fitted MFA model (with |
method |
A string specifying how to choose the sign. Currently only
|
cluster_ids |
Which clusters to process. Defaults to all. |
- For each cluster k, we loop over each factor (column). We find the row
index i_max that has the largest absolute loading. If
Lambda[k][i_max, factor] < 0, we multiply that entire column by -1.
- If factor_scores is present, we also multiply the corresponding column
in each subject's factor score by -1 to maintain consistency.
- This doesn't change the model fit or BIC, just the sign convention.
The same mfa_fit object, but with possibly flipped signs in
Lambda columns and factor_scores columns.
Similar to align_factor_signs_mfa, but for a Mixture PCA model
whose loadings are in W[[k]].
align_factor_signs_mpca(mpca_fit, method = c("max_abs"), cluster_ids = NULL)align_factor_signs_mpca(mpca_fit, method = c("max_abs"), cluster_ids = NULL)
mpca_fit |
A fitted MPCA model (with |
method |
A string specifying how to choose the sign. Defaults to |
cluster_ids |
Which clusters to process. Defaults to all. |
- For each cluster k, we loop over each factor (column) in W[[k]].
If the entry with largest absolute loading is negative, we multiply that entire column by -1.
- If factor_scores is present, we also multiply the corresponding column
in each subject's factor scores by -1.
The same mpca_fit object, but with possibly flipped signs in
W columns and factor_scores columns (if present).
Performs k-means clustering on subject-level features to obtain initial cluster assignments for mixture model fitting.
assign_by_kmeans(features, K)assign_by_kmeans(features, K)
features |
An |
K |
Number of clusters to create. |
This function uses the standard k-means algorithm with 10 random starts
(nstart=10) to find a stable clustering solution. The resulting
cluster assignments can be used as initial values for EM algorithms in
mixture models.
An integer vector of length N containing cluster labels (1..K).
Each element indicates which cluster the corresponding subject is assigned to.
## Not run: # Create example features features <- matrix(rnorm(100), nrow = 10, ncol = 10) # Assign to 3 clusters z_init <- assign_by_kmeans(features, K = 3) table(z_init) # Check cluster sizes ## End(Not run)## Not run: # Create example features features <- matrix(rnorm(100), nrow = 10, ncol = 10) # Assign to 3 clusters z_init <- assign_by_kmeans(features, K = 3) table(z_init) # Check cluster sizes ## End(Not run)
Applies a bandpass filter to EMG signals to extract the frequency band of interest (typically 20-450 Hz for surface EMG).
bandpass_filter( data, sampling_rate, low_cutoff = 20, high_cutoff = 450, filter_order = 4, filter_type = "butterworth", zero_phase = TRUE )bandpass_filter( data, sampling_rate, low_cutoff = 20, high_cutoff = 450, filter_order = 4, filter_type = "butterworth", zero_phase = TRUE )
data |
EMG signal. Can be a numeric vector (single channel), a matrix (T x M, time x channels), or a list of matrices. |
sampling_rate |
Sampling frequency in Hz. |
low_cutoff |
Lower cutoff frequency in Hz. Default is 20 Hz. |
high_cutoff |
Upper cutoff frequency in Hz. Default is 450 Hz. |
filter_order |
Filter order. Default is 4 (creates 4th order filter, 8th order effective with zero-phase filtering). |
filter_type |
Type of filter: |
zero_phase |
Logical. If TRUE (default), applies zero-phase filtering (forward-backward filtering) to avoid phase distortion. |
The bandpass filter removes:
Low-frequency noise and motion artifacts (below low_cutoff)
High-frequency noise (above high_cutoff)
Standard EMG bandwidth is 20-450 Hz for surface EMG. The lower cutoff helps remove motion artifacts, while the upper cutoff prevents aliasing and removes high-frequency noise.
Filtered EMG signal, same structure as input.
## Not run: # Generate sample EMG-like signal fs <- 1000 # 1000 Hz sampling rate t <- seq(0, 1, by = 1/fs) emg <- rnorm(length(t)) + 0.1 * sin(2 * pi * 10 * t) # with low-freq noise # Apply bandpass filter filtered <- bandpass_filter(emg, sampling_rate = fs) ## End(Not run)## Not run: # Generate sample EMG-like signal fs <- 1000 # 1000 Hz sampling rate t <- seq(0, 1, by = 1/fs) emg <- rnorm(length(t)) + 0.1 * sin(2 * pi * 10 * t) # with low-freq noise # Apply bandpass filter filtered <- bandpass_filter(emg, sampling_rate = fs) ## End(Not run)
Computes bootstrap confidence intervals for the loading matrices in mixture PCA or mixture FA models. Uses Procrustes alignment to ensure bootstrap samples are comparable across resamples.
bootstrap_loading_ci( list_of_data, K, r, B = 200, alpha = 0.05, mc_cores = 1, model_type = c("MPCA", "MFA"), max_iter = 50, n_init = 1, use_kmeans_init = TRUE, seed = NULL, verbose = TRUE )bootstrap_loading_ci( list_of_data, K, r, B = 200, alpha = 0.05, mc_cores = 1, model_type = c("MPCA", "MFA"), max_iter = 50, n_init = 1, use_kmeans_init = TRUE, seed = NULL, verbose = TRUE )
list_of_data |
A list of N matrices, each of dimension (T_i x M), containing the observed EMG data. |
K |
Integer. Number of clusters. |
r |
Integer. Number of synergies (factors/principal components). |
B |
Integer. Number of bootstrap iterations. Default: 200. |
alpha |
Numeric. Significance level for confidence intervals. Default: 0.05 (95% CI). |
mc_cores |
Integer. Number of cores for parallel computation. Default: 1 (sequential). |
model_type |
Character. Either "MPCA" or "MFA". Default: "MPCA". |
max_iter |
Integer. Maximum EM iterations per fit. Default: 50. |
n_init |
Integer. Number of random initializations. Default: 1. |
use_kmeans_init |
Logical. Whether to use k-means initialization. Default: TRUE. |
seed |
Integer. Random seed for reproducibility. Default: NULL. |
verbose |
Logical. Print progress messages. Default: TRUE. |
The bootstrap procedure: 1. Fit the model to the full dataset to obtain reference loadings 2. For each bootstrap iteration b = 1, ..., B: a. Resample subjects with replacement b. Fit the model to the bootstrap sample c. Align bootstrap loadings to reference using Procrustes rotation 3. Compute percentile confidence intervals from aligned samples
Procrustes alignment is essential because factor loadings are only identifiable up to rotation and sign. Without alignment, bootstrap samples would not be comparable, leading to inflated variance estimates.
A list with the following elements:
List of K matrices (M x r), median loadings for each cluster
List of K matrices (M x r), lower CI bound for each cluster
List of K matrices (M x r), upper CI bound for each cluster
List of K matrices (M x r), standard errors for each cluster
Array of dimension (B x K x M x r) containing all aligned bootstrap samples (optional, if return_samples=TRUE)
The reference model fit used for alignment
Number of successful bootstrap iterations
The significance level used
For each cluster k, the bootstrap loading matrix W_k(b) is aligned to the reference W_k using orthogonal Procrustes: W_aligned(b) = W_k(b) R* where R* minimizes ||W_k - W_k(b) R||_F subject to R'R = I.
The optimal R is found via SVD: if W_k' W_k(b) = UDV', then R* = VU'.
mixture_pca_em_fit, mfa_em_fit
## Not run: # Simulate some data sim <- simulate_dynamic_synergy_data(N = 50, K = 2, r = 3, M = 8, T_each = 100) # Compute bootstrap CIs boot_ci <- bootstrap_loading_ci( list_of_data = sim$X_list, K = 2, r = 3, B = 100, alpha = 0.05, mc_cores = 4 ) # View median loadings for cluster 1 print(boot_ci$loadings_median[[1]]) # View 95% CI width for first synergy, first muscle, cluster 1 width <- boot_ci$loadings_upper[[1]][1,1] - boot_ci$loadings_lower[[1]][1,1] print(width) ## End(Not run)## Not run: # Simulate some data sim <- simulate_dynamic_synergy_data(N = 50, K = 2, r = 3, M = 8, T_each = 100) # Compute bootstrap CIs boot_ci <- bootstrap_loading_ci( list_of_data = sim$X_list, K = 2, r = 3, B = 100, alpha = 0.05, mc_cores = 4 ) # View median loadings for cluster 1 print(boot_ci$loadings_median[[1]]) # View 95% CI width for first synergy, first muscle, cluster 1 width <- boot_ci$loadings_upper[[1]][1,1] - boot_ci$loadings_lower[[1]][1,1] print(width) ## End(Not run)
Uses the final hard assignments mfa_fit$z, reconstruct each subject's data.
calc_reconstruction_error_mixtureFA(list_of_data, mfa_fit)calc_reconstruction_error_mixtureFA(list_of_data, mfa_fit)
list_of_data |
The data list. |
mfa_fit |
The mixture FA result, which contains |
SSE (sum of squared errors).
Compute SSE for a MixturePCA model
calc_reconstruction_error_mixturePCA(list_of_data, mpca_fit)calc_reconstruction_error_mixturePCA(list_of_data, mpca_fit)
list_of_data |
The data list. |
mpca_fit |
The mixture PCA result, containing |
SSE (sum of squared errors).
Compute Total Reconstruction SSE for Single FA
calc_reconstruction_error_singleFA(list_of_data, fa_res)calc_reconstruction_error_singleFA(list_of_data, fa_res)
list_of_data |
The original data list. |
fa_res |
A result from |
A numeric value of the sum of squared errors (SSE).
Compute Total Reconstruction SSE for Single PCA
calc_reconstruction_error_singlePCA(list_of_data, pca_res)calc_reconstruction_error_singlePCA(list_of_data, pca_res)
list_of_data |
The data list. |
pca_res |
The result from |
SSE (sum of squared errors).
This function concatenates all matrices in list_of_data into one big matrix,
calculates the global mean, and then sums the squared differences from that mean.
The result can be used to compute VAF (Variance Accounted For).
calc_total_SST(list_of_data)calc_total_SST(list_of_data)
list_of_data |
A list of |
A numeric scalar, the total sum of squares (SST).
Convenience function that extracts responsibilities from a fitted model and computes calibration against true labels.
calibrate_model(fit, z_true, n_bins = 10)calibrate_model(fit, z_true, n_bins = 10)
fit |
Fitted mixture model object (MFA or MPCA) |
z_true |
Integer vector of true cluster labels |
n_bins |
Number of bins for calibration. Default: 10. |
A calibration_result object
## Not run: # Fit model fit <- mixture_pca_em_fit(list_of_data, K = 3, r = 2) # Compute calibration calib <- calibrate_model(fit, z_true) print(calib) ## End(Not run)## Not run: # Fit model fit <- mixture_pca_em_fit(list_of_data, K = 3, r = 2) # Compute calibration calib <- calibrate_model(fit, z_true) print(calib) ## End(Not run)
Checks whether the future ecosystem packages are installed.
check_future_available(batchtools = FALSE)check_future_available(batchtools = FALSE)
batchtools |
Logical. Also check for future.batchtools. |
Logical. TRUE if packages are available.
Checks the status of a PBS job.
check_pbs_job_status(job_id)check_pbs_job_status(job_id)
job_id |
Character. PBS job ID. |
List with job status information.
## Not run: status <- check_pbs_job_status("12345") ## End(Not run)## Not run: status <- check_pbs_job_status("12345") ## End(Not run)
This function performs diagnostic checks to investigate SSE (Sum of Squared Errors) behavior in mixture model fits, particularly when SSE increases monotonically with latent dimension r. It examines three key aspects: EM convergence quality, noise variance (Psi) distribution, and VAF-SSE correlation.
check_SSE_diagnostics( fit_results, list_of_data, mixtureFA_fit = NULL, mixturePCA_fit = NULL, output_dir = NULL, psi_small_thresh = 0.01, psi_large_thresh = 100 )check_SSE_diagnostics( fit_results, list_of_data, mixtureFA_fit = NULL, mixturePCA_fit = NULL, output_dir = NULL, psi_small_thresh = 0.01, psi_large_thresh = 100 )
fit_results |
A data frame returned by |
list_of_data |
The original data used for fitting (list of N matrices, each T_i x M). Required for VAF-SSE correlation theoretical line calculation. |
mixtureFA_fit |
Optional fitted MFA model object. If NULL, will attempt to extract from fit_results attributes. If not available, EM convergence and Psi diagnostics for MFA will be skipped. |
mixturePCA_fit |
Optional fitted MPCA model object. If NULL, will attempt to extract from fit_results attributes. If not available, EM convergence and Psi diagnostics for MPCA will be skipped. |
output_dir |
Optional directory path where diagnostic plots will be saved. If NULL (default), plots are displayed on screen only. |
psi_small_thresh |
Threshold for detecting overfitting (Psi values below this). Default is 0.01. |
psi_large_thresh |
Threshold for detecting poor fit (Psi values above this). Default is 100. |
The function performs three main diagnostic checks:
1. EM Convergence Quality Check
Since the C++ EM implementation doesn't return a convergence trace, this check examines the final model quality by comparing log-likelihoods and checking for degenerate solutions (e.g., empty clusters, extreme parameter values).
2. Psi (Noise Variance) Distribution Check
Examines the distribution of noise variance parameters in both MFA and MPCA models. Extreme values (very small < 0.01 or very large > 100) may indicate:
Overfitting (Psi approaches 0)
Poor model fit (Psi approaches infinity)
Numerical instability
Creates histograms showing the distribution of Psi values across all clusters and muscles.
3. VAF-SSE Correlation Verification
Since VAF = 1 - SSE/SST, there should be a strong negative correlation (approximately -1) between VAF and SSE across methods. Deviations from this expected relationship may indicate:
Scaling inconsistencies in SSE calculation
Different SST values being used across methods
Numerical precision issues
Creates a scatter plot of VAF vs SSE with the expected theoretical relationship.
A list with diagnostic results:
convergence_okLogical; TRUE if convergence appears stable
psi_okLogical; TRUE if Psi values are in reasonable range
correlation_okLogical; TRUE if VAF-SSE correlation is strongly negative
warningsCharacter vector of warning messages
psi_summary_mfaSummary statistics for MFA Psi values
psi_summary_mpcaSummary statistics for MPCA Psi values
vaf_sse_correlationCorrelation coefficient between VAF and SSE
## Not run: # Example 1: Basic usage with fit_all_methods_on_data() # The fitted models are stored as attributes and automatically extracted sim_data <- simulate_mixture_data(N = 30, K = 3, r = 3, M = 8, T_each = 200, seed = 123) fit_results <- fit_all_methods_on_data( list_of_data = sim_data$list_of_data, z_true = sim_data$z_true, N = 30, K = 3, r = 3, M = 8, seed = 123 ) # Run diagnostics (fitted models extracted from attributes automatically) diagnostics <- check_SSE_diagnostics( fit_results = fit_results, list_of_data = sim_data$list_of_data, output_dir = "diagnostics" ) # Check results print(diagnostics$warnings) print(diagnostics$psi_summary_mfa) print(diagnostics$vaf_sse_correlation) # Example 2: Pass fitted models explicitly # Useful when you have fitted models from other sources mfa_fit <- mfa_em_fit(sim_data$list_of_data, K = 3, r = 3) mpca_fit <- mixture_pca_em_fit(sim_data$list_of_data, K = 3, r = 3) # Create a minimal results data frame results_df <- data.frame( Method = c("MixtureFA", "MixturePCA"), SSE = c(100, 120), VAF = c(0.85, 0.80) ) # Run diagnostics with explicit fitted models diagnostics2 <- check_SSE_diagnostics( fit_results = results_df, list_of_data = sim_data$list_of_data, mixtureFA_fit = mfa_fit, mixturePCA_fit = mpca_fit, output_dir = "diagnostics2", psi_small_thresh = 0.005, # Custom threshold psi_large_thresh = 200 # Custom threshold ) # Example 3: VAF-SSE correlation only (no fitted models) # Useful for quick checks without EM convergence/Psi diagnostics diagnostics3 <- check_SSE_diagnostics( fit_results = fit_results, list_of_data = sim_data$list_of_data ) # Note: EM convergence and Psi diagnostics will be skipped with a warning ## End(Not run)## Not run: # Example 1: Basic usage with fit_all_methods_on_data() # The fitted models are stored as attributes and automatically extracted sim_data <- simulate_mixture_data(N = 30, K = 3, r = 3, M = 8, T_each = 200, seed = 123) fit_results <- fit_all_methods_on_data( list_of_data = sim_data$list_of_data, z_true = sim_data$z_true, N = 30, K = 3, r = 3, M = 8, seed = 123 ) # Run diagnostics (fitted models extracted from attributes automatically) diagnostics <- check_SSE_diagnostics( fit_results = fit_results, list_of_data = sim_data$list_of_data, output_dir = "diagnostics" ) # Check results print(diagnostics$warnings) print(diagnostics$psi_summary_mfa) print(diagnostics$vaf_sse_correlation) # Example 2: Pass fitted models explicitly # Useful when you have fitted models from other sources mfa_fit <- mfa_em_fit(sim_data$list_of_data, K = 3, r = 3) mpca_fit <- mixture_pca_em_fit(sim_data$list_of_data, K = 3, r = 3) # Create a minimal results data frame results_df <- data.frame( Method = c("MixtureFA", "MixturePCA"), SSE = c(100, 120), VAF = c(0.85, 0.80) ) # Run diagnostics with explicit fitted models diagnostics2 <- check_SSE_diagnostics( fit_results = results_df, list_of_data = sim_data$list_of_data, mixtureFA_fit = mfa_fit, mixturePCA_fit = mpca_fit, output_dir = "diagnostics2", psi_small_thresh = 0.005, # Custom threshold psi_large_thresh = 200 # Custom threshold ) # Example 3: VAF-SSE correlation only (no fitted models) # Useful for quick checks without EM convergence/Psi diagnostics diagnostics3 <- check_SSE_diagnostics( fit_results = fit_results, list_of_data = sim_data$list_of_data ) # Note: EM convergence and Psi diagnostics will be skipped with a warning ## End(Not run)
This function enables pure method-level benchmarking by generating data using
only the v2 dynamic synergy simulator and applying all six analysis methods
(SingleFA, SinglePCA, TwoStep_FA, TwoStep_PCA, MixtureFA, MixturePCA).
This complements compare_static_vs_dynamic by focusing on
method performance rather than model comparison.
compare_baselines( N = 50, K = 2, r = 2, M = 6, T_each = 100, cluster_sep_spatial = 1, cluster_sep_temporal = 1, cluster_sep_stability = 1, seed = 123, n_init = 1, use_kmeans_init = FALSE, mc_cores = 1, method_pca = "EM", align_basis = TRUE, refine_assignments = TRUE )compare_baselines( N = 50, K = 2, r = 2, M = 6, T_each = 100, cluster_sep_spatial = 1, cluster_sep_temporal = 1, cluster_sep_stability = 1, seed = 123, n_init = 1, use_kmeans_init = FALSE, mc_cores = 1, method_pca = "EM", align_basis = TRUE, refine_assignments = TRUE )
N |
Number of subjects (time series). Default is 50. |
K |
Number of clusters. Default is 2. |
r |
Number of synergies (factor dimension). Default is 2. |
M |
Number of observed channels (muscles). Default is 6. |
T_each |
Time-series length per subject. Default is 100. |
cluster_sep_spatial |
Numeric scalar (0-2) controlling spatial structure differentiation between clusters. Higher values create more distinct spatial modules. Default is 1.0. |
cluster_sep_temporal |
Numeric scalar (0-2) controlling temporal coordination differentiation between clusters. Higher values create more distinct temporal patterns. Default is 1.0. |
cluster_sep_stability |
Numeric scalar (0-2) controlling stability-adaptability differentiation between clusters. Higher values create more distinct noise profiles. Default is 1.0. |
seed |
Random seed for data generation. Default is 123. |
n_init |
Number of random initializations for mixture methods. Default is 1. |
use_kmeans_init |
Logical; if TRUE, also try k-means initialization. Default is FALSE. |
mc_cores |
Number of cores for parallel computation. Default is 1. |
method_pca |
Method for PCA fitting. Default is "EM". |
align_basis |
Logical. If |
refine_assignments |
Logical. If |
This function generates data using simulate_dynamic_synergy_data
with three orthogonal control axes (spatial, temporal, stability), then applies
all six analysis methods to evaluate their performance. This is useful for:
Method benchmarking on realistic dynamic synergy data
Parameter sensitivity analysis for method performance
Integration with run_param_sweep for systematic evaluation
The function complements compare_static_vs_dynamic by focusing
on method performance rather than model comparison. Together, these functions
provide comprehensive evaluation of both models and methods.
A data frame with the following columns:
MethodAnalysis method name (e.g., "MixtureFA", "SinglePCA")
BICBayesian Information Criterion
ARIAdjusted Rand Index (clustering accuracy)
SSESum of Squared Errors (reconstruction error)
VAFVariance Accounted For (1 - SSE/totalSST)
model_typeAlways "Dynamic_v2" for this function
seedRandom seed used for data generation
cluster_sep_spatialSpatial separation parameter
cluster_sep_temporalTemporal separation parameter
cluster_sep_stabilityStability separation parameter
NNumber of subjects
KNumber of clusters
rNumber of synergies
MNumber of muscles
T_eachTime series length
compare_static_vs_dynamic for model comparison,
run_param_sweep for systematic parameter sweep,
simulate_dynamic_synergy_data for data generation
## Not run: # Basic method comparison on v2 data results <- compare_baselines( N = 50, K = 2, r = 2, M = 6, T_each = 100, cluster_sep_spatial = 1.0, cluster_sep_temporal = 1.0, cluster_sep_stability = 1.0, seed = 123 ) print(results) # Compare methods with high spatial separation results_spatial <- compare_baselines( N = 50, K = 2, r = 2, M = 6, T_each = 100, cluster_sep_spatial = 2.0, cluster_sep_temporal = 0.5, cluster_sep_stability = 1.0, seed = 456 ) # Visualize method performance library(ggplot2) ggplot(results, aes(x = Method, y = ARI)) + geom_bar(stat = "identity", fill = "steelblue") + labs(title = "Method Performance on v2 Dynamic Data") ## End(Not run)## Not run: # Basic method comparison on v2 data results <- compare_baselines( N = 50, K = 2, r = 2, M = 6, T_each = 100, cluster_sep_spatial = 1.0, cluster_sep_temporal = 1.0, cluster_sep_stability = 1.0, seed = 123 ) print(results) # Compare methods with high spatial separation results_spatial <- compare_baselines( N = 50, K = 2, r = 2, M = 6, T_each = 100, cluster_sep_spatial = 2.0, cluster_sep_temporal = 0.5, cluster_sep_stability = 1.0, seed = 456 ) # Visualize method performance library(ggplot2) ggplot(results, aes(x = Method, y = ARI)) + geom_bar(stat = "identity", fill = "steelblue") + labs(title = "Method Performance on v2 Dynamic Data") ## End(Not run)
This function uses the v2 dynamic synergy simulator
(simulate_dynamic_synergy_data), which provides three
orthogonal control axes: spatial structure, temporal coordination, and
stability-adaptability. This allows for systematic evaluation of how
different motor control strategies affect muscle synergy structures.
compare_static_vs_dynamic( model_types = c("Dynamic_v2"), N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 1, cluster_sep_temporal = 1, cluster_sep_stability = 1, seed = 123, output_dir = "results/compare_dynamic_v2", n_init = 1, use_kmeans_init = FALSE, mc_cores = 1 )compare_static_vs_dynamic( model_types = c("Dynamic_v2"), N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 1, cluster_sep_temporal = 1, cluster_sep_stability = 1, seed = 123, output_dir = "results/compare_dynamic_v2", n_init = 1, use_kmeans_init = FALSE, mc_cores = 1 )
model_types |
Character vector specifying which model types to use.
Default is |
N |
Number of subjects (time series). Default is 30. |
K |
True number of clusters. Default is 3. |
r |
True factor dimension (number of synergies). Default is 3. |
M |
Number of observed channels (muscles). Default is 8. |
T_each |
Time-series length per subject. Default is 200. |
cluster_sep_spatial |
Numeric scalar (0-2) controlling spatial structure differentiation between clusters. Higher values create more distinct spatial modules. Default is 1.0. |
cluster_sep_temporal |
Numeric scalar (0-2) controlling temporal coordination differentiation between clusters. Higher values create more distinct temporal patterns. Default is 1.0. |
cluster_sep_stability |
Numeric scalar (0-2) controlling stability-adaptability differentiation between clusters. Higher values create more distinct noise profiles. Default is 1.0. |
seed |
Random seed for data generation. Default is 123. |
output_dir |
Directory path where results will be saved. Default is
|
n_init |
Number of random initializations for mixture methods. Default is 1. |
use_kmeans_init |
Logical; if TRUE, also try k-means initialization. Default is FALSE. |
mc_cores |
Number of cores for parallel computation. Default is 1. |
The function generates data using the Dynamic_v2 model and applies six analysis methods (SingleFA, SinglePCA, TwoStep_FA, TwoStep_PCA, MixtureFA, MixturePCA) to evaluate their performance.
The function saves results to an RDS file in the specified output directory
with filename format results_YYYY-MM-DD.rds.
Data is generated using simulate_dynamic_synergy_data,
which creates time-varying synergy activation patterns with three orthogonal
control axes: (1) Spatial structure, (2) Temporal coordination, and
(3) Stability-Adaptability.
The generated data is analyzed using six methods, allowing comparison of method performance on realistic dynamic synergy data.
A data frame with the following columns:
model_typeCharacter string: "Dynamic_v2"
MethodAnalysis method name (e.g., "MixtureFA", "SinglePCA")
BICBayesian Information Criterion
ARIAdjusted Rand Index (clustering accuracy)
SSESum of Squared Errors (reconstruction error)
VAFVariance Accounted For (1 - SSE/totalSST)
seedRandom seed used for data generation
cluster_sep_spatialSpatial separation parameter
cluster_sep_temporalTemporal separation parameter
cluster_sep_stabilityStability separation parameter
NNumber of subjects
KNumber of clusters
rNumber of synergies
MNumber of muscles
T_eachTime series length
## Not run: # Basic comparison with v2 simulator results <- compare_static_vs_dynamic( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 1.0, cluster_sep_temporal = 1.0, cluster_sep_stability = 1.0, seed = 123 ) print(results) # Compare with high spatial separation results_spatial <- compare_static_vs_dynamic( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 2.0, cluster_sep_temporal = 0.5, cluster_sep_stability = 1.0, seed = 456 ) # Visualize results library(ggplot2) ggplot(results, aes(x = Method, y = ARI)) + geom_bar(stat = "identity", fill = "steelblue") + labs(title = "Method Performance on Dynamic v2 Data") ## End(Not run)## Not run: # Basic comparison with v2 simulator results <- compare_static_vs_dynamic( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 1.0, cluster_sep_temporal = 1.0, cluster_sep_stability = 1.0, seed = 123 ) print(results) # Compare with high spatial separation results_spatial <- compare_static_vs_dynamic( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 2.0, cluster_sep_temporal = 0.5, cluster_sep_stability = 1.0, seed = 456 ) # Visualize results library(ggplot2) ggplot(results, aes(x = Method, y = ARI)) + geom_bar(stat = "identity", fill = "steelblue") + labs(title = "Method Performance on Dynamic v2 Data") ## End(Not run)
Computes the Adjusted Rand Index between true and predicted cluster
assignments. This is a NA-safe wrapper around mclust::adjustedRandIndex.
compute_ari(true_cluster, pred_cluster)compute_ari(true_cluster, pred_cluster)
true_cluster |
Integer vector of true cluster assignments. |
pred_cluster |
Integer vector of predicted cluster assignments. |
The Adjusted Rand Index (ARI) measures the similarity between two clusterings, adjusted for chance. It is commonly used to evaluate clustering accuracy when ground truth is available.
Numeric scalar: ARI value in [-1, 1], where 1 indicates perfect agreement. Returns NA if inputs are invalid or mclust is not available.
## Not run: true_cluster <- c(1, 1, 1, 2, 2, 2, 3, 3, 3) pred_cluster <- c(1, 1, 2, 2, 2, 2, 3, 3, 3) ari <- compute_ari(true_cluster, pred_cluster) ## End(Not run)## Not run: true_cluster <- c(1, 1, 1, 2, 2, 2, 3, 3, 3) pred_cluster <- c(1, 1, 2, 2, 2, 2, 3, 3, 3) ari <- compute_ari(true_cluster, pred_cluster) ## End(Not run)
This function takes a data frame with a file column (typically from
read_all_results), reads each result file to extract fitted models,
computes VAF for MFA and MPCA, and joins these back to the input data frame.
compute_ari_vaf_table(df)compute_ari_vaf_table(df)
df |
A data frame with a |
The input data frame enriched with VAF_MFA and VAF_PCA columns.
If models are not available in a file, VAF values will be NA.
## Not run: df <- read_all_results("results") df <- compute_ari_vaf_table(df) head(df) ## End(Not run)## Not run: df <- read_all_results("results") df <- compute_ari_vaf_table(df) head(df) ## End(Not run)
Unified interface for computing BIC for both MFA and MPCA models.
compute_BIC(loglik, K, r, M, N_obs, model_type)compute_BIC(loglik, K, r, M, N_obs, model_type)
loglik |
Numeric scalar, the log-likelihood value |
K |
Integer, number of clusters |
r |
Integer, number of factors/synergies |
M |
Integer, number of variables (muscles) |
N_obs |
Integer, number of observations (total time points across subjects) |
model_type |
Character, either "MFA" or "MPCA" |
BIC = -2 * loglik + p * log(N_obs), where p is the number of parameters. The parameter count differs between MFA and MPCA due to different model structures.
A numeric scalar representing the BIC value (lower is better)
compute_BIC_mfa, compute_BIC_mpca
## Not run: # Compute BIC for an MFA model bic <- compute_BIC(loglik, K = 2, r = 3, M = 8, N_obs = 1000, model_type = "MFA") ## End(Not run)## Not run: # Compute BIC for an MFA model bic <- compute_BIC(loglik, K = 2, r = 3, M = 8, N_obs = 1000, model_type = "MFA") ## End(Not run)
Given the log-likelihood from compute_logLik_mfa, and known
K, r, M, N, this function computes
BIC = -2 * log(L) + nu * log(N),
where nu is the parameter count for the MFA model. The corrected formula is
nu = K * (M * r + r * (r-1)/2 + M + M) + (K - 1).
compute_BIC_mfa(loglik, K, r, M, N_obs)compute_BIC_mfa(loglik, K, r, M, N_obs)
loglik |
The total log-likelihood from |
K |
Number of clusters. |
r |
Factor dimension. |
M |
Observed dimension (channels). |
N_obs |
Number of observations (typically sum of all T_i across subjects). |
The parameter count includes:
M*r: factor loadings (Lambda)
r*(r-1)/2: factor covariances (off-diagonal elements)
M: unique variances (diagonal Psi)
M: cluster means (mu)
K-1: mixing proportions
This corrected formula properly penalizes larger r values, improving r estimation stability.
Note: N_obs should typically be the total number of time points (sum of T_i) rather than the number of subjects, as BIC penalizes based on sample size.
A numeric BIC value.
Given the log-likelihood from compute_logLik_mpca, and the
number of clusters K, dimension r, etc., this function
computes the corrected BIC:
BIC = -2 * log(L) + nu * log(N),
where nu is the parameter count for MPCA. The corrected formula is
K*(M*r + r*(r-1)/2 + M + 1) + (K-1), i.e. for each cluster
we have (M*r) for the directions, r*(r-1)/2 for factor covariances,
M for the mean, and 1 for sigma^2. Then (K-1) for mixing proportions.
compute_BIC_mpca(loglik, K, r, M, N_obs)compute_BIC_mpca(loglik, K, r, M, N_obs)
loglik |
The total mixture log-likelihood from |
K |
Number of clusters. |
r |
Dimension of principal components. |
M |
Observed dimension. |
N_obs |
Number of observations (typically sum of all T_i across subjects). |
The parameter count includes:
M*r: loading matrix (W or P)
r*(r-1)/2: factor covariances (off-diagonal elements)
M: cluster means (mu)
1: isotropic noise variance (sigma2)
K-1: mixing proportions
This corrected formula properly penalizes larger r values, improving r estimation stability.
Note: N_obs should typically be the total number of time points (sum of T_i) rather than the number of subjects, as BIC penalizes based on sample size.
A numeric BIC value.
Computes the Bayesian Information Criterion (BIC) for a fitted MFA or MPCA model. This is a unified wrapper that dispatches to the appropriate method-specific function.
compute_bic_wrapper(method, fit, K, r, M, N_obs)compute_bic_wrapper(method, fit, K, r, M, N_obs)
method |
Model type: "MFA" or "MPCA". |
fit |
A fitted model object. |
K |
Number of clusters. |
r |
Factor dimension. |
M |
Number of observed dimensions (muscles). |
N_obs |
Number of observations (typically sum of T_i). |
BIC is computed as , where L is the likelihood,
p is the number of parameters, and N is the sample size.
Numeric scalar: BIC value. Lower is better. Returns NA if computation fails.
## Not run: fit <- mfa_em_fit(list_of_data, K = 3, r = 2) N_obs <- sum(sapply(list_of_data, nrow)) M <- ncol(list_of_data[[1]]) bic <- compute_bic_wrapper("MFA", fit, K = 3, r = 2, M = M, N_obs = N_obs) ## End(Not run)## Not run: fit <- mfa_em_fit(list_of_data, K = 3, r = 2) N_obs <- sum(sapply(list_of_data, nrow)) M <- ncol(list_of_data[[1]]) bic <- compute_bic_wrapper("MFA", fit, K = 3, r = 2, M = M, N_obs = N_obs) ## End(Not run)
Computes calibration statistics by binning predicted probabilities and comparing to observed frequencies. This helps diagnose whether the model's probabilistic predictions are reliable.
compute_calibration(resp, z_true, n_bins = 10)compute_calibration(resp, z_true, n_bins = 10)
resp |
Matrix of responsibilities (N x K), where resp[i,k] is the posterior probability that subject i belongs to cluster k. Rows should sum to 1. |
z_true |
Integer vector of length N with true cluster labels (1 to K). If not available, can use hard cluster assignments from another method. |
n_bins |
Integer. Number of bins for calibration curve. Default: 10. |
Calibration is computed for each cluster separately: 1. Bin the predicted probabilities into n_bins equal-width bins 2. For each bin, compute mean predicted probability and observed frequency 3. A well-calibrated model has mean_predicted close to mean_observed
The Expected Calibration Error (ECE) summarizes overall calibration:
where S_b is the set of samples in bin b, acc is accuracy (observed frequency), and conf is confidence (mean predicted probability).
A list with class "calibration_result" containing:
Data frame with columns: bin_midpoint, mean_predicted, mean_observed, n_samples, cluster
Expected Calibration Error (weighted average bin error)
Maximum Calibration Error (worst bin)
Number of bins used
Number of clusters
Number of subjects
## Not run: # Fit a mixture model fit <- mixture_pca_em_fit(list_of_data, K = 3, r = 2) # Compute calibration using true labels calib <- compute_calibration(fit$resp, z_true) # View ECE print(calib$ece) # Plot calibration curve plot_calibration(calib) ## End(Not run)## Not run: # Fit a mixture model fit <- mixture_pca_em_fit(list_of_data, K = 3, r = 2) # Compute calibration using true labels calib <- compute_calibration(fit$resp, z_true) # View ECE print(calib$ece) # Plot calibration curve plot_calibration(calib) ## End(Not run)
Given a result with a vector z of length N (the cluster assignments),
this function returns a frequency table, i.e., how many subjects are assigned
to each cluster.
compute_cluster_sizes(res)compute_cluster_sizes(res)
res |
A fitted mixture model object that contains |
A table of cluster frequencies.
## Not run: tab <- compute_cluster_sizes(fit_mfa) print(tab) ## End(Not run)## Not run: tab <- compute_cluster_sizes(fit_mfa) print(tab) ## End(Not run)
Like compute_cluster_sizes, but for a Mixture PCA model result.
compute_cluster_sizes_mpca(res)compute_cluster_sizes_mpca(res)
res |
A fitted mixture PCA model result, containing |
A table of frequencies of cluster assignments.
Computes subspace similarity scores for each cluster, using the aligned mapping between estimated and true clusters. This provides a detailed assessment of how well each cluster's subspace is recovered.
compute_clusterwise_subspace_score(true_Lambda_list, est_Lambda_list, mapping)compute_clusterwise_subspace_score(true_Lambda_list, est_Lambda_list, mapping)
true_Lambda_list |
List of K_true matrices, each (M x r) representing true cluster-specific basis matrices. |
est_Lambda_list |
List of K_hat matrices, each (M x r_hat) representing estimated cluster-specific basis matrices. |
mapping |
Named integer vector from |
For each true cluster k:
Find the estimated cluster that maps to k (using the mapping)
Compute subspace similarity between true_Lambda_list[[k]] and the corresponding estimated basis
If no estimated cluster maps to k, the score is NA
This function is NA-safe: if estimation failed for some clusters (NULL or invalid matrices), those clusters receive NA scores and are excluded from the mean calculation.
A list with:
scoresNamed numeric vector of subspace similarity scores for each true cluster (names are cluster indices as characters).
mean_scoreNumeric scalar: mean of non-NA scores.
n_matchedInteger: number of true clusters with a valid estimated match.
Returns a list with NA values if inputs are invalid.
## Not run: # Generate data and fit model data <- generate_synergy_data(N = 30, K = 3, r = 2, seed = 123) fit <- mfa_em_fit(data$list_of_data, K = 3, r = 2) # Align clusters alignment <- align_clusters_to_truth(data$true_cluster, fit$z) # Compute cluster-wise scores scores <- compute_clusterwise_subspace_score( data$true_Lambda_list, fit$Lambda, alignment$mapping ) ## End(Not run)## Not run: # Generate data and fit model data <- generate_synergy_data(N = 30, K = 3, r = 2, seed = 123) fit <- mfa_em_fit(data$list_of_data, K = 3, r = 2) # Align clusters alignment <- align_clusters_to_truth(data$true_cluster, fit$z) # Compute cluster-wise scores scores <- compute_clusterwise_subspace_score( data$true_Lambda_list, fit$Lambda, alignment$mapping ) ## End(Not run)
A convenience function to compute only the ECE from responsibilities and true labels.
compute_ece(resp, z_true, n_bins = 10)compute_ece(resp, z_true, n_bins = 10)
resp |
Matrix of responsibilities (N x K) |
z_true |
Integer vector of true cluster labels (length N) |
n_bins |
Number of bins. Default: 10. |
ECE measures the average absolute difference between predicted probabilities and observed frequencies. A value of 0 indicates perfect calibration; values above 0.1 suggest significant miscalibration.
Guidelines for interpretation:
ECE < 0.02: Excellent calibration
ECE 0.02-0.05: Good calibration
ECE 0.05-0.10: Moderate calibration
ECE > 0.10: Poor calibration
Numeric scalar, the ECE value. Lower is better (0 = perfect calibration).
## Not run: ece <- compute_ece(fit$resp, z_true) cat(sprintf("ECE: %.3f\n", ece)) ## End(Not run)## Not run: ece <- compute_ece(fit$resp, z_true) cat(sprintf("ECE: %.3f\n", ece)) ## End(Not run)
Computes the entropy term used in ICL (Integrated Complete-data Likelihood). Higher entropy indicates more uncertain cluster assignments.
compute_entropy(resp)compute_entropy(resp)
resp |
An (N x K) matrix of responsibilities (posterior probabilities), where resp[i,k] is the probability that subject i belongs to cluster k. |
The entropy is computed as:
where is the responsibility of subject i for cluster k.
A small constant (1e-16) is added to avoid log(0).
A numeric scalar representing the entropy: -sum(resp * log(resp)).
## Not run: # Responsibilities from MFA fit entropy <- compute_entropy(fit_mfa$resp) ## End(Not run)## Not run: # Responsibilities from MFA fit entropy <- compute_entropy(fit_mfa$resp) ## End(Not run)
Given a single cluster's parameters (mu, Lambda, Psi) and data X,
this function returns the estimated factor scores.
compute_factor_scores(X, mu, Lambda, Psi)compute_factor_scores(X, mu, Lambda, Psi)
X |
A numeric matrix of size |
mu |
A length-M mean vector. |
Lambda |
An |
Psi |
An |
This follows the standard posterior mean formula in factor analysis:
.
A (T x r) matrix of factor scores.
## Not run: # Suppose we have X (T x M), mu (M), Lambda (M x r), Psi (M x M). scores <- compute_factor_scores(X, mu, Lambda, Psi) head(scores) ## End(Not run)## Not run: # Suppose we have X (T x M), mu (M), Lambda (M x r), Psi (M x M). scores <- compute_factor_scores(X, mu, Lambda, Psi) head(scores) ## End(Not run)
Given a fitted MFA model (with z, mu, Lambda, Psi for each cluster),
this function computes the posterior factor scores Z_i(t) for each subject i
and stores them in model$factor_scores[[i]].
compute_factor_scores_mfa(mfa_fit, list_of_data)compute_factor_scores_mfa(mfa_fit, list_of_data)
mfa_fit |
A fitted MFA model, typically from
|
list_of_data |
The same list of data |
Internally, it calls compute_factor_scores_optimized for each subject,
using that subject's assigned cluster k = z[i].
The same mfa_fit object, but with a new element factor_scores
(a list of length N), where each factor_scores[[i]] is a
(T_i x r) matrix of factor scores for subject i.
## Not run: mfa_fit <- compute_factor_scores_mfa(mfa_fit, list_of_data) # Now mfa_fit$factor_scores[[i]] is available for each subject i ## End(Not run)## Not run: mfa_fit <- compute_factor_scores_mfa(mfa_fit, list_of_data) # Now mfa_fit$factor_scores[[i]] is available for each subject i ## End(Not run)
Given a fitted MPCA model (with z, mu, W, sigma2 for each cluster),
this function computes the posterior factor (PC) scores Z_i(t) for each subject i
and stores them in mpca_fit$factor_scores[[i]].
compute_factor_scores_mpca(mpca_fit, list_of_data)compute_factor_scores_mpca(mpca_fit, list_of_data)
mpca_fit |
A fitted MPCA model from
|
list_of_data |
The same list of data |
We use compute_factor_scores_mpca_single for each subject, with the
appropriate cluster parameters. This assumes isotropic noise sigma2[k] for cluster k.
The same mpca_fit object, but with a new element factor_scores,
where factor_scores[[i]] is a (T_i x r) matrix of PC scores for subject i.
## Not run: mpca_fit <- compute_factor_scores_mpca(mpca_fit, list_of_data) mpca_fit$factor_scores[[1]] # (T_1 x r) PC scores ## End(Not run)## Not run: mpca_fit <- compute_factor_scores_mpca(mpca_fit, list_of_data) mpca_fit$factor_scores[[1]] # (T_1 x r) PC scores ## End(Not run)
Given a single subject's data X, and the cluster parameters (mu, W, sigma2), this function computes the posterior factor scores (T x r) under a PPCA assumption with isotropic noise sigma^2 * I.
compute_factor_scores_mpca_single(X, mu, W, sigma2)compute_factor_scores_mpca_single(X, mu, W, sigma2)
X |
A (T x M) data matrix for one subject/time-series. |
mu |
A length-M mean vector. |
W |
An (M x r) loading (projection) matrix for the cluster. |
sigma2 |
A scalar representing isotropic noise variance (sigma^2). |
We use the posterior mean formula for PPCA with isotropic noise: z(t) = inv(W^T W + sigma2 * I_r) * W^T * (x(t) - mu). This is applied row by row in X, but we can do it in a vectorized manner.
If your noise model is not purely sigma2 * I, you will need a more general approach. Also note that if T=1, the result might be a (1 x r) matrix or (r)-vector, so be sure to keep it as a matrix if desired.
A (T x r) matrix of factor (PC) scores for this subject.
Given a single subject's data X and the cluster's parameters
(mu, Lambda, Psi), this function computes the posterior factor scores
(of size T x r) in a standard Factor Analysis approach.
compute_factor_scores_optimized(X, mu, Lambda, Psi)compute_factor_scores_optimized(X, mu, Lambda, Psi)
X |
A |
mu |
A length- |
Lambda |
An |
Psi |
An |
We use the standard formula for Factor Analysis posterior means:
The code is implemented in a vectorized manner. If ,
then the output dimension is (T x r).
A (T x r) matrix of factor scores Z_i(t), where t = 1..T.
## Not run: X_i <- list_of_data[[i]] # (T x M) # from model$mu[[k]], model$Lambda[[k]], model$Psi[[k]] Z_i <- compute_factor_scores_optimized(X_i, mu_k, Lambda_k, Psi_k) dim(Z_i) # (T x r) ## End(Not run)## Not run: X_i <- list_of_data[[i]] # (T x M) # from model$mu[[k]], model$Lambda[[k]], model$Psi[[k]] Z_i <- compute_factor_scores_optimized(X_i, mu_k, Lambda_k, Psi_k) dim(Z_i) # (T x r) ## End(Not run)
This function takes a fitted MFA model (with elements z, mu, Lambda, Psi)
and reconstructs all subjects' data from the factor scores, computing the
ratio of explained variance ().
compute_global_vaf_mfa(list_of_data, res)compute_global_vaf_mfa(list_of_data, res)
list_of_data |
A list of matrices, each |
res |
A fitted MFA model result. It must contain:
|
For each subject i, we identify its cluster assignment k_i, compute factor scores
via compute_factor_scores, reconstruct Xhat from the factor model,
accumulate the sum of squares of residuals (SSE), and the sum of squares total (SST).
A numeric scalar for the global variance accounted for, .
## Not run: gvaf <- compute_global_vaf_mfa(my_data_list, fit_mfa) cat("Global VAF:", gvaf, "\n") ## End(Not run)## Not run: gvaf <- compute_global_vaf_mfa(my_data_list, fit_mfa) cat("Global VAF:", gvaf, "\n") ## End(Not run)
Similar to compute_global_vaf_mfa, but uses a Mixture PCA model structure.
Given a model with z, mu, P, D, Psi, we reconstruct each subject's data from
the principal component scores, accumulate SSE, and compare to total sum of squares (SST).
compute_global_vaf_mpca(list_of_data, res)compute_global_vaf_mpca(list_of_data, res)
list_of_data |
A list of |
res |
The fitted Mixture PCA model, typically from
|
The user must define how to reconstruct data from PCA parameters. Typically,
for each cluster k, we have W = P * D, so we either compute
posterior scores or do a direct projection.
A numeric scalar, across all subjects and time steps.
Unified interface for computing ICL (Integrated Complete-data Likelihood) for either MFA or MPCA models.
compute_ICL(loglik, K, r, M, N_obs, resp, model_type)compute_ICL(loglik, K, r, M, N_obs, resp, model_type)
loglik |
The total log-likelihood from the fitted model. |
K |
Number of clusters. |
r |
Factor/principal component dimension. |
M |
Observed dimension (channels). |
N_obs |
Number of observations. |
resp |
An (N x K) matrix of responsibilities. |
model_type |
Either "MFA" or "MPCA". |
A numeric ICL value.
compute_ICL_mfa, compute_ICL_mpca
ICL (Integrated Complete-data Likelihood) is a model selection criterion that penalizes uncertain cluster assignments more heavily than BIC. This makes it more conservative for selecting the number of clusters K.
compute_ICL_mfa(loglik, K, r, M, N_obs, resp)compute_ICL_mfa(loglik, K, r, M, N_obs, resp)
loglik |
The total log-likelihood from the MFA model. |
K |
Number of clusters. |
r |
Factor dimension. |
M |
Observed dimension (channels). |
N_obs |
Number of observations (typically sum of all T_i across subjects). |
resp |
An (N x K) matrix of responsibilities (posterior probabilities). |
ICL is computed as:
where Entropy = -sum(resp * log(resp)).
The entropy penalty discourages models where cluster assignments are uncertain, which typically happens when K is overestimated (extra clusters with low membership). This makes ICL more conservative than BIC for K selection.
A numeric ICL value.
Biernacki, C., Celeux, G., & Govaert, G. (2000). Assessing a mixture model for clustering with the integrated completed likelihood. IEEE Transactions on Pattern Analysis and Machine Intelligence, 22(7), 719-725.
compute_BIC_mfa, compute_entropy
## Not run: icl <- compute_ICL_mfa(fit$logLik, K = 2, r = 3, M = 8, N_obs = 1000, resp = fit$resp) ## End(Not run)## Not run: icl <- compute_ICL_mfa(fit$logLik, K = 2, r = 3, M = 8, N_obs = 1000, resp = fit$resp) ## End(Not run)
ICL (Integrated Complete-data Likelihood) is a model selection criterion that penalizes uncertain cluster assignments more heavily than BIC. This makes it more conservative for selecting the number of clusters K.
compute_ICL_mpca(loglik, K, r, M, N_obs, resp)compute_ICL_mpca(loglik, K, r, M, N_obs, resp)
loglik |
The total log-likelihood from the MPCA model. |
K |
Number of clusters. |
r |
Principal component dimension. |
M |
Observed dimension (channels). |
N_obs |
Number of observations (typically sum of all T_i across subjects). |
resp |
An (N x K) matrix of responsibilities (posterior probabilities). |
ICL is computed as:
where Entropy = -sum(resp * log(resp)).
A numeric ICL value.
compute_BIC_mpca, compute_entropy
Unified interface for computing log-likelihood for both MFA and MPCA models. Automatically detects model type from the fit object structure.
compute_logLik(list_of_data, fit, model_type = NULL)compute_logLik(list_of_data, fit, model_type = NULL)
list_of_data |
A list of N matrices, each of dimension (T_i x M) |
fit |
A fitted model object (MFA or MPCA) |
model_type |
Character, either "MFA" or "MPCA". If NULL, auto-detected from the fit object structure. |
A numeric scalar representing the total log-likelihood
compute_logLik_mfa, compute_logLik_mpca
## Not run: # Works with either MFA or MPCA fit objects ll <- compute_logLik(list_of_data, fit) # Or explicitly specify model type ll <- compute_logLik(list_of_data, fit, model_type = "MFA") ## End(Not run)## Not run: # Works with either MFA or MPCA fit objects ll <- compute_logLik(list_of_data, fit) # Or explicitly specify model type ll <- compute_logLik(list_of_data, fit, model_type = "MFA") ## End(Not run)
Given a fitted MFA model (with K clusters, each containing
Lambda[[k]], mu[[k]], Psi[[k]], and mixing proportion pi[k]),
this function computes the standard mixture log-likelihood:
where Sigma_k = Lambda_k * Lambda_k^T + Psi_k.
compute_logLik_mfa(list_of_data, mfa_fit)compute_logLik_mfa(list_of_data, mfa_fit)
list_of_data |
A list of length |
mfa_fit |
A fitted MFA model, containing:
|
Internally uses rowwise multivariate normal densities. You will need
mvtnorm::dmvnorm or an equivalent. Ensure each Sigma_k is well-defined
and invertible if needed.
A numeric scalar, the total log-likelihood.
Given a fitted Mixture PCA model with $P[[k]], $mu[[k]],
$sigma2[k], and $pi[k], we compute
where Sigma_k = W_k * W_k^T + sigma2_k * I. A typical approach is to reconstruct Sigma_k from P[[k]] if needed (or W[[k]]).
compute_logLik_mpca(list_of_data, mpca_fit)compute_logLik_mpca(list_of_data, mpca_fit)
list_of_data |
A list of length |
mpca_fit |
A fitted Mixture PCA model, containing:
|
We assume each cluster k has Sigma_k = W_k * W_k^T + sigma2_k * I.
You must assemble that to call mvtnorm::dmvnorm row by row.
A numeric scalar, the total mixture log-likelihood.
Computes Maximum Voluntary Contraction (MVC) reference values from MVC trial data for use in EMG normalization.
compute_mvc_reference( mvc_data, method = "peak", window_ms = 500, top_percent = 5, sampling_rate = NULL )compute_mvc_reference( mvc_data, method = "peak", window_ms = 500, top_percent = 5, sampling_rate = NULL )
mvc_data |
MVC trial data. Can be a matrix (T x M) or a list of matrices (multiple MVC trials). |
method |
Method to compute MVC:
|
window_ms |
Window size in ms for peak detection (used with
|
top_percent |
Percentage of top values to average (used with
|
sampling_rate |
Sampling rate in Hz (required for |
Numeric vector of MVC values, one per channel.
# From single MVC trial mvc_trial <- matrix(abs(rnorm(1000 * 4)), ncol = 4) mvc_ref <- compute_mvc_reference(mvc_trial) # From multiple MVC trials (takes maximum across trials) mvc_trials <- list( trial1 = matrix(abs(rnorm(1000 * 4)), ncol = 4), trial2 = matrix(abs(rnorm(1000 * 4)), ncol = 4) ) mvc_ref <- compute_mvc_reference(mvc_trials)# From single MVC trial mvc_trial <- matrix(abs(rnorm(1000 * 4)), ncol = 4) mvc_ref <- compute_mvc_reference(mvc_trial) # From multiple MVC trials (takes maximum across trials) mvc_trials <- list( trial1 = matrix(abs(rnorm(1000 * 4)), ncol = 4), trial2 = matrix(abs(rnorm(1000 * 4)), ncol = 4) ) mvc_ref <- compute_mvc_reference(mvc_trials)
Unified interface for computing reconstruction error for both MFA and MPCA models. Automatically detects model type from the fit object structure.
compute_reconstruction_error( list_of_data, fit, model_type = NULL, metric = c("sse", "rmse") )compute_reconstruction_error( list_of_data, fit, model_type = NULL, metric = c("sse", "rmse") )
list_of_data |
A list of N matrices, each of dimension (T_i x M) |
fit |
A fitted model object (MFA or MPCA) |
model_type |
Character, either "MFA" or "MPCA". If NULL, auto-detected from the fit object structure. |
metric |
Character, one of "sse" (sum of squared errors) or "rmse" (root mean squared error). Default: "sse" |
A numeric scalar representing the reconstruction error
## Not run: # Compute SSE sse <- compute_reconstruction_error(list_of_data, fit) # Compute RMSE rmse <- compute_reconstruction_error(list_of_data, fit, metric = "rmse") ## End(Not run)## Not run: # Compute SSE sse <- compute_reconstruction_error(list_of_data, fit) # Compute RMSE rmse <- compute_reconstruction_error(list_of_data, fit, metric = "rmse") ## End(Not run)
Computes the temporal smoothness penalty for factor scores using second-order differences. This penalty measures how "wiggly" the factor activation profiles are, with higher values indicating more high-frequency noise.
compute_smoothness_penalty(factor_scores)compute_smoothness_penalty(factor_scores)
factor_scores |
A list of N matrices, each (T_i x r), containing factor scores for each subject. |
The smoothness penalty is computed as:
where is the j-th factor score for subject i at time t.
This is equivalent to summing the squared second-order differences across all time series. When r is too large, models tend to fit high-frequency noise, producing wiggly factors with high smoothness penalties.
A numeric scalar representing the total smoothness penalty across all subjects and factors.
## Not run: # Compute factor scores first mfa_fit <- compute_factor_scores_mfa(mfa_fit, list_of_data) # Then compute smoothness smooth_val <- compute_smoothness_penalty(mfa_fit$factor_scores) ## End(Not run)## Not run: # Compute factor scores first mfa_fit <- compute_factor_scores_mfa(mfa_fit, list_of_data) # Then compute smoothness smooth_val <- compute_smoothness_penalty(mfa_fit$factor_scores) ## End(Not run)
Computes the similarity between two subspaces spanned by basis matrices using QR decomposition and SVD. This metric measures how well the estimated subspace recovers the true subspace, independent of rotation and scaling.
compute_subspace_similarity(L_true, L_hat)compute_subspace_similarity(L_true, L_hat)
L_true |
A (M x r_true) matrix representing the true basis. |
L_hat |
A (M x r_hat) matrix representing the estimated basis. |
The subspace similarity is computed as follows:
Orthonormalize both bases using QR decomposition
Compute the SVD of Q_true' * Q_hat
Return the mean of squared singular values (up to min_dim)
This metric is invariant to rotation and scaling of the basis vectors, making it suitable for comparing factor analysis solutions where rotation indeterminacy exists.
When r_true != r_hat, the metric uses min(r_true, r_hat) dimensions, which allows comparison even when the estimated rank differs from truth.
Numeric scalar in [0, 1], where 1 indicates identical subspaces. Returns NA if inputs are invalid (NULL, empty, or contain NA/NaN/Inf).
## Not run: # Same subspace (rotated) L_true <- matrix(c(1, 0, 0, 1), 2, 2) R <- matrix(c(cos(pi/4), -sin(pi/4), sin(pi/4), cos(pi/4)), 2, 2) L_hat <- L_true %*% R compute_subspace_similarity(L_true, L_hat) # Should be ~1 # Orthogonal subspaces L_true <- matrix(c(1, 0, 0, 0), 2, 2) L_hat <- matrix(c(0, 0, 0, 1), 2, 2) compute_subspace_similarity(L_true, L_hat) # Should be ~0 ## End(Not run)## Not run: # Same subspace (rotated) L_true <- matrix(c(1, 0, 0, 1), 2, 2) R <- matrix(c(cos(pi/4), -sin(pi/4), sin(pi/4), cos(pi/4)), 2, 2) L_hat <- L_true %*% R compute_subspace_similarity(L_true, L_hat) # Should be ~1 # Orthogonal subspaces L_true <- matrix(c(1, 0, 0, 0), 2, 2) L_hat <- matrix(c(0, 0, 0, 1), 2, 2) compute_subspace_similarity(L_true, L_hat) # Should be ~0 ## End(Not run)
Unified interface for computing global VAF for both MFA and MPCA models. Automatically detects model type from the fit object structure.
compute_VAF(list_of_data, fit, model_type = NULL)compute_VAF(list_of_data, fit, model_type = NULL)
list_of_data |
A list of N matrices, each of dimension (T_i x M) |
fit |
A fitted model object (MFA or MPCA) |
model_type |
Character, either "MFA" or "MPCA". If NULL, auto-detected from the fit object structure. |
VAF is computed as 1 - SSE/SST, where SSE is the sum of squared errors between observed and reconstructed data, and SST is the total sum of squares.
A numeric scalar representing the global VAF (0 to 1)
compute_global_vaf_mfa, compute_global_vaf_mpca
## Not run: # Works with either MFA or MPCA fit objects vaf <- compute_VAF(list_of_data, fit) # Or explicitly specify model type vaf <- compute_VAF(list_of_data, fit, model_type = "MFA") ## End(Not run)## Not run: # Works with either MFA or MPCA fit objects vaf <- compute_VAF(list_of_data, fit) # Or explicitly specify model type vaf <- compute_VAF(list_of_data, fit, model_type = "MFA") ## End(Not run)
This function computes the Variance Accounted For (VAF) for a fitted MFA model across all subjects, reconstructing each subject's data via factor scores and summing squared errors.
compute_VAF_mfa(list_of_data, mfa_fit, z)compute_VAF_mfa(list_of_data, mfa_fit, z)
list_of_data |
A list of subject data matrices, each |
mfa_fit |
An MFA fit object containing |
z |
An integer vector of length |
A numeric scalar representing the total VAF over all subjects.
## Not run: sim <- simulate_mixture_data(N = 50, K = 3, r = 2, M = 6, T_each = 100) fit <- mfa_em_fit(sim$list_of_data, K = 3, r = 2) vaf <- compute_VAF_mfa(sim$list_of_data, fit, fit$z) print(vaf) ## End(Not run)## Not run: sim <- simulate_mixture_data(N = 50, K = 3, r = 2, M = 6, T_each = 100) fit <- mfa_em_fit(sim$list_of_data, K = 3, r = 2) vaf <- compute_VAF_mfa(sim$list_of_data, fit, fit$z) print(vaf) ## End(Not run)
This function computes the Variance Accounted For (VAF) for a fitted Mixture PCA model.
compute_VAF_mpca(list_of_data, mpca_fit, z)compute_VAF_mpca(list_of_data, mpca_fit, z)
list_of_data |
A list of subject data matrices. |
mpca_fit |
A fitted MPCA model with |
z |
An integer vector of cluster assignments. |
A numeric scalar for the overall VAF.
## Not run: sim <- simulate_mixture_data(N = 50, K = 3, r = 2, M = 6, T_each = 100) fit <- mixture_pca_em_fit(sim$list_of_data, K = 3, r = 2) vaf <- compute_VAF_mpca(sim$list_of_data, fit, fit$z) print(vaf) ## End(Not run)## Not run: sim <- simulate_mixture_data(N = 50, K = 3, r = 2, M = 6, T_each = 100) fit <- mixture_pca_em_fit(sim$list_of_data, K = 3, r = 2) vaf <- compute_VAF_mpca(sim$list_of_data, fit, fit$z) print(vaf) ## End(Not run)
Computes the global Variance Accounted For (VAF) for a fitted MFA or MPCA model. This is a unified wrapper that dispatches to the appropriate method-specific function.
compute_vaf_wrapper(method, list_of_data, fit)compute_vaf_wrapper(method, list_of_data, fit)
method |
Model type: "MFA" or "MPCA". |
list_of_data |
A list of data matrices, each (T_i x M). |
fit |
A fitted model object. |
VAF is computed as , where SSE is the sum of squared
reconstruction errors and SST is the total sum of squares.
Numeric scalar: VAF value in [0, 1], where 1 indicates perfect reconstruction. Returns NA if computation fails.
## Not run: fit <- mfa_em_fit(list_of_data, K = 3, r = 2) vaf <- compute_vaf_wrapper("MFA", list_of_data, fit) ## End(Not run)## Not run: fit <- mfa_em_fit(list_of_data, K = 3, r = 2) vaf <- compute_vaf_wrapper("MFA", list_of_data, fit) ## End(Not run)
Computes the Very Simple Structure (VSS) criterion, which evaluates how well factor loadings exhibit simple structure (each variable loads strongly on one factor, weakly on others).
compute_vss_criterion( Lambda, threshold = 0.5, method = c("threshold", "ratio"), rotate = c("none", "varimax") )compute_vss_criterion( Lambda, threshold = 0.5, method = c("threshold", "ratio"), rotate = c("none", "varimax") )
Lambda |
A list of K loading matrices, each (M x r), representing factor loadings for each cluster. |
threshold |
Threshold for determining "strong" vs "weak" loadings. Default is 0.5. Loadings with absolute value above this threshold are considered strong. |
method |
Method for computing VSS. Options: "threshold" (count variables with exactly one strong loading above threshold), "ratio" (compute concentration ratio max(lambda^2)/sum(lambda^2) for each variable). Default is "threshold". |
rotate |
Rotation method to apply before computing VSS. Options: "none" (no rotation), "varimax" (orthogonal rotation). Default is "none". VSS on unrotated FA loadings is rotation-dependent and often uninformative. Rotation is recommended for meaningful VSS. |
The VSS criterion evaluates simple structure in factor loadings. Two methods are available:
**Threshold method (default):** For each variable (muscle), count how many factors have |loading| > threshold. Simple structure is achieved when this count is exactly 1. The VSS score is the proportion of variables across all clusters that exhibit simple structure.
**Ratio method:** For each variable (muscle), compute the concentration ratio max(lambda^2)/sum(lambda^2), which measures how concentrated the loadings are on a single factor. The VSS score is the average concentration ratio across all variables. This method is more robust when loadings are small in absolute magnitude, as it doesn't depend on an arbitrary threshold.
This implementation is inspired by the psych::VSS() function, adapted for mixture models where each cluster has its own loading matrix.
A numeric scalar representing the VSS criterion. Higher values indicate better simple structure. Returns NA if rotation fails or loadings are degenerate.
Revelle, W., & Rocklin, T. (1979). Very Simple Structure: An Alternative Procedure For Estimating The Optimal Number Of Interpretable Factors. Multivariate Behavioral Research, 14(4), 403-414.
## Not run: # For an MFA model vss_val <- compute_vss_criterion(mfa_fit$Lambda, threshold = 0.5) ## End(Not run)## Not run: # For an MFA model vss_val <- compute_vss_criterion(mfa_fit$Lambda, threshold = 0.5) ## End(Not run)
Counts how many tasks have completed by checking partial result files.
count_completed_tasks(output_dir, n_total = NULL)count_completed_tasks(output_dir, n_total = NULL)
output_dir |
Character. Output directory. |
n_total |
Integer. Total number of expected tasks (optional). |
List with completion statistics.
Returns preset configurations for common EMG preprocessing scenarios.
emg_preset_config(preset = "default")emg_preset_config(preset = "default")
preset |
Preset name:
|
A list containing preprocessing configuration for each step.
# Get default configuration config <- emg_preset_config("default") # Modify for custom needs config$notch$freq <- 60 # Change to 60 Hz config$envelope$cutoff <- 10 # Higher cutoff for faster movements# Get default configuration config <- emg_preset_config("default") # Modify for custom needs config$notch$freq <- 60 # Change to 60 Hz config$envelope$cutoff <- 10 # Higher cutoff for faster movements
Comprehensive evaluation of model selection results, computing all relevant metrics including ARI, VAF, BIC, logLik, and selection accuracy.
evaluate_model_selection( list_of_data, true_cluster, K_true, r_true, select_result, runtime_sec = NA_real_ )evaluate_model_selection( list_of_data, true_cluster, K_true, r_true, select_result, runtime_sec = NA_real_ )
list_of_data |
A list of data matrices, each (T_i x M). |
true_cluster |
Integer vector of true cluster assignments. |
K_true |
True number of clusters. |
r_true |
True factor dimension. |
select_result |
Result from |
runtime_sec |
Runtime in seconds (optional). |
A list with evaluation metrics:
K_hatEstimated number of clusters.
r_hatEstimated factor dimension.
K_correctLogical: K_hat == K_true.
r_correctLogical: r_hat == r_true.
Kr_correctLogical: both K and r correct.
ARIAdjusted Rand Index.
VAFVariance Accounted For.
logLikLog-likelihood.
BICBayesian Information Criterion.
runtime_secRuntime in seconds.
## Not run: # Generate data data <- generate_synergy_data(N = 30, K = 3, r = 3, seed = 123) # Run model selection start_time <- Sys.time() select_result <- select_K_r(data$list_of_data, method = "MFA", strategy = "grid") runtime <- as.numeric(difftime(Sys.time(), start_time, units = "secs")) # Evaluate eval_result <- evaluate_model_selection( data$list_of_data, data$true_cluster, K_true = 3, r_true = 3, select_result, runtime_sec = runtime ) ## End(Not run)## Not run: # Generate data data <- generate_synergy_data(N = 30, K = 3, r = 3, seed = 123) # Run model selection start_time <- Sys.time() select_result <- select_K_r(data$list_of_data, method = "MFA", strategy = "grid") runtime <- as.numeric(difftime(Sys.time(), start_time, units = "secs")) # Evaluate eval_result <- evaluate_model_selection( data$list_of_data, data$true_cluster, K_true = 3, r_true = 3, select_result, runtime_sec = runtime ) ## End(Not run)
This function extracts cluster assignment labels from a fitted MFA or MPCA model object. It searches through common field names used by different model implementations.
extract_cluster_labels(fit)extract_cluster_labels(fit)
fit |
A fitted model object (MFA or MPCA). |
The function searches for cluster labels in the following fields (in order):
z: Standard field for MFA/MPCA models
cluster: Alternative naming
clusters: Plural form
class: Classification result
z_hat: Estimated assignments
cl: Short form
hard_cluster: Hard assignment from soft clustering
labels: Generic label field
If the model has a resp (responsibility) matrix but no hard assignments,
the function computes hard assignments using MAP (maximum a posteriori).
An integer vector of cluster assignments (1 to K), or NA if cluster labels cannot be extracted.
## Not run: fit <- mfa_em_fit(list_of_data, K = 3, r = 2) pred_cluster <- extract_cluster_labels(fit) ## End(Not run)## Not run: fit <- mfa_em_fit(list_of_data, K = 3, r = 2) pred_cluster <- extract_cluster_labels(fit) ## End(Not run)
Extracts the amplitude envelope from rectified EMG signals using various methods.
extract_envelope( data, sampling_rate, method = "lowpass", cutoff = 6, window_ms = 50, filter_order = 4, zero_phase = TRUE )extract_envelope( data, sampling_rate, method = "lowpass", cutoff = 6, window_ms = 50, filter_order = 4, zero_phase = TRUE )
data |
Rectified EMG signal. Can be a numeric vector (single channel), a matrix (T x M, time x channels), or a list of matrices. Should typically be rectified before envelope extraction. |
sampling_rate |
Sampling frequency in Hz. |
method |
Envelope extraction method:
|
cutoff |
Cutoff frequency for low-pass filter in Hz.
Only used when |
window_ms |
Window size in milliseconds for RMS or moving average.
Only used when |
filter_order |
Filter order for low-pass method. Default is 4. |
zero_phase |
Logical. If TRUE (default), applies zero-phase filtering for the low-pass method. |
The envelope represents the amplitude modulation of the EMG signal, showing muscle activation patterns over time. Common approaches:
Low-pass filter: Applies a Butterworth low-pass filter to the rectified signal. Cutoff frequency typically 4-10 Hz.
RMS: Computes root mean square in a sliding window. Good for preserving amplitude information.
Moving average: Simple smoothing with a sliding window. Fast but may introduce artifacts at window edges.
EMG envelope signal, same structure as input.
## Not run: # Generate and process EMG fs <- 1000 raw_emg <- rnorm(1000) rect_emg <- rectify(raw_emg) # Low-pass envelope (most common) env_lp <- extract_envelope(rect_emg, sampling_rate = fs, method = "lowpass") # RMS envelope env_rms <- extract_envelope(rect_emg, sampling_rate = fs, method = "rms", window_ms = 100) ## End(Not run)## Not run: # Generate and process EMG fs <- 1000 raw_emg <- rnorm(1000) rect_emg <- rectify(raw_emg) # Low-pass envelope (most common) env_lp <- extract_envelope(rect_emg, sampling_rate = fs, method = "lowpass") # RMS envelope env_rms <- extract_envelope(rect_emg, sampling_rate = fs, method = "rms", window_ms = 100) ## End(Not run)
Converts the summary from select_K_r to a flat data frame,
useful for saving and plotting.
extract_selection_summary(select_result)extract_selection_summary(select_result)
select_result |
Result from |
A data frame with columns K, r, logLik, BIC, and optionally stage (for twostage strategy).
This function applies PCA to the concatenated data across all subjects,
then for each subject i, computes the mean of the top r_dim principal
component scores as a single feature vector. This is useful for initializing
cluster assignments in mixture models.
extract_subject_features_by_singlePCA(list_of_data, r_dim = 2)extract_subject_features_by_singlePCA(list_of_data, r_dim = 2)
list_of_data |
A list of |
r_dim |
Number of principal components to extract. Defaults to 2. |
The function first concatenates all subject data into a single matrix, performs PCA on this combined dataset, and then computes the mean of the PC scores for each subject's time points. This provides a low-dimensional representation of each subject that can be used for clustering initialization.
A numeric matrix of shape (N x r_dim), where N=length(list_of_data).
Each row contains the mean PC scores for one subject.
## Not run: # Create example data N <- 10 M <- 8 list_of_data <- lapply(1:N, function(i) matrix(rnorm(100 * M), 100, M)) # Extract 2D features for each subject features <- extract_subject_features_by_singlePCA(list_of_data, r_dim = 2) dim(features) # Should be 10 x 2 ## End(Not run)## Not run: # Create example data N <- 10 M <- 8 list_of_data <- lapply(1:N, function(i) matrix(rnorm(100 * M), 100, M)) # Extract 2D features for each subject features <- extract_subject_features_by_singlePCA(list_of_data, r_dim = 2) dim(features) # Should be 10 x 2 ## End(Not run)
Helper function to apply consistent facet_grid() styling for cluster-factor plots.
facet_mixsynergy(rows = NULL, cols = NULL, scales = "fixed", ...)facet_mixsynergy(rows = NULL, cols = NULL, scales = "fixed", ...)
rows |
Variable(s) for facet rows (e.g., "Cluster") |
cols |
Variable(s) for facet columns (e.g., "Factor") |
scales |
Scale behavior: "fixed" (default), "free", "free_x", "free_y" |
... |
Additional arguments passed to facet_grid() |
A ggplot2 facet_grid object
## Not run: library(ggplot2) ggplot(data, aes(x, y)) + geom_line() + facet_mixsynergy(rows = "Cluster", cols = "Factor", scales = "free_y") ## End(Not run)## Not run: library(ggplot2) ggplot(data, aes(x, y)) + geom_line() + facet_mixsynergy(rows = "Cluster", cols = "Factor", scales = "free_y") ## End(Not run)
This function concatenates all subjects' data into one large matrix, then performs a naive factor analysis. It returns a simple BIC measure and the fitted loadings, mean, and diagonal Psi.
fit_single_factor_analysis(list_of_data, r = 2)fit_single_factor_analysis(list_of_data, r = 2)
list_of_data |
A list of (T_i x M) matrices. |
r |
The factor dimension. |
A list with elements (loadings, mu, diagPsi, logLik, BIC).
## Not run: sim <- simulate_mixture_data(N = 50, K = 3, r = 2, M = 6, T_each = 100) fa_res <- fit_single_factor_analysis(sim$list_of_data, r = 2) print(fa_res$BIC) ## End(Not run)## Not run: sim <- simulate_mixture_data(N = 50, K = 3, r = 2, M = 6, T_each = 100) fa_res <- fit_single_factor_analysis(sim$list_of_data, r = 2) print(fa_res$BIC) ## End(Not run)
Concatenates all data into one matrix, performs SVD, keeps r
principal components, then computes a naive PPCA logLik and BIC.
fit_single_pca(list_of_data, r = 2)fit_single_pca(list_of_data, r = 2)
list_of_data |
List of (T_i x M) matrices. |
r |
Number of principal components. |
A list with (P, mu, sigma2, logLik, BIC).
## Not run: sim <- simulate_mixture_data(N = 50, K = 3, r = 2, M = 6, T_each = 100) pca_res <- fit_single_pca(sim$list_of_data, r = 2) print(pca_res$BIC) ## End(Not run)## Not run: sim <- simulate_mixture_data(N = 50, K = 3, r = 2, M = 6, T_each = 100) pca_res <- fit_single_pca(sim$list_of_data, r = 2) print(pca_res$BIC) ## End(Not run)
This function implements a two-step baseline approach for comparison with mixture-based methods:
Step 1: Individual Decomposition - Apply PCA or FA to each
subject's data separately to extract r basis vectors per subject.
Step 1.5: Basis Alignment - Align basis vectors across subjects using the Hungarian algorithm to ensure corresponding components are in the same order, improving clustering accuracy.
Step 2: Clustering - Normalize the basis vectors, concatenate them across all subjects, and apply k-means clustering. Assign each subject to a cluster based on majority vote of their basis vectors.
fit_two_step_baseline( data_list, r, K, method = c("PCA", "FA"), seed = 123, z_true = NULL, refine_assignments = FALSE, align_basis = TRUE )fit_two_step_baseline( data_list, r, K, method = c("PCA", "FA"), seed = 123, z_true = NULL, refine_assignments = FALSE, align_basis = TRUE )
data_list |
A list of |
r |
Number of components (factors or principal components) to extract per subject. |
K |
Number of clusters for k-means. |
method |
Either |
seed |
Random seed for reproducibility. |
z_true |
Optional true cluster labels for computing ARI. If |
refine_assignments |
Logical. If |
align_basis |
Logical. If |
The algorithm addresses sign indeterminacy by normalizing each basis vector so that its maximum absolute value element is positive. Tie-breaking in majority vote is handled by computing the mean distance from a subject's basis vectors to each tied cluster centroid and selecting the closer one.
Step 1.5 (basis alignment) uses the Hungarian algorithm to align basis vectors across subjects. This ensures that corresponding components (e.g., the first component of each subject) represent similar patterns, which is crucial for accurate clustering. Without alignment, the arbitrary ordering of components from individual PCA/FA can lead to poor clustering performance.
Step 4 (re-optimization) fits cluster-specific models in standardized space
to ensure consistency with Step 1. This improves reconstruction metrics (SSE/VAF)
but does not change ARI unless refine_assignments = TRUE.
If refine_assignments = TRUE, a single reassignment pass is performed
after fitting cluster-specific models. Each subject is reassigned to the cluster
that minimizes reconstruction error. This can improve ARI while maintaining the
two-step nature of the baseline (unlike iterative EM which would drift toward
the mixture model).
For FA decomposition, the function uses psych::fa() if available.
If the psych package is not installed or if FA fails for a subject,
the function falls back to PCA with a warning.
A list with:
z_estInteger vector of estimated cluster assignments (1..K).
W_listList of normalized basis matrices, one per subject.
W_centroidsMatrix of cluster centroids in basis space.
mu_listList of centering vectors used for standardization, one per subject.
sd_listList of scaling vectors used for standardization, one per subject.
cluster_modelsList of cluster-specific models (each with W and n_members).
methodCharacter string indicating the method used (e.g., "TwoStep_PCA").
BICSet to NA (k-means does not have a canonical BIC).
ARIAdjusted Rand Index if z_true is provided, otherwise NA.
## Not run: sim <- simulate_mixture_data(N = 50, K = 3, r = 2, M = 6, T_each = 100) result <- fit_two_step_baseline( sim$list_of_data, r = 2, K = 3, method = "PCA", seed = 123, z_true = sim$z_true ) print(result$ARI) ## End(Not run)## Not run: sim <- simulate_mixture_data(N = 50, K = 3, r = 2, M = 6, T_each = 100) result <- fit_two_step_baseline( sim$list_of_data, r = 2, K = 3, method = "PCA", seed = 123, z_true = sim$z_true ) print(result$ARI) ## End(Not run)
Generates a PBS array job script for submitting parameter sweep tasks.
generate_pbs_script( n_tasks, output_dir, pbs_config = list(), sweep_type = c("modelsel", "baselines"), sweep_config = list() )generate_pbs_script( n_tasks, output_dir, pbs_config = list(), sweep_type = c("modelsel", "baselines"), sweep_config = list() )
n_tasks |
Integer. Total number of tasks (rows in parameter grid). |
output_dir |
Character. Directory for output files. |
pbs_config |
List. PBS configuration options:
|
sweep_type |
Character. Type of sweep: "modelsel" or "baselines". |
sweep_config |
List. Sweep-specific configuration passed to run_single_task. |
Character. Path to the generated PBS script.
## Not run: script_path <- generate_pbs_script( n_tasks = 100, output_dir = "results", pbs_config = list( queue = "batch", walltime = "02:00:00", r_module = "R/4.3.0" ) ) ## End(Not run)## Not run: script_path <- generate_pbs_script( n_tasks = 100, output_dir = "results", pbs_config = list( queue = "batch", walltime = "02:00:00", r_module = "R/4.3.0" ) ) ## End(Not run)
This function provides a standardized interface for generating v2 dynamic
synergy data suitable for model selection experiments. It wraps
simulate_dynamic_synergy_data and returns data in a format
optimized for parameter sweep experiments with model selection.
generate_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 1, cluster_sep_temporal = 1, cluster_sep_stability = 1, freq_range = c(0.5, 3), amp_range = c(0.5, 1.5), base_level = 0.05, rectify_output = TRUE, seed )generate_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 1, cluster_sep_temporal = 1, cluster_sep_stability = 1, freq_range = c(0.5, 3), amp_range = c(0.5, 1.5), base_level = 0.05, rectify_output = TRUE, seed )
N |
Number of subjects (time series). Default is 30. |
K |
Number of clusters (subgroups). Default is 3. |
r |
Number of synergies per cluster. Default is 3. |
M |
Number of observed channels (muscles). Default is 8. |
T_each |
Time-series length per subject. Default is 200. |
cluster_sep_spatial |
Numeric scalar (0-2) controlling spatial structure differentiation between clusters. Default is 1.0. |
cluster_sep_temporal |
Numeric scalar (0-2) controlling temporal coordination differentiation between clusters. Default is 1.0. |
cluster_sep_stability |
Numeric scalar (0-2) controlling stability-adaptability differentiation between clusters. Default is 1.0. |
freq_range |
Numeric vector of length 2 specifying the range of base frequencies (in Hz) for the periodic activation signals. Default is c(0.5, 3.0). |
amp_range |
Numeric vector of length 2 specifying the range of amplitudes for the periodic activation signals. Default is c(0.5, 1.5). |
base_level |
Numeric scalar specifying the baseline activation level. Default is 0.05. |
rectify_output |
Logical; if TRUE, apply half-wave rectification. Default is TRUE. |
seed |
Random seed for reproducibility. Required for deterministic results. |
This function is designed for use in parameter sweep experiments where model
selection (K, r) is performed on generated data. The key differences from
simulate_dynamic_synergy_data are:
Returns list_of_data (renamed from X_list) for consistency
with fitting functions
Returns true_cluster (renamed from z_true) for consistency
with evaluation functions
Includes a params list for tracking generation parameters
Seed is required (not optional) to ensure reproducibility
A list with the following components:
list_of_dataList of length N; each element is a (T_each x M) matrix of generated EMG signals. This is the standard input format for MFA/MPCA fitting.
true_clusterInteger vector of length N indicating true cluster
assignments (1 to K). Named as true_cluster for consistency.
true_Lambda_listList of length K; each element is a (M x r) matrix of true cluster-specific synergy loadings. Essential for subspace recovery evaluation. This is the canonical name for ground truth basis matrices.
paramsList containing all generation parameters for reproducibility. Includes both canonical short names (T, sep_spatial, sep_temporal, sep_stability) and full names (T_each, cluster_sep_spatial, etc.) for compatibility. Also includes r_mode = "global" for future extension.
Lambda_listList of length K; each element is a (M x r) matrix
of cluster-specific synergy loadings. Kept for backward compatibility;
identical to true_Lambda_list.
C_listList of length N; each element is a (T_each x r) matrix of synergy activation signals (for visualization/validation).
spatial_paramsList containing spatial structure parameters for each cluster.
temporal_paramsList containing temporal coordination parameters for each cluster.
stability_paramsList containing stability-adaptability parameters for each cluster.
simulate_dynamic_synergy_data for the underlying
simulation function, run_param_sweep_modelsel for parameter
sweep experiments.
## Not run: # Generate data for model selection experiment data <- generate_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 1.0, cluster_sep_temporal = 1.0, cluster_sep_stability = 1.0, seed = 123 ) # Access the data for fitting list_of_data <- data$list_of_data true_cluster <- data$true_cluster # Fit MFA model fit <- mfa_em_fit(list_of_data, K = 3, r = 3) # Evaluate clustering accuracy ari <- mclust::adjustedRandIndex(true_cluster, fit$z) ## End(Not run)## Not run: # Generate data for model selection experiment data <- generate_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 1.0, cluster_sep_temporal = 1.0, cluster_sep_stability = 1.0, seed = 123 ) # Access the data for fitting list_of_data <- data$list_of_data true_cluster <- data$true_cluster # Fit MFA model fit <- mfa_em_fit(list_of_data, K = 3, r = 3) # Evaluate clustering accuracy ari <- mclust::adjustedRandIndex(true_cluster, fit$z) ## End(Not run)
After calling select_optimal_K_r_mfa (or a similar function),
you have $all_models containing fits for various (K, r). This
function extracts the model for a user-specified pair (K_target, r_target).
get_model_by_K_r(selection_obj, K_target, r_target)get_model_by_K_r(selection_obj, K_target, r_target)
selection_obj |
The object returned by |
K_target |
Desired number of clusters. |
r_target |
Desired factor dimension. |
The fitted model (the same structure returned by mfa_em_fit),
or NULL if no match found.
## Not run: sel_obj <- select_optimal_K_r_mfa(my_data, Kvec=2:4, rvec=1:3) best_model <- get_model_by_K_r(sel_obj, K_target=3, r_target=2) ## End(Not run)## Not run: sel_obj <- select_optimal_K_r_mfa(my_data, Kvec=2:4, rvec=1:3) best_model <- get_model_by_K_r(sel_obj, K_target=3, r_target=2) ## End(Not run)
Given a selection_obj from select_optimal_K_r_mpca,
extracts the model for the specified (K_target, r_target) if it exists.
get_model_by_K_r_mpca(selection_obj, K_target, r_target)get_model_by_K_r_mpca(selection_obj, K_target, r_target)
selection_obj |
The output of |
K_target |
Desired K. |
r_target |
Desired r. |
The fitted model (same structure as from mixture_pca_em_fit), or NULL.
This function returns a small data.frame that describes the parameter
ranges used in the simulation (e.g., K, r, N, M,
T_each, etc.).
make_table1()make_table1()
A data.frame with columns Parameter and Values.
## Not run: table1 <- make_table1() print(table1) ## End(Not run)## Not run: table1 <- make_table1() print(table1) ## End(Not run)
This function filters the data for certain separation/noise conditions
(e.g., sep=1.0 and noise=1.0) and computes group-wise means and
standard deviations for ARI and BIC. It returns a small summary table.
make_table2(df)make_table2(df)
df |
A |
A data.frame summarizing ARI/BIC means and sds, grouped by
(K_true, r_true, N, M).
## Not run: df <- read_all_results("results") table2 <- make_table2(df) print(table2) ## End(Not run)## Not run: df <- read_all_results("results") table2 <- make_table2(df) print(table2) ## End(Not run)
This function calls the C++ function mfaTimeseriesCpp() to perform a Mixture
Factor Analysis EM algorithm for fixed K and r. By default, it runs
a single pass with the internal initialization from C++. However, if you specify
multiple initial attempts (via n_init>1) and/or use_kmeans_init=TRUE,
this function will try several different initial cluster assignments (in parallel
using mclapply), then return the best solution (maximizing the final log-likelihood).
mfa_em_fit( list_of_data, K, r, max_iter = 50, iter_fa = 20, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, kmeans_rdim = r, mc_cores = 1, seed = NULL, verbose = TRUE, n_threads = 0, cpp_seed = 0, progress_callback = NULL, ... )mfa_em_fit( list_of_data, K, r, max_iter = 50, iter_fa = 20, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, kmeans_rdim = r, mc_cores = 1, seed = NULL, verbose = TRUE, n_threads = 0, cpp_seed = 0, progress_callback = NULL, ... )
list_of_data |
A list of matrices (each |
K |
Number of clusters. |
r |
Factor dimension. |
max_iter |
Maximum EM iterations for |
iter_fa |
Number of sub-iterations for the factor analyzer update in C++.
(Replaces deprecated |
tol |
Convergence tolerance for |
n_init |
Number of random initial assignments to try (in addition to the default
single-run or k-means if requested). Defaults to |
use_kmeans_init |
If |
kmeans_rdim |
PCA dimension for extracting subject-level features,
used only if |
mc_cores |
Number of cores for parallel execution via |
seed |
Random seed for reproducibility (default: NULL). |
verbose |
Logical; if |
n_threads |
Integer; number of OpenMP threads to use for parallel computation (0 = auto). Default is |
cpp_seed |
Integer; random seed for C++ RNG (0 = default/no seed). Default is |
progress_callback |
Optional function to report progress from C++. Should accept two arguments: current iteration and total iterations. |
... |
Additional arguments for backwards compatibility. Deprecated arguments like
|
The single-run approach in C++ already does a built-in initialization if z_init
is not provided. Therefore, if n_init=1 and use_kmeans_init=FALSE, we just call
mfaTimeseriesCpp once (like the original design).
Otherwise:
If use_kmeans_init=TRUE, we do one run where we assign clusters by k-means
on some subject-level features (extracted by PCA).
We also sample n_init random assignments (each subject assigned to a random cluster).
For each assignment, we call mfa_em_fit_cpp_singleInit.
We compare all results' logLik and keep the best one.
This provides a more robust initialization scheme to avoid poor local maxima.
A list with the same elements as a single run: z, pi, mu, Lambda, Psi, logLik, resp.
It corresponds to the best solution (i.e. highest log-likelihood) among all tried inits.
mixture_pca_em_fit for MPCA fitting,
select_r for selecting optimal r,
plot_cluster_synergy_loadings_mfa for visualization
## Not run: # Suppose we have a list_of_data for N=100 subjects, each (T_i x M=8). # We want to fit K=3, r=2, and try 5 random inits plus one k-means init: fit <- mfa_em_fit( list_of_data, K=3, r=2, max_iter=50, iter_fa=20, tol=1e-3, n_init=5, use_kmeans_init=TRUE, kmeans_rdim=2, mc_cores=2, seed=123 ) print(fit$logLik) head(fit$z) ## End(Not run)## Not run: # Suppose we have a list_of_data for N=100 subjects, each (T_i x M=8). # We want to fit K=3, r=2, and try 5 random inits plus one k-means init: fit <- mfa_em_fit( list_of_data, K=3, r=2, max_iter=50, iter_fa=20, tol=1e-3, n_init=5, use_kmeans_init=TRUE, kmeans_rdim=2, mc_cores=2, seed=123 ) print(fit$logLik) head(fit$z) ## End(Not run)
This helper function calls the C++ routine mfaTimeseriesCpp() with a user-specified
cluster assignment (z_init) and then computes the final log-likelihood and
responsibilities in R.
mfa_em_fit_cpp_singleInit( list_of_data, K, r, z_init, max_iter = 50, nIterFA = 20, tol = 0.001, verbose = TRUE, n_threads = 0, seed = 0, progress_callback = NULL, em_type = c("hard", "soft") )mfa_em_fit_cpp_singleInit( list_of_data, K, r, z_init, max_iter = 50, nIterFA = 20, tol = 0.001, verbose = TRUE, n_threads = 0, seed = 0, progress_callback = NULL, em_type = c("hard", "soft") )
list_of_data |
A list of |
K |
Number of clusters. |
r |
Factor dimension in each cluster. |
z_init |
An integer vector of length |
max_iter |
Maximum EM iterations in C++. |
nIterFA |
Number of sub-iterations for the factor analyzer update in C++. |
tol |
Convergence tolerance used in C++. |
verbose |
Logical; if |
n_threads |
Integer; number of OpenMP threads to use (0 = auto). Default is |
seed |
Integer; random seed for C++ RNG (0 = default/no seed). Default is |
progress_callback |
Optional function to report progress from C++. Should accept two arguments: current iteration and total iterations. |
em_type |
Character; type of EM algorithm to use. Either "hard" (classification EM with hard assignments) or "soft" (standard EM with responsibility-weighted updates). Default is "hard". |
A list with elements:
zHard cluster assignments, length N.
piCluster mixing proportions, length K.
muList of length K, each a mean vector (M x 1).
LambdaList of length K, each an M x r factor loading matrix.
PsiList of length K, each an M x M diagonal noise matrix.
logLikFinal log-likelihood computed in R.
respAn N x K matrix of responsibilities.
## Not run: # Suppose we have list_of_data, K=3, r=2: z_init <- sample.int(3, size=length(list_of_data), replace=TRUE) fit_one <- mfa_em_fit_cpp_singleInit(list_of_data, K=3, r=2, z_init=z_init) fit_one$logLik ## End(Not run)## Not run: # Suppose we have list_of_data, K=3, r=2: z_init <- sample.int(3, size=length(list_of_data), replace=TRUE) fit_one <- mfa_em_fit_cpp_singleInit(list_of_data, K=3, r=2, z_init=z_init) fit_one$logLik ## End(Not run)
This function calls the C++ function mpcaTimeseriesCpp() to perform a
Mixture PCA (PPCA) EM algorithm for fixed K and r, then converts
the W matrices into (P, D), creates Psi, and computes the final
log-likelihood/responsibilities in R. By default, it runs a single pass with
the built-in initialization in C++. However, if n_init > 1 or
use_kmeans_init=TRUE, it performs multiple initializations in parallel
and returns the best-fitting result (highest log-likelihood).
mixture_pca_em_fit( list_of_data, K, r, max_iter = 50, iter_pca = 20, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, kmeans_rdim = r, mc_cores = 1, seed = NULL, verbose = TRUE, n_threads = 0, cpp_seed = 0, progress_callback = NULL, ... )mixture_pca_em_fit( list_of_data, K, r, max_iter = 50, iter_pca = 20, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, kmeans_rdim = r, mc_cores = 1, seed = NULL, verbose = TRUE, n_threads = 0, cpp_seed = 0, progress_callback = NULL, ... )
list_of_data |
A list of matrices (each |
K |
Number of clusters. |
r |
Number of principal components. |
max_iter |
Maximum EM iterations for the C++ routine. |
iter_pca |
Sub-iterations for updating each cluster's PPCA parameters.
(Replaces deprecated |
tol |
Convergence tolerance for |
method |
Either |
n_init |
Integer; how many random initial assignments to try (in addition to
the default single-run or k-means if requested). Defaults to |
use_kmeans_init |
Logical; if |
kmeans_rdim |
The PCA dimension for the subject-level feature extraction,
used only if |
mc_cores |
Number of cores for parallel execution via |
seed |
Random seed for reproducibility (default: NULL). |
verbose |
Logical; if |
n_threads |
Integer; number of OpenMP threads to use for parallel computation (0 = auto). Default is |
cpp_seed |
Integer; random seed for C++ RNG (0 = default/no seed). Default is |
progress_callback |
Optional function to report progress from C++. Should accept two arguments: current iteration and total iterations. |
... |
Additional arguments for backwards compatibility. Deprecated arguments like
|
If n_init=1 and use_kmeans_init=FALSE, this function runs exactly one pass
with the default initialization in C++ (i.e. subject i is assigned to cluster
(i % K) + 1). Otherwise:
If use_kmeans_init=TRUE, we do a run where we apply k-means to some
subject-level PCA features to get z_init, then run EM once.
We generate n_init random initial assignments, run EM for each in parallel,
and collect the results.
We compare all solutions by final log-likelihood and pick the best.
A list with elements:
z |
Hard cluster assignments (1..K). |
pi |
Mixing proportions. |
mu |
List of length K, each a mean vector. |
P |
List of length K, each |
D |
List of length K, each |
Psi |
List of length K, each |
logLik |
Final log-likelihood over all data. |
sigma2 |
Numeric vector of length K for |
resp |
|
mfa_em_fit for MFA fitting,
select_r for selecting optimal r,
plot_cluster_synergy_loadings_mpca for visualization
## Not run: # Suppose we have a list_of_data, K=3, r=2, and we want to try 5 random inits + k-means: fit <- mixture_pca_em_fit( list_of_data, K=3, r=2, max_iter=50, iter_pca=20, tol=1e-3, method="EM", n_init=5, use_kmeans_init=TRUE, kmeans_rdim=2, mc_cores=2 ) print(fit$logLik) head(fit$z) ## End(Not run)## Not run: # Suppose we have a list_of_data, K=3, r=2, and we want to try 5 random inits + k-means: fit <- mixture_pca_em_fit( list_of_data, K=3, r=2, max_iter=50, iter_pca=20, tol=1e-3, method="EM", n_init=5, use_kmeans_init=TRUE, kmeans_rdim=2, mc_cores=2 ) print(fit$logLik) head(fit$z) ## End(Not run)
This helper function calls the updated C++ routine mpcaTimeseriesCpp()
with a user-specified cluster assignment (z_init), then converts
the returned W into (P, D) and constructs Psi, and finally
computes the final log-likelihood and responsibilities in R.
mixture_pca_em_fit_cpp_singleInit( list_of_data, K, r, max_iter = 50, nIterPCA = 20, tol = 0.001, method = "EM", z_init, verbose = TRUE, n_threads = 0, seed = 0, progress_callback = NULL, em_type = c("hard", "soft") )mixture_pca_em_fit_cpp_singleInit( list_of_data, K, r, max_iter = 50, nIterPCA = 20, tol = 0.001, method = "EM", z_init, verbose = TRUE, n_threads = 0, seed = 0, progress_callback = NULL, em_type = c("hard", "soft") )
list_of_data |
A list of matrices (each |
K |
Number of clusters. |
r |
Number of principal components (dimension). |
max_iter |
Maximum EM iterations (C++). |
nIterPCA |
Sub-iterations for updating each cluster's PPCA parameters in C++. |
tol |
Convergence tolerance (C++). |
method |
Either |
z_init |
An integer vector of length |
verbose |
Logical; if |
n_threads |
Integer; number of OpenMP threads to use (0 = auto). Default is |
seed |
Integer; random seed for C++ RNG (0 = default/no seed). Default is |
progress_callback |
Optional function to report progress from C++. Should accept two arguments: current iteration and total iterations. |
em_type |
Character; type of EM algorithm to use. Either "hard" (classification EM with hard assignments) or "soft" (standard EM with responsibility-weighted updates). Default is "hard". |
A list with elements:
z |
Hard cluster assignments (1..K). |
pi |
Mixing proportions (length K). |
mu |
List of length K, each a mean vector (length M). |
W |
List of length K, each an |
P |
List of length K, each an |
D |
List of length K, each an |
Psi |
List of length K, each an |
logLik |
Final log-likelihood computed in R. |
sigma2 |
Numeric vector of length K, the final |
resp |
An |
## Not run: # Suppose we have list_of_data, K=3, r=2, method="EM", plus some z_init: z_init <- sample.int(3, size=length(list_of_data), replace=TRUE) fit_one <- mixture_pca_em_fit_cpp_singleInit( list_of_data, K=3, r=2, max_iter=50, nIterPCA=20, tol=1e-3, method="EM", z_init=z_init ) print(fit_one$logLik) # Now we can call compute_factor_scores_mpca(fit_one, list_of_data) because fit_one$W exists ## End(Not run)## Not run: # Suppose we have list_of_data, K=3, r=2, method="EM", plus some z_init: z_init <- sample.int(3, size=length(list_of_data), replace=TRUE) fit_one <- mixture_pca_em_fit_cpp_singleInit( list_of_data, K=3, r=2, max_iter=50, nIterPCA=20, tol=1e-3, method="EM", z_init=z_init ) print(fit_one$logLik) # Now we can call compute_factor_scores_mpca(fit_one, list_of_data) because fit_one$W exists ## End(Not run)
Normalizes EMG signals using various methods to allow comparison across channels, subjects, or sessions.
normalize_emg(data, method = "max", reference = NULL, per_channel = TRUE)normalize_emg(data, method = "max", reference = NULL, per_channel = TRUE)
data |
EMG signal. Can be a numeric vector (single channel), a matrix (T x M, time x channels), or a list of matrices. |
method |
Normalization method:
|
reference |
Reference values for MVC normalization.
Can be a single value (applied to all channels) or a vector
(one value per channel). Only used when |
per_channel |
Logical. If TRUE (default), normalize each channel independently. If FALSE, use global statistics across all channels. |
Normalization is essential for:
Comparing EMG across different muscles
Comparing EMG across different subjects
Comparing EMG across different recording sessions
MVC normalization (method = "mvc") is the gold standard
in EMG research, expressing activation as a percentage of maximum
voluntary contraction. Requires separate MVC trials for reference.
Max normalization (method = "max") is useful when MVC
data is not available, normalizing to the peak value in the data.
Normalized EMG signal, same structure as input.
# Max normalization (0 to 1 range) emg <- matrix(rnorm(1000), ncol = 4) norm_emg <- normalize_emg(emg, method = "max") # MVC normalization (% MVC) mvc_values <- c(100, 150, 80, 120) # MVC for each channel norm_emg <- normalize_emg(emg, method = "mvc", reference = mvc_values) # Z-score normalization norm_emg <- normalize_emg(emg, method = "zscore")# Max normalization (0 to 1 range) emg <- matrix(rnorm(1000), ncol = 4) norm_emg <- normalize_emg(emg, method = "max") # MVC normalization (% MVC) mvc_values <- c(100, 150, 80, 120) # MVC for each channel norm_emg <- normalize_emg(emg, method = "mvc", reference = mvc_values) # Z-score normalization norm_emg <- normalize_emg(emg, method = "zscore")
Applies a notch (band-stop) filter to remove power line interference (50 Hz or 60 Hz) and optionally its harmonics.
notch_filter( data, sampling_rate, notch_freq = 50, Q = 30, harmonics = TRUE, zero_phase = TRUE )notch_filter( data, sampling_rate, notch_freq = 50, Q = 30, harmonics = TRUE, zero_phase = TRUE )
data |
EMG signal. Can be a numeric vector (single channel), a matrix (T x M, time x channels), or a list of matrices. |
sampling_rate |
Sampling frequency in Hz. |
notch_freq |
Frequency to remove in Hz. Default is 50 Hz. Use 60 Hz for regions with 60 Hz power lines (e.g., Americas, Japan). |
Q |
Quality factor determining the filter bandwidth. Higher Q = narrower notch. Default is 30. |
harmonics |
Logical. If TRUE (default), also removes harmonics (2x, 3x, etc. of notch_freq up to Nyquist frequency). |
zero_phase |
Logical. If TRUE (default), applies zero-phase filtering. |
Power line interference (50/60 Hz) is a common artifact in EMG recordings.
The notch filter creates a narrow band-stop at the specified frequency.
When harmonics = TRUE, harmonics (100/120 Hz, 150/180 Hz, etc.)
are also removed.
Filtered EMG signal with power line noise removed.
## Not run: # Remove 50 Hz power line noise clean_emg <- notch_filter(emg, sampling_rate = 1000, notch_freq = 50) # Remove 60 Hz (Americas) with harmonics clean_emg <- notch_filter(emg, sampling_rate = 1000, notch_freq = 60, harmonics = TRUE) ## End(Not run)## Not run: # Remove 50 Hz power line noise clean_emg <- notch_filter(emg, sampling_rate = 1000, notch_freq = 50) # Remove 60 Hz (Americas) with harmonics clean_emg <- notch_filter(emg, sampling_rate = 1000, notch_freq = 60, harmonics = TRUE) ## End(Not run)
Visualizes temporal activation curves per cluster by showing representative activation patterns from subjects in each cluster.
plot_activation_patterns(sim, n_subjects_per_cluster = 3, theme_base_size = 14)plot_activation_patterns(sim, n_subjects_per_cluster = 3, theme_base_size = 14)
sim |
A list returned by |
n_subjects_per_cluster |
Number of subjects to display per cluster. Default is 3. |
theme_base_size |
Base font size for the plot theme. Default is 14. |
A ggplot object showing temporal activation curves per cluster.
## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_activation_patterns(sim) ## End(Not run)## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_activation_patterns(sim) ## End(Not run)
Creates heatmaps of basis vectors (W matrices) for each subject and component, showing how well the Two-step alignment procedure worked. Compares aligned basis vectors with true synergies (if available) to diagnose alignment failures.
plot_aligned_basis_heatmaps( W_list, W_true = NULL, z_true = NULL, z_est = NULL, max_subjects = 30, theme_base_size = 10 )plot_aligned_basis_heatmaps( W_list, W_true = NULL, z_true = NULL, z_est = NULL, max_subjects = 30, theme_base_size = 10 )
W_list |
List of basis matrices, one per subject. Each matrix should be
M x r (M channels/muscles, r components/synergies). This is typically the
output from |
W_true |
Optional list of true basis matrices for comparison (from simulation
data, e.g., |
z_true |
Optional vector of true cluster assignments (length N). Used to organize subjects by cluster. If NULL, subjects are shown in original order. |
z_est |
Optional vector of estimated cluster assignments (length N). Used to show clustering results alongside basis vectors. Default is NULL. |
max_subjects |
Maximum number of subjects to display. If N > max_subjects, a random sample will be shown. Default is 30. |
theme_base_size |
Base font size for the plot theme. Default is 10. |
This function visualizes the output of the Two-step alignment procedure
(align_basis_across_subjects()) to diagnose alignment failures. Each
row represents one subject's basis vector for a specific component. Columns
represent muscles/channels. Colors indicate the weight/loading values.
When W_true is provided, the function creates a side-by-side comparison
showing true synergies (left panel) and estimated aligned basis vectors (right
panel). This helps identify whether alignment failures are due to:
Poor individual decomposition (Step 1)
Alignment algorithm issues (Step 1.5)
Fundamental differences between true and estimated structures
A ggplot object showing heatmaps of basis vectors organized by subject and component, with optional comparison to true synergies.
## Not run: # Simulate data with known ground truth sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) # Fit Two-step baseline fit <- fit_two_step_baseline( sim$list_of_data, r=3, K=3, method="PCA", z_true=sim$z_true, align_basis=TRUE ) # Visualize aligned basis vectors plot_aligned_basis_heatmaps(fit$W_list, z_est=fit$z_est) # Compare with true synergies plot_aligned_basis_heatmaps( fit$W_list, W_true=sim$Lambda_list, z_true=sim$z_true, z_est=fit$z_est ) ## End(Not run)## Not run: # Simulate data with known ground truth sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) # Fit Two-step baseline fit <- fit_two_step_baseline( sim$list_of_data, r=3, K=3, method="PCA", z_true=sim$z_true, align_basis=TRUE ) # Visualize aligned basis vectors plot_aligned_basis_heatmaps(fit$W_list, z_est=fit$z_est) # Compare with true synergies plot_aligned_basis_heatmaps( fit$W_list, W_true=sim$Lambda_list, z_true=sim$z_true, z_est=fit$z_est ) ## End(Not run)
This function computes the factor scores Z_i(t) for each subject i, identifies that subject's cluster k, and then creates a large facet plot of the time evolution of each factor (1..r) in each cluster (1..K). Optionally overlays all subjects in the same cluster.
plot_all_factor_scores_mfa( mfa_fit, list_of_data, overlay_subjects = TRUE, muscle_names = NULL )plot_all_factor_scores_mfa( mfa_fit, list_of_data, overlay_subjects = TRUE, muscle_names = NULL )
mfa_fit |
A fitted MFA model (with z, Lambda, Psi, mu, etc.). |
list_of_data |
A list of (T_i x M) data matrices. |
overlay_subjects |
Logical; if TRUE, all subjects in the same cluster are overlaid in the same facet. If FALSE, you could average them, etc. |
muscle_names |
Optional character vector of muscle names for y-axis labels. If NULL, default channel names will be used. |
A ggplot object that shows the factor scores over time, with facets by (Cluster, Factor).
## Not run: p <- plot_all_factor_scores_mfa(my_mfa_fit, list_of_data) print(p) ## End(Not run)## Not run: p <- plot_all_factor_scores_mfa(my_mfa_fit, list_of_data) print(p) ## End(Not run)
This function uses precomputed factor scores mpca_fit$factor_scores[[i]]
(each T_i x r) and plots them over time, grouped by cluster z[i].
Optionally overlays all subjects in the same cluster on one facet, or can average them.
plot_all_factor_scores_mpca( mpca_fit, list_of_data, overlay_subjects = TRUE, muscle_names = NULL )plot_all_factor_scores_mpca( mpca_fit, list_of_data, overlay_subjects = TRUE, muscle_names = NULL )
mpca_fit |
A fitted MPCA model (with z, W, mu, etc.) plus
|
list_of_data |
A list of (T_i x M) data matrices (just for dimension reference). |
overlay_subjects |
Logical; if TRUE, all subjects in the same cluster are overlaid in the same facet. If FALSE, we can average them etc. |
muscle_names |
Optional character vector of muscle names for y-axis labels. If NULL, default channel names will be used. |
A ggplot object that shows the factor scores over time, with facets by (Cluster, Factor).
## Not run: mpca_fit <- compute_factor_scores_mpca(mpca_fit, list_of_data) p <- plot_all_factor_scores_mpca(mpca_fit, list_of_data, overlay_subjects=TRUE) print(p) ## End(Not run)## Not run: mpca_fit <- compute_factor_scores_mpca(mpca_fit, list_of_data) p <- plot_all_factor_scores_mpca(mpca_fit, list_of_data, overlay_subjects=TRUE) print(p) ## End(Not run)
This function plots the reconstructed waveforms (Xhat_i) for each subject across all channels, grouped by cluster. By default, it overlays all subjects in the same cluster, then uses facet to separate by (Cluster, Channel).
plot_all_reconstructed_waveforms_mfa( mfa_fit, list_of_data, overlay_subjects = TRUE, muscle_names = NULL )plot_all_reconstructed_waveforms_mfa( mfa_fit, list_of_data, overlay_subjects = TRUE, muscle_names = NULL )
mfa_fit |
A fitted MFA model (with z, Lambda, Psi, mu, etc.). |
list_of_data |
A list of (T_i x M) data matrices used in fitting. |
overlay_subjects |
Logical; if TRUE, each subject in the same cluster is drawn in the same facet. If FALSE, the function computes the average waveforms across subjects in each cluster. |
muscle_names |
Optional character vector of muscle names for y-axis labels. If NULL, default channel names will be used. |
A ggplot object with line plots of reconstructed waveforms, facet by cluster & channel.
## Not run: p_recon <- plot_all_reconstructed_waveforms_mfa(mfa_fit, list_of_data) print(p_recon) ## End(Not run)## Not run: p_recon <- plot_all_reconstructed_waveforms_mfa(mfa_fit, list_of_data) print(p_recon) ## End(Not run)
This function plots the reconstructed waveforms (Xhat_i) for each subject across all channels, grouped by cluster. By default, it overlays all subjects in the same cluster, then uses facet to separate by (Cluster, Channel).
plot_all_reconstructed_waveforms_mpca( mpca_fit, list_of_data, overlay_subjects = TRUE, muscle_names = NULL )plot_all_reconstructed_waveforms_mpca( mpca_fit, list_of_data, overlay_subjects = TRUE, muscle_names = NULL )
mpca_fit |
A fitted MPCA model (with z, W, mu, etc.).
Also |
list_of_data |
A list of (T_i x M) data matrices used in fitting. |
overlay_subjects |
Logical; if TRUE, each subject in the same cluster is drawn in the same facet. If FALSE, the function computes the average waveforms across subjects in each cluster. |
muscle_names |
Optional character vector of muscle names for y-axis labels. If NULL, default channel names will be used. |
A ggplot object with line plots of reconstructed waveforms, facet by cluster & channel.
## Not run: mpca_fit <- compute_factor_scores_mpca(mpca_fit, list_of_data) p_recon <- plot_all_reconstructed_waveforms_mpca(mpca_fit, list_of_data) print(p_recon) ## End(Not run)## Not run: mpca_fit <- compute_factor_scores_mpca(mpca_fit, list_of_data) p_recon <- plot_all_reconstructed_waveforms_mpca(mpca_fit, list_of_data) print(p_recon) ## End(Not run)
Creates a UMAP or PCA embedding of basis vectors at the component level (not subject level) to visualize clustering quality. Each point represents one basis vector (subject x component), colored by true cluster and shaped by estimated cluster. This helps diagnose clustering failures in the Two-step algorithm.
plot_basis_umap( W_list, z_true, z_est = NULL, method = "umap", theme_base_size = 14 )plot_basis_umap( W_list, z_true, z_est = NULL, method = "umap", theme_base_size = 14 )
W_list |
List of basis matrices, one per subject. Each matrix should be
M x r (M channels/muscles, r components/synergies). This is typically the
output from |
z_true |
Vector of true cluster assignments (length N). Required for coloring points by true cluster. |
z_est |
Optional vector of estimated cluster assignments (length N). If provided, points will be shaped by estimated cluster to show mismatches. Default is NULL. |
method |
Character string specifying the embedding method: "umap" or "pca". Default is "umap". |
theme_base_size |
Base font size for the plot theme. Default is 14. |
This function extends plot_cluster_embedding() to work at the basis
vector level rather than the subject level. Instead of showing N points
(one per subject), it shows Nxr points (one per basis vector).
This visualization is particularly useful for diagnosing Two-step clustering failures because it reveals:
Whether basis vectors from the same true cluster are close together
Whether k-means clustering in Step 2 correctly separated clusters
Which specific basis vectors were misclassified
Whether alignment in Step 1.5 successfully matched corresponding components
When z_est is provided, misclassified basis vectors are easy to spot
as points with different colors (true cluster) and shapes (estimated cluster).
A ggplot object showing low-dimensional embedding of basis vectors (Nxr points), colored by true cluster and optionally shaped by estimated cluster.
## Not run: # Simulate data with known ground truth sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) # Fit Two-step baseline fit <- fit_two_step_baseline( sim$list_of_data, r=3, K=3, method="PCA", z_true=sim$z_true, align_basis=TRUE ) # Visualize basis vector embedding plot_basis_umap(fit$W_list, z_true=sim$z_true, z_est=fit$z_est) # Use PCA instead of UMAP plot_basis_umap(fit$W_list, z_true=sim$z_true, z_est=fit$z_est, method="pca") ## End(Not run)## Not run: # Simulate data with known ground truth sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) # Fit Two-step baseline fit <- fit_two_step_baseline( sim$list_of_data, r=3, K=3, method="PCA", z_true=sim$z_true, align_basis=TRUE ) # Visualize basis vector embedding plot_basis_umap(fit$W_list, z_true=sim$z_true, z_est=fit$z_est) # Use PCA instead of UMAP plot_basis_umap(fit$W_list, z_true=sim$z_true, z_est=fit$z_est, method="pca") ## End(Not run)
Creates a boxplot or violin plot comparing BIC values across methods and model types. Lower BIC values indicate better model fit.
plot_bic_comparison(aggregated_df, plot_type = "boxplot")plot_bic_comparison(aggregated_df, plot_type = "boxplot")
aggregated_df |
Data frame with aggregated results from |
plot_type |
Character. Type of plot. One of "boxplot" or "violin". Default is "boxplot". |
A ggplot2 object
## Not run: library(synergyMixR) results <- run_param_sweep(test = TRUE, cores = 2) # Plot BIC comparison p <- plot_bic_comparison(results$aggregated_results) print(p) ## End(Not run)## Not run: library(synergyMixR) results <- run_param_sweep(test = TRUE, cores = 2) # Plot BIC comparison p <- plot_bic_comparison(results$aggregated_results) print(p) ## End(Not run)
Takes the summary data.frame from select_optimal_K_r_mfa() (which has columns
K, r, logLik, BIC) and produces a simple line plot of BIC. You can choose whether
the x-axis is K or r, and color/line by the other.
plot_bic_line(df_summary, x_axis = c("K", "r"))plot_bic_line(df_summary, x_axis = c("K", "r"))
df_summary |
A data.frame with columns |
x_axis |
One of |
A ggplot object.
Creates a reliability diagram (calibration plot) showing the relationship between predicted probabilities and observed frequencies.
plot_calibration( calib_result, show_histogram = TRUE, by_cluster = FALSE, title = "Calibration Plot", ... )plot_calibration( calib_result, show_histogram = TRUE, by_cluster = FALSE, title = "Calibration Plot", ... )
calib_result |
Result from |
show_histogram |
Logical. If TRUE, show histogram of predictions below the calibration curve. Default: TRUE. |
by_cluster |
Logical. If TRUE, show separate curves for each cluster. If FALSE, aggregate across clusters. Default: FALSE. |
title |
Character. Plot title. Default: "Calibration Plot". |
... |
Additional arguments passed to ggplot2 functions. |
A reliability diagram plots mean predicted probability (x-axis) against mean observed frequency (y-axis) for each bin. A perfectly calibrated model follows the diagonal line (y = x). Points above the diagonal indicate underconfidence; points below indicate overconfidence.
The shaded band around the diagonal shows +/- 0.1 deviation as a reference. The ECE value is displayed in the plot subtitle.
A ggplot2 object.
## Not run: calib <- compute_calibration(fit$resp, z_true) # Basic calibration plot p <- plot_calibration(calib) print(p) # Show by cluster p <- plot_calibration(calib, by_cluster = TRUE) print(p) # Save to file ggsave("calibration.pdf", p, width = 6, height = 5) ## End(Not run)## Not run: calib <- compute_calibration(fit$resp, z_true) # Basic calibration plot p <- plot_calibration(calib) print(p) # Show by cluster p <- plot_calibration(calib, by_cluster = TRUE) print(p) # Save to file ggsave("calibration.pdf", p, width = 6, height = 5) ## End(Not run)
Creates a low-dimensional embedding (UMAP or PCA) to visualize cluster separability. Each point represents a subject, colored by true cluster assignment.
plot_cluster_embedding(sim, fit = NULL, method = "umap", theme_base_size = 14)plot_cluster_embedding(sim, fit = NULL, method = "umap", theme_base_size = 14)
sim |
A list returned by |
fit |
Optional fitted model object (e.g., from MFA/MPCA). If provided, predicted cluster assignments can be overlaid. Default is NULL. |
method |
Character string specifying the embedding method: "umap" or "pca". Default is "umap". |
theme_base_size |
Base font size for the plot theme. Default is 14. |
A ggplot object showing low-dimensional embedding of subjects.
## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_cluster_embedding(sim, method = "umap") plot_cluster_embedding(sim, method = "pca") ## End(Not run)## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_cluster_embedding(sim, method = "umap") plot_cluster_embedding(sim, method = "pca") ## End(Not run)
This function takes a fitted MFA model (e.g., from mfa_em_fit()) and
produces a faceted heatmap or bar plot of each cluster's factor loadings.
plot_cluster_synergy_loadings_mfa( mfa_fit, cluster_ids = NULL, plot_type = c("heatmap", "bar"), muscle_names = NULL )plot_cluster_synergy_loadings_mfa( mfa_fit, cluster_ids = NULL, plot_type = c("heatmap", "bar"), muscle_names = NULL )
mfa_fit |
A fitted MFA model object containing |
cluster_ids |
A numeric vector of cluster IDs to plot. Defaults to all. |
plot_type |
One of |
muscle_names |
Optional character vector of muscle names for y-axis labels. If NULL, default channel names will be used. |
A ggplot object (which you can print or further modify).
## Not run: # Suppose we have a best MFA model in 'best_mfa_model' p <- plot_cluster_synergy_loadings_mfa(best_mfa_model, cluster_ids = 1:2) print(p) ## End(Not run)## Not run: # Suppose we have a best MFA model in 'best_mfa_model' p <- plot_cluster_synergy_loadings_mfa(best_mfa_model, cluster_ids = 1:2) print(p) ## End(Not run)
This function takes a fitted MPCA model (e.g. from mixture_pca_em_fit())
and produces a faceted heatmap or bar plot of each cluster's factor loadings
W[[k]] (an M x r matrix).
plot_cluster_synergy_loadings_mpca( mpca_fit, cluster_ids = NULL, plot_type = c("heatmap", "bar"), muscle_names = NULL )plot_cluster_synergy_loadings_mpca( mpca_fit, cluster_ids = NULL, plot_type = c("heatmap", "bar"), muscle_names = NULL )
mpca_fit |
A fitted MPCA model object containing |
cluster_ids |
A numeric vector of cluster IDs to plot. Defaults to all. |
plot_type |
One of |
muscle_names |
Optional character vector of muscle names for y-axis labels. If NULL, default channel names will be used. |
A ggplot object (which you can print or further modify).
## Not run: # Suppose we have a best MPCA model in 'best_mpca_model' # that has best_mpca_model$W[[k]] for each cluster p <- plot_cluster_synergy_loadings_mpca(best_mpca_model, cluster_ids = 1:2) print(p) ## End(Not run)## Not run: # Suppose we have a best MPCA model in 'best_mpca_model' # that has best_mpca_model$W[[k]] for each cluster p <- plot_cluster_synergy_loadings_mpca(best_mpca_model, cluster_ids = 1:2) print(p) ## End(Not run)
Creates a confusion matrix heatmap comparing true cluster assignments with estimated cluster assignments. This is the standard way to visualize clustering accuracy and identify systematic misclassification patterns.
plot_confusion_matrix(z_true, z_est, normalize = "true", theme_base_size = 14)plot_confusion_matrix(z_true, z_est, normalize = "true", theme_base_size = 14)
z_true |
Vector of true cluster assignments (length N, values 1 to K). |
z_est |
Vector of estimated cluster assignments (length N, values 1 to K). |
normalize |
Character string specifying normalization: "none" (raw counts), "true" (normalize by true cluster size), or "pred" (normalize by predicted cluster size). Default is "true". |
theme_base_size |
Base font size for the plot theme. Default is 14. |
The confusion matrix shows the correspondence between true and estimated cluster assignments. Rows represent true clusters, columns represent estimated clusters. Cell values indicate the number (or proportion) of subjects with that true-estimated cluster pair.
Perfect clustering produces a diagonal matrix (all subjects correctly assigned). Off-diagonal entries indicate misclassifications. This visualization complements the ARI metric by showing:
Which clusters are confused with each other
Whether misclassifications are systematic or random
Cluster size imbalances
Label permutation issues (if estimated clusters are numbered differently)
Normalization options:
"none": Raw counts (useful for seeing absolute numbers)
"true": Divide by true cluster size (shows recall/sensitivity)
"pred": Divide by predicted cluster size (shows precision)
A ggplot object showing the confusion matrix as a heatmap.
## Not run: # Simulate data sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) # Fit Two-step baseline fit <- fit_two_step_baseline( sim$list_of_data, r=3, K=3, method="PCA", z_true=sim$z_true, align_basis=TRUE ) # Plot confusion matrix plot_confusion_matrix(sim$z_true, fit$z_est) # Show raw counts instead of proportions plot_confusion_matrix(sim$z_true, fit$z_est, normalize="none") # Normalize by predicted cluster size plot_confusion_matrix(sim$z_true, fit$z_est, normalize="pred") ## End(Not run)## Not run: # Simulate data sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) # Fit Two-step baseline fit <- fit_two_step_baseline( sim$list_of_data, r=3, K=3, method="PCA", z_true=sim$z_true, align_basis=TRUE ) # Plot confusion matrix plot_confusion_matrix(sim$z_true, fit$z_est) # Show raw counts instead of proportions plot_confusion_matrix(sim$z_true, fit$z_est, normalize="none") # Normalize by predicted cluster size plot_confusion_matrix(sim$z_true, fit$z_est, normalize="pred") ## End(Not run)
Creates a faceted plot showing ARI (Adjusted Rand Index) values for MFA and MPCA across different separation and noise conditions.
plot_fig1_ARI(df)plot_fig1_ARI(df)
df |
A |
A ggplot object.
## Not run: df <- read_all_results("results") p <- plot_fig1_ARI(df) print(p) ggsave("figure1_ARI.pdf", p, width = 8, height = 6) ## End(Not run)## Not run: df <- read_all_results("results") p <- plot_fig1_ARI(df) print(p) ggsave("figure1_ARI.pdf", p, width = 8, height = 6) ## End(Not run)
Creates a bar plot comparing ARI and VAF values across different methods, including Two-step baselines. This visualization highlights the performance differences between single-model approaches, two-step baselines, and mixture models.
plot_fig1_baseline_comparison(df, metric = c("ARI", "VAF"))plot_fig1_baseline_comparison(df, metric = c("ARI", "VAF"))
df |
A |
metric |
Character string specifying which metric to plot: "ARI" or "VAF". Defaults to "ARI". |
The plot uses color coding to distinguish between method types:
Single methods (SingleFA, SinglePCA) - shown in one color group
Two-step methods (TwoStep_FA, TwoStep_PCA) - shown in another color group
Mixture methods (MixtureFA, MixturePCA) - shown in a third color group
This visualization is designed to demonstrate the superiority of mixture-based approaches over simpler baseline methods.
A ggplot object showing a bar plot of the specified metric by method.
## Not run: df_comp <- simulate_and_compare_5methods( N = 100, K_true = 3, r_true = 4, M = 6, T_each = 100 ) p_ari <- plot_fig1_baseline_comparison(df_comp, metric = "ARI") p_vaf <- plot_fig1_baseline_comparison(df_comp, metric = "VAF") print(p_ari) ggsave("baseline_comparison_ARI.pdf", p_ari, width = 8, height = 6) ## End(Not run)## Not run: df_comp <- simulate_and_compare_5methods( N = 100, K_true = 3, r_true = 4, M = 6, T_each = 100 ) p_ari <- plot_fig1_baseline_comparison(df_comp, metric = "ARI") p_vaf <- plot_fig1_baseline_comparison(df_comp, metric = "VAF") print(p_ari) ggsave("baseline_comparison_ARI.pdf", p_ari, width = 8, height = 6) ## End(Not run)
Creates a heatmap of BIC values for a specific subset of conditions.
plot_fig2_BIC_heatmap(df)plot_fig2_BIC_heatmap(df)
df |
A |
A ggplot object.
## Not run: df <- read_all_results("results") p <- plot_fig2_BIC_heatmap(df) print(p) ggsave("figure2_BIC.pdf", p, width = 6, height = 5) ## End(Not run)## Not run: df <- read_all_results("results") p <- plot_fig2_BIC_heatmap(df) print(p) ggsave("figure2_BIC.pdf", p, width = 6, height = 5) ## End(Not run)
Creates a boxplot showing the distribution of ARI values across multiple random initializations.
plot_fig3_init_boxplot(df)plot_fig3_init_boxplot(df)
df |
A |
A ggplot object.
## Not run: df <- read_all_results("results") p <- plot_fig3_init_boxplot(df) print(p) ggsave("figure3_boxplot.pdf", p, width = 6, height = 4) ## End(Not run)## Not run: df <- read_all_results("results") p <- plot_fig3_init_boxplot(df) print(p) ggsave("figure3_boxplot.pdf", p, width = 6, height = 4) ## End(Not run)
Creates visualizations of reconstruction error (SSE) and Variance Accounted For (VAF) for different methods and conditions.
plot_fig4to6_reconstruction_vaf(df)plot_fig4to6_reconstruction_vaf(df)
df |
A |
A ggplot object.
## Not run: df <- read_all_results("results") p <- plot_fig4to6_reconstruction_vaf(df) print(p) ggsave("figure4to6_VAF.pdf", p, width = 10, height = 8) ## End(Not run)## Not run: df <- read_all_results("results") p <- plot_fig4to6_reconstruction_vaf(df) print(p) ggsave("figure4to6_VAF.pdf", p, width = 10, height = 8) ## End(Not run)
Creates a line plot showing how a performance metric varies with a parameter axis (e.g., cluster separation). Useful for exploring parameter sensitivity.
plot_metric_vs_axis( aggregated_df, metric = "ARI", axis = "cluster_sep_spatial", facet_by = "model_type", color_by = "Method", show_error_bars = TRUE )plot_metric_vs_axis( aggregated_df, metric = "ARI", axis = "cluster_sep_spatial", facet_by = "model_type", color_by = "Method", show_error_bars = TRUE )
aggregated_df |
Data frame with aggregated results from |
metric |
Character. Metric to plot. One of "ARI", "VAF", "BIC", "SSE". Default is "ARI". |
axis |
Character. Parameter axis to plot on x-axis. One of "cluster_sep_spatial", "cluster_sep_temporal", "cluster_sep_stability", "N", "K", "r". Default is "cluster_sep_spatial". |
facet_by |
Character. Variable to facet by. One of "model_type" or "Method". Default is "model_type". |
color_by |
Character. Variable to color by. One of "Method" or "model_type". Default is "Method". |
show_error_bars |
Logical. Whether to show error bars (mean +/- sd). Default is TRUE. |
A ggplot2 object
## Not run: library(synergyMixR) results <- run_param_sweep(test = TRUE, cores = 2) # Plot ARI vs spatial separation p1 <- plot_metric_vs_axis( results$aggregated_results, metric = "ARI", axis = "cluster_sep_spatial" ) print(p1) # Plot VAF vs temporal separation p2 <- plot_metric_vs_axis( results$aggregated_results, metric = "VAF", axis = "cluster_sep_temporal" ) print(p2) ## End(Not run)## Not run: library(synergyMixR) results <- run_param_sweep(test = TRUE, cores = 2) # Plot ARI vs spatial separation p1 <- plot_metric_vs_axis( results$aggregated_results, metric = "ARI", axis = "cluster_sep_spatial" ) print(p1) # Plot VAF vs temporal separation p2 <- plot_metric_vs_axis( results$aggregated_results, metric = "VAF", axis = "cluster_sep_temporal" ) print(p2) ## End(Not run)
Visualizes time-varying neural command trajectories estimated from synergy activation patterns. This function creates a low-dimensional representation of the temporal evolution of neural control signals, revealing how motor commands change over time within and across clusters.
plot_neural_command( sim, method = "pca", color_by = "cluster", smooth = TRUE, theme_base_size = 14 )plot_neural_command( sim, method = "pca", color_by = "cluster", smooth = TRUE, theme_base_size = 14 )
sim |
A list returned by |
method |
Character string specifying the embedding method: "pca" or "umap". Default is "pca". |
color_by |
Character string specifying how to color points: "cluster" (by cluster assignment) or "time" (by temporal progression). Default is "cluster". |
smooth |
Logical; if TRUE, connect time points with smooth paths using geom_path with alpha gradient. Default is TRUE. |
theme_base_size |
Base font size for the plot theme. Default is 14. |
A ggplot object showing neural command trajectories in 2D space.
## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_neural_command(sim, method = "pca", color_by = "cluster") plot_neural_command(sim, method = "umap", color_by = "time", smooth = TRUE) ## End(Not run)## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_neural_command(sim, method = "pca", color_by = "cluster") plot_neural_command(sim, method = "umap", color_by = "time", smooth = TRUE) ## End(Not run)
Visualizes the distribution of noise parameters across clusters, showing how stability-adaptability varies between clusters.
plot_noise_profiles(sim, theme_base_size = 14)plot_noise_profiles(sim, theme_base_size = 14)
sim |
A list returned by |
theme_base_size |
Base font size for the plot theme. Default is 14. |
A ggplot object showing noise parameter distributions per cluster.
## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_noise_profiles(sim) ## End(Not run)## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_noise_profiles(sim) ## End(Not run)
Visualizes EMG time-series per cluster and subject. When cluster_id is NULL, shows all clusters. For each cluster, individual subject EMG traces are shown as thin semi-transparent lines, with the cluster-mean waveform overlaid as a bold black line.
plot_reconstructed_emg( sim, cluster_id = NULL, muscles = NULL, mean_ci = FALSE, theme_base_size = 13 )plot_reconstructed_emg( sim, cluster_id = NULL, muscles = NULL, mean_ci = FALSE, theme_base_size = 13 )
sim |
A list returned by |
cluster_id |
Integer specifying which cluster to plot. If NULL, plots all clusters. Default is NULL. |
muscles |
Integer vector specifying which muscles to plot. If NULL, plots all muscles. Default is NULL. |
mean_ci |
Logical; if TRUE, display +/-1 SD ribbons (not yet implemented). Default is FALSE. |
theme_base_size |
Base font size for the plot theme. Default is 13. |
A ggplot object showing EMG time-series with individual subjects and cluster means.
## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_reconstructed_emg(sim) plot_reconstructed_emg(sim, cluster_id = 1) plot_reconstructed_emg(sim, muscles = c(1, 2, 3)) ## End(Not run)## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_reconstructed_emg(sim) plot_reconstructed_emg(sim, cluster_id = 1) plot_reconstructed_emg(sim, muscles = c(1, 2, 3)) ## End(Not run)
Creates a heatmap showing Sum of Squared Errors (SSE) for each subject across different methods. This helps identify which methods perform poorly for specific subjects and reveals the instability of the Two-step approach.
plot_sse_heatmap( results_list, list_of_data, log_scale = TRUE, theme_base_size = 12 )plot_sse_heatmap( results_list, list_of_data, log_scale = TRUE, theme_base_size = 12 )
results_list |
A named list of method results. Each element should be a fitted model object containing SSE information. Names should be method names (e.g., "TwoStep_PCA", "MixtureFA", "SinglePCA"). |
list_of_data |
List of data matrices, one per subject (T_i x M). Required to compute per-subject SSE if not already in results. |
log_scale |
Logical. If TRUE, displays log10(SSE) instead of raw SSE. Recommended for better visualization when SSE values span multiple orders of magnitude. Default is TRUE. |
theme_base_size |
Base font size for the plot theme. Default is 12. |
This function computes per-subject reconstruction errors for multiple methods and displays them as a heatmap. Darker colors indicate higher errors (worse reconstruction). This visualization is useful for:
Comparing reconstruction quality across methods
Identifying subjects that are poorly reconstructed by Two-step methods
Revealing instability in Two-step assignments (high SSE for misclassified subjects)
Showing that mixture models provide more consistent reconstruction
The function expects results from fit_all_methods_on_data() or similar
comparison functions. It computes per-subject SSE by reconstructing each
subject's data using the assigned cluster model.
A ggplot object showing a heatmap of SSE values (subjects x methods).
## Not run: # Simulate data sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) # Fit all methods results <- fit_all_methods_on_data( sim$list_of_data, z_true=sim$z_true, N=30, K=3, r=3, M=8, seed=123 ) # Create SSE heatmap plot_sse_heatmap(results, sim$list_of_data) # Use linear scale instead of log scale plot_sse_heatmap(results, sim$list_of_data, log_scale=FALSE) ## End(Not run)## Not run: # Simulate data sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) # Fit all methods results <- fit_all_methods_on_data( sim$list_of_data, z_true=sim$z_true, N=30, K=3, r=3, M=8, seed=123 ) # Create SSE heatmap plot_sse_heatmap(results, sim$list_of_data) # Use linear scale instead of log scale plot_sse_heatmap(results, sim$list_of_data, log_scale=FALSE) ## End(Not run)
Creates a bar plot comparing method performance across all parameter combinations, showing mean performance with error bars.
plot_sweep_summary( aggregated_df, metric = "ARI", facet_by = "model_type", summary = "mean_sd" )plot_sweep_summary( aggregated_df, metric = "ARI", facet_by = "model_type", summary = "mean_sd" )
aggregated_df |
Data frame with aggregated results from |
metric |
Character. Metric to plot. One of "ARI", "VAF", "BIC", "SSE". Default is "ARI". |
facet_by |
Character. Variable to facet by. One of "model_type" or "Method". Default is "model_type". |
summary |
Character. Type of summary to show. One of "mean_sd" (mean +/- sd) or "min_max" (min to max range). Default is "mean_sd". |
A ggplot2 object
## Not run: library(synergyMixR) results <- run_param_sweep(test = TRUE, cores = 2) # Plot overall ARI comparison p <- plot_sweep_summary(results$aggregated_results, metric = "ARI") print(p) ## End(Not run)## Not run: library(synergyMixR) results <- run_param_sweep(test = TRUE, cores = 2) # Plot overall ARI comparison p <- plot_sweep_summary(results$aggregated_results, metric = "ARI") print(p) ## End(Not run)
Creates heatmaps of synergy matrices (Lambda_k) for each cluster. Each heatmap shows the muscle-synergy structure with muscles on the y-axis and synergies on the x-axis.
plot_synergy_bases(sim, theme_base_size = 14)plot_synergy_bases(sim, theme_base_size = 14)
sim |
A list returned by |
theme_base_size |
Base font size for the plot theme. Default is 14. |
A ggplot object showing heatmaps of synergy matrices per cluster.
## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_synergy_bases(sim) ## End(Not run)## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_synergy_bases(sim) ## End(Not run)
Compares true synergies with estimated synergies by computing and visualizing
the correlation matrix between them. This extends the existing
plot_synergy_correlation() function to compare true vs estimated
synergies rather than comparing between clusters.
plot_synergy_correlation_comparison( W_true, W_est, z_true, z_est, cluster_id = NULL, method = "pearson", theme_base_size = 12 )plot_synergy_correlation_comparison( W_true, W_est, z_true, z_est, cluster_id = NULL, method = "pearson", theme_base_size = 12 )
W_true |
List of true basis matrices (e.g., |
W_est |
List of estimated basis matrices (e.g., from fitted model). Each matrix should be M x r. |
z_true |
Vector of true cluster assignments (length N). |
z_est |
Vector of estimated cluster assignments (length N). |
cluster_id |
Integer specifying which cluster to analyze. If NULL, analyzes all clusters separately. Default is NULL. |
method |
Correlation method: "pearson", "kendall", or "spearman". Default is "pearson". |
theme_base_size |
Base font size for the plot theme. Default is 12. |
This function computes the correlation between true synergy patterns (from simulation data) and estimated synergy patterns (from fitted models). For each cluster, it creates a correlation matrix where:
Rows represent true synergies (components)
Columns represent estimated synergies (components)
Cell values show correlation between true component i and estimated component j
Perfect recovery produces a diagonal matrix with high correlations (close to 1) on the diagonal and low correlations off-diagonal. This indicates that each estimated component correctly matches its corresponding true component.
Common failure patterns:
Permuted components: High correlations off-diagonal (alignment failure)
Low correlations everywhere: Poor decomposition quality
Mixed patterns: Some components recovered, others not
A ggplot object showing correlation heatmap(s) between true and estimated synergies.
## Not run: # Simulate data sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) # Fit Two-step baseline fit <- fit_two_step_baseline( sim$list_of_data, r=3, K=3, method="PCA", z_true=sim$z_true, align_basis=TRUE ) # Compare true and estimated synergies plot_synergy_correlation_comparison( sim$Lambda_list, fit$W_list, sim$z_true, fit$z_est ) # Analyze specific cluster plot_synergy_correlation_comparison( sim$Lambda_list, fit$W_list, sim$z_true, fit$z_est, cluster_id = 1 ) ## End(Not run)## Not run: # Simulate data sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) # Fit Two-step baseline fit <- fit_two_step_baseline( sim$list_of_data, r=3, K=3, method="PCA", z_true=sim$z_true, align_basis=TRUE ) # Compare true and estimated synergies plot_synergy_correlation_comparison( sim$Lambda_list, fit$W_list, sim$z_true, fit$z_est ) # Analyze specific cluster plot_synergy_correlation_comparison( sim$Lambda_list, fit$W_list, sim$z_true, fit$z_est, cluster_id = 1 ) ## End(Not run)
Creates a comprehensive summary plot combining multiple visualization panels using patchwork. This provides an overview of spatial synergy structures, temporal activation dynamics, and cluster separability.
plot_synergy_summary(sim, fit = NULL, theme_base_size = 12)plot_synergy_summary(sim, fit = NULL, theme_base_size = 12)
sim |
A list returned by |
fit |
Optional fitted model object (e.g., from MFA/MPCA). Default is NULL. |
theme_base_size |
Base font size for the plot theme. Default is 12. |
A patchwork object combining multiple ggplot panels.
## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_synergy_summary(sim) ## End(Not run)## Not run: sim <- simulate_dynamic_synergy_data(N=30, K=3, r=3, M=8, T_each=200) plot_synergy_summary(sim) ## End(Not run)
Plot Original vs. Reconstructed Waveform for an MFA Model
plot_waveform_comparison_mfa( mfa_fit, list_of_data, subject_id, channel = 1, muscle_names = NULL )plot_waveform_comparison_mfa( mfa_fit, list_of_data, subject_id, channel = 1, muscle_names = NULL )
mfa_fit |
A fitted MFA model with |
list_of_data |
The original data list used to fit the model. |
subject_id |
Index of the subject to plot. |
channel |
Which channel (muscle) to plot. Defaults to 1. |
muscle_names |
Optional character vector of muscle names for y-axis labels. If NULL, default channel names will be used. |
A ggplot object showing original and reconstructed waveforms.
Plot Original vs. Reconstructed Waveform for an MPCA Model
plot_waveform_comparison_mpca( mpca_fit, list_of_data, subject_id, channel = 1, muscle_names = NULL )plot_waveform_comparison_mpca( mpca_fit, list_of_data, subject_id, channel = 1, muscle_names = NULL )
mpca_fit |
A fitted MPCA model with |
list_of_data |
The original data list used to fit the model. |
subject_id |
Index of the subject to plot (1-based). |
channel |
Which channel (1-based) to plot. Defaults to 1. |
muscle_names |
Optional character vector of muscle names for y-axis labels. If NULL, default channel names will be used. |
A ggplot object showing original and reconstructed waveforms.
Creates a heatmap showing the percentage of parameter combinations where each method performed best for each metric.
plot_winrate_heatmap(win_rates_df, facet_by = "metric")plot_winrate_heatmap(win_rates_df, facet_by = "metric")
win_rates_df |
Data frame with win rates from |
facet_by |
Character. Variable to facet by. One of "model_type" or "metric". Default is "metric". |
A ggplot2 object
## Not run: library(synergyMixR) results <- run_param_sweep(test = TRUE, cores = 2) # Read win rates win_rates <- read.csv(results$win_rates_file) # Plot win rate heatmap p <- plot_winrate_heatmap(win_rates) print(p) ## End(Not run)## Not run: library(synergyMixR) results <- run_param_sweep(test = TRUE, cores = 2) # Read win rates win_rates <- read.csv(results$win_rates_file) # Plot win rate heatmap p <- plot_winrate_heatmap(win_rates) print(p) ## End(Not run)
Visualize r-selection results with multiple plot types.
## S3 method for class 'mixture_r_selection' plot( x, type = c("overview", "global_cv", "cluster_metrics", "r_comparison", "cluster_scores"), ... )## S3 method for class 'mixture_r_selection' plot( x, type = c("overview", "global_cv", "cluster_metrics", "r_comparison", "cluster_scores"), ... )
x |
A mixture_r_selection object. |
type |
Type of plot to generate. Options:
|
... |
Additional arguments (ignored). |
The plot method provides several visualization types depending on the selection mode:
For global-first mode: - "global_cv": Shows CV error curve with selected r_global
For clusterwise mode: - "cluster_metrics": Heatmap of VAF/VSS/smoothness for each cluster and r value - "cluster_scores": Composite scores showing how each cluster's metrics vary with r
For hybrid mode: - All of the above plus "r_comparison" showing r_global vs cluster-specific r values
The "overview" type automatically generates a multi-panel plot with all relevant visualizations for the given mode.
## Not run: result <- select_r_mixture(list_of_data, K = 3, mode = "hybrid") plot(result) # Overview plot(result, type = "global_cv") plot(result, type = "cluster_metrics") plot(result, type = "r_comparison") ## End(Not run)## Not run: result <- select_r_mixture(list_of_data, K = 3, mode = "hybrid") plot(result) # Overview plot(result, type = "global_cv") plot(result, type = "cluster_metrics") plot(result, type = "r_comparison") ## End(Not run)
Given the output of select_optimal_K_r_mfa, this function computes
additional metrics for each fitted model in all_models, such as
global VAF (compute_global_vaf_mfa) and cluster sizes
(compute_cluster_sizes).
posthoc_mfa_evaluation(list_of_data, selection_obj)posthoc_mfa_evaluation(list_of_data, selection_obj)
list_of_data |
The same list of data used to fit the models. |
selection_obj |
The object returned by |
This function loops over each entry in selection_obj$all_models,
extracts the model, calls compute_global_vaf_mfa and
compute_cluster_sizes, and records the results in a combined table.
A data frame with columns:
K |
Number of clusters. |
r |
Factor dimension. |
logLik |
Log-likelihood from the fit. |
BIC |
BIC from the fit. |
GlobalVAF |
Global variance accounted for, |
minClusterSize |
Minimum cluster size. |
maxClusterSize |
Maximum cluster size. |
select_optimal_K_r_mfa, compute_factor_scores
## Not run: sel_obj <- select_optimal_K_r_mfa(my_data, Kvec=2:4, rvec=1:3) df_posthoc <- posthoc_mfa_evaluation(my_data, sel_obj) head(df_posthoc) ## End(Not run)## Not run: sel_obj <- select_optimal_K_r_mfa(my_data, Kvec=2:4, rvec=1:3) df_posthoc <- posthoc_mfa_evaluation(my_data, sel_obj) head(df_posthoc) ## End(Not run)
Takes the output of select_optimal_K_r_mpca and computes additional
metrics (global VAF, cluster sizes, etc.) for each entry in all_models.
posthoc_mpca_evaluation(list_of_data, selection_obj)posthoc_mpca_evaluation(list_of_data, selection_obj)
list_of_data |
The same list of data used for the grid search. |
selection_obj |
The object returned by |
A data frame with columns K, r, logLik, BIC, GlobalVAF, minClusterSize, maxClusterSize.
Applies a complete preprocessing pipeline to raw EMG data, transforming it into the format required for MFA/MPCA analysis.
preprocess_emg( raw_data, sampling_rate, pipeline_config = "default", mvc_data = NULL, channel_names = NULL, verbose = TRUE )preprocess_emg( raw_data, sampling_rate, pipeline_config = "default", mvc_data = NULL, channel_names = NULL, verbose = TRUE )
raw_data |
Raw EMG data. Can be:
|
sampling_rate |
Sampling frequency in Hz. |
pipeline_config |
Preprocessing configuration. Can be:
|
mvc_data |
Optional MVC reference data for MVC normalization. Can be a matrix (T x M) or a list of matrices. |
channel_names |
Optional character vector of channel/muscle names. |
verbose |
Logical. If TRUE (default), prints progress information. |
The preprocessing pipeline transforms raw EMG signals into activation patterns suitable for muscle synergy analysis:
Raw EMG --> [DC Removal] --> [Bandpass] --> [Notch] --> [Rectify]
| | | |
Remove bias Extract signal Remove power Convert to
and drift bandwidth line noise positive
|
v
Preprocessed <-- [Normalize] <-- [Envelope] <-------+
(list_of_data) | |
Scale for Extract amplitude
comparison modulation
Removes electrode DC bias and signal drift. Methods: "mean" (subtract mean), "linear" (detrend), "polynomial". Typical use: Always recommended as first step.
Extracts the EMG frequency band (typically 20-450 Hz). Removes low-frequency motion artifacts (<20 Hz) and high-frequency noise (>450 Hz). Parameters: low_cutoff=20, high_cutoff=450, order=4 (Butterworth).
Removes power line interference (50 Hz in Japan/Europe, 60 Hz in Americas). Can also remove harmonics (100, 150, 200 Hz, etc.). Parameters: freq=50 or 60, Q=30, harmonics=TRUE.
Converts bipolar EMG to unipolar by taking absolute value (full-wave) or setting negatives to zero (half-wave). Full-wave rectification is standard for envelope extraction.
Extracts the amplitude envelope representing muscle activation pattern. Methods: "lowpass" (4-10 Hz cutoff), "rms" (root mean square), "moving_average". Lowpass with 6 Hz cutoff is most common.
Scales signals for comparison across muscles/subjects/sessions. Methods: "mvc" (percentage of max voluntary contraction - gold standard), "max" (peak value), "zscore" (standardization), "range" (0-1 scaling).
General-purpose settings. Bandpass 20-450 Hz, 50 Hz notch, lowpass envelope (6 Hz), max normalization.
Optimized for walking/gait analysis. Linear detrend, slower envelope (4 Hz cutoff), MVC normalization.
For sustained contractions. RMS envelope (100 ms window), MVC normalization. No time normalization needed.
For precise movements. Wider bandwidth (10-500 Hz), faster envelope (10 Hz cutoff).
config <- list( dc_removal = list(method = "mean"), bandpass = list(low = 20, high = 450, order = 4), notch = list(freq = 50, harmonics = TRUE), rectify = list(method = "full_wave"), envelope = list(method = "lowpass", cutoff = 6), normalize = list(method = "max") )
Set any step to NULL or FALSE to skip it.
An object of class "preprocessed_emg" containing:
data: Preprocessed data in list_of_data format (ready for MFA/MPCA)
processing_info: Record of all preprocessing steps and parameters
channel_names: Channel names
sampling_rate: Original sampling rate
emg_preset_config for preset configurations,
bandpass_filter, notch_filter,
rectify, extract_envelope,
normalize_emg for individual processing functions.
## Not run: # Basic usage with default settings raw_emg <- matrix(rnorm(1000 * 8), ncol = 8) processed <- preprocess_emg(raw_emg, sampling_rate = 1000) # Use with MFA analysis fit <- mfa_em_fit(processed$data, K = 2, r = 3) # Custom configuration config <- list( bandpass = list(low = 30, high = 400), notch = list(freq = 60), # 60 Hz for Americas envelope = list(method = "rms", window_ms = 50), normalize = list(method = "mvc") ) processed <- preprocess_emg(raw_emg, sampling_rate = 1000, pipeline_config = config, mvc_data = mvc_trials) ## End(Not run)## Not run: # Basic usage with default settings raw_emg <- matrix(rnorm(1000 * 8), ncol = 8) processed <- preprocess_emg(raw_emg, sampling_rate = 1000) # Use with MFA analysis fit <- mfa_em_fit(processed$data, K = 2, r = 3) # Custom configuration config <- list( bandpass = list(low = 30, high = 400), notch = list(freq = 60), # 60 Hz for Americas envelope = list(method = "rms", window_ms = 50), normalize = list(method = "mvc") ) processed <- preprocess_emg(raw_emg, sampling_rate = 1000, pipeline_config = config, mvc_data = mvc_trials) ## End(Not run)
Print Summary of Bootstrap CI Results
## S3 method for class 'bootstrap_ci' print(x, cluster = 1, ...)## S3 method for class 'bootstrap_ci' print(x, cluster = 1, ...)
x |
Result from bootstrap_loading_ci |
cluster |
Which cluster to summarize (default: 1) |
... |
Additional arguments (ignored) |
Print Summary of Calibration Results
## S3 method for class 'calibration_result' print(x, ...)## S3 method for class 'calibration_result' print(x, ...)
x |
A calibration_result object |
... |
Additional arguments (ignored) |
Print Method for mixture_r_selection Objects
## S3 method for class 'mixture_r_selection' print(x, ...)## S3 method for class 'mixture_r_selection' print(x, ...)
x |
A mixture_r_selection object. |
... |
Additional arguments (ignored). |
Print Method for preprocessed_emg Objects
## S3 method for class 'preprocessed_emg' print(x, ...)## S3 method for class 'preprocessed_emg' print(x, ...)
x |
A preprocessed_emg object |
... |
Additional arguments (ignored) |
This function searches a directory for .rds files, each presumably containing
one or more rows of simulation results, then merges them into a single data frame.
Each row includes a file column indicating the source file path.
read_all_results(result_dir = "results")read_all_results(result_dir = "results")
result_dir |
A character string specifying the directory to look for |
If no files are found, the function raises an error. Otherwise, each file is read with
readRDS and merged using dplyr::bind_rows, which safely handles
heterogeneous column structures by filling missing columns with NA.
A combined data.frame with rows from all loaded files, including a file column.
## Not run: df <- read_all_results("results") head(df) ## End(Not run)## Not run: df <- read_all_results("results") head(df) ## End(Not run)
This function reads all .rds result files in a specified directory, merges them
into a single data frame, prints summary tables, and generates several figures.
read_and_visualize_all(result_dir = "results")read_and_visualize_all(result_dir = "results")
result_dir |
A character string specifying the directory containing |
Invisibly returns the merged data frame of all results.
## Not run: df_all <- read_and_visualize_all("results") head(df_all) ## End(Not run)## Not run: df_all <- read_and_visualize_all("results") head(df_all) ## End(Not run)
Reconstruct a single subject's data from a Mixture PCA model
reconstruct_singleMPCA(X, mu, W, Z)reconstruct_singleMPCA(X, mu, W, Z)
X |
Original |
mu |
An |
W |
An |
Z |
A |
A (T x M) reconstructed matrix Xhat
Applies rectification to EMG signals, converting all values to positive.
rectify(data, method = "full_wave")rectify(data, method = "full_wave")
data |
EMG signal. Can be a numeric vector (single channel), a matrix (T x M, time x channels), or a list of matrices. |
method |
Rectification method:
|
Rectification is a standard step in EMG processing that prepares the signal for envelope extraction. Full-wave rectification (absolute value) is most commonly used.
Rectified EMG signal.
signal <- rnorm(1000) rectified <- rectify(signal) # full-wave rectification half_rect <- rectify(signal, method = "half_wave")signal <- rnorm(1000) rectified <- rectify(signal) # full-wave rectification half_rect <- rectify(signal, method = "half_wave")
Removes the DC component (baseline offset) from EMG signals using various methods.
remove_dc_offset(data, method = "mean", poly_order = 1)remove_dc_offset(data, method = "mean", poly_order = 1)
data |
EMG signal. Can be a numeric vector (single channel), a matrix (T x M, time x channels), or a list of matrices. |
method |
Method for DC removal:
|
poly_order |
Polynomial order when |
Data with DC offset removed, same structure as input.
# Single channel signal <- rnorm(1000) + 0.5 clean <- remove_dc_offset(signal) # Multi-channel matrix emg <- matrix(rnorm(1000 * 8), nrow = 1000, ncol = 8) emg_clean <- remove_dc_offset(emg, method = "linear")# Single channel signal <- rnorm(1000) + 0.5 clean <- remove_dc_offset(signal) # Multi-channel matrix emg <- matrix(rnorm(1000 * 8), nrow = 1000, ncol = 8) emg_clean <- remove_dc_offset(emg, method = "linear")
Applies a chosen rotation (e.g., "varimax") to each cluster's loading matrix
(Lambda[[k]]). Optionally, also rotates the factor scores in
factor_scores[[i]] if they exist and rotate_scores=TRUE.
rotate_mfa_model( mfa_fit, rotation = c("varimax"), rotate_scores = FALSE, cluster_ids = NULL )rotate_mfa_model( mfa_fit, rotation = c("varimax"), rotate_scores = FALSE, cluster_ids = NULL )
mfa_fit |
A fitted MFA model, typically returned by
|
rotation |
A string specifying the rotation method. Currently supports |
rotate_scores |
Logical; if TRUE and |
cluster_ids |
Vector of cluster indices to rotate. Defaults to all. |
- Rotation does not change log-likelihood or BIC, just reorients factors for interpretability.
- If factor_scores is missing and rotate_scores=TRUE, you can either skip or error.
A new MFA model object, with rotated Lambda (and factor_scores if requested).
Other fields are unchanged.
Applies a chosen rotation (e.g. varimax) to each cluster's loading matrix W[[k]]
in a fitted MPCA model, optionally also rotating the subject factor scores
in factor_scores[[i]].
rotate_mpca_model( mpca_fit, rotation = c("varimax"), rotate_scores = FALSE, cluster_ids = NULL )rotate_mpca_model( mpca_fit, rotation = c("varimax"), rotate_scores = FALSE, cluster_ids = NULL )
mpca_fit |
A fitted MPCA model, e.g. returned by
|
rotation |
Rotation method, e.g. |
rotate_scores |
Logical; if TRUE, also rotate factor_scores if present. |
cluster_ids |
Vector of cluster indices to rotate. Defaults to all. |
In R's stats::varimax(), the matrix should have rows = variables, cols = factors.
If W_k is already (M x r), then passing it directly to varimax means
we have M variables, r factors. The returned rotation matrix is (r x r), and
scores_i (T_i x r) can be multiplied by that.
A new MPCA model object with W[[k]] rotated, and factor_scores
also rotated if requested and available.
Compares multiple K selection methods (BIC, ICL with various temperatures, Ensemble, Adaptive, Silhouette) across a parameter grid.
run_k_selection_comparison( test = FALSE, cores = 4, output_dir = NULL, parallel_strategy = c("local", "pbs", "future"), pbs_config = list(), pbs_submit = FALSE, pbs_wait = FALSE, Kvec = 2:6, r_fixed = 2, max_iter = 50, verbose = TRUE )run_k_selection_comparison( test = FALSE, cores = 4, output_dir = NULL, parallel_strategy = c("local", "pbs", "future"), pbs_config = list(), pbs_submit = FALSE, pbs_wait = FALSE, Kvec = 2:6, r_fixed = 2, max_iter = 50, verbose = TRUE )
test |
Logical. If TRUE, use smaller test grid. Default FALSE. |
cores |
Integer. Number of CPU cores. Default 4. |
output_dir |
Character. Output directory. Default auto-detected. |
parallel_strategy |
Character. "local", "pbs", or "future". |
pbs_config |
List. PBS configuration (queue, walltime, mem, r_module). |
pbs_submit |
Logical. If TRUE, submit PBS job. Default FALSE (dry run). |
pbs_wait |
Logical. If TRUE, wait for PBS completion. Default FALSE. |
Kvec |
Integer vector. Candidate K values. Default 2:6. |
r_fixed |
Integer. Fixed r value for two-stage. Default 2. |
max_iter |
Integer. Maximum EM iterations. Default 50. |
verbose |
Logical. Print progress. Default TRUE. |
This function compares the following K selection methods:
BIC: Bayesian Information Criterion
ICL_T1: ICL with temperature = 1.0
ICL_T2: ICL with temperature = 2.0 (recommended)
ICL_T3: ICL with temperature = 3.0
Ensemble: Majority vote of BIC, ICL_T1, ICL_T2
Adaptive: Adaptive temperature selection
Silhouette: Silhouette-based selection
Data frame with results, or PBS job info if using PBS.
## Not run: # Local test run results <- run_k_selection_comparison(test = TRUE, cores = 2) # Full simulation results <- run_k_selection_comparison(test = FALSE, cores = 8) # PBS submission run_k_selection_comparison( test = FALSE, parallel_strategy = "pbs", pbs_config = list(queue = "batch"), pbs_submit = TRUE ) ## End(Not run)## Not run: # Local test run results <- run_k_selection_comparison(test = TRUE, cores = 2) # Full simulation results <- run_k_selection_comparison(test = FALSE, cores = 8) # PBS submission run_k_selection_comparison( test = FALSE, parallel_strategy = "pbs", pbs_config = list(queue = "batch"), pbs_submit = TRUE ) ## End(Not run)
Orchestrates a comprehensive parameter sweep experiment to evaluate the performance of MFA, MPCA, and baseline methods using the v2 dynamic synergy simulator with three orthogonal control axes.
run_param_sweep( test = FALSE, cores = 4, output_dir = NULL, param_grid = NULL, verbose = TRUE )run_param_sweep( test = FALSE, cores = 4, output_dir = NULL, param_grid = NULL, verbose = TRUE )
test |
Logical. If TRUE, uses a smaller test grid for quick validation. Default is FALSE (full parameter grid). |
cores |
Integer. Number of CPU cores to use for parallel processing. Default is 4. Set to 1 for sequential processing. |
output_dir |
Character. Directory to save results. Default is "inst/paper/results_sweep" if it exists (repo use), otherwise "results_sweep" in the current working directory. |
param_grid |
Optional. Custom parameter grid data frame. If NULL,
uses the built-in full or test grid based on the |
verbose |
Logical. If TRUE, prints progress information. Default is TRUE. |
The parameter sweep evaluates:
6 methods: SingleFA, SinglePCA, TwoStep_FA, TwoStep_PCA, MixtureFA, MixturePCA
2 model types: Mixture (static) vs Dynamic_v2 (with 3 orthogonal axes)
Metrics: ARI (clustering accuracy), VAF (reconstruction quality), BIC, SSE
Variable parameters: N, K, r, cluster_sep_spatial, cluster_sep_temporal, cluster_sep_stability
For parallel processing (cores > 1), the function uses parLapplyLB for
load balancing. If the pbapply package is installed, a progress bar
will be displayed.
Invisibly returns a list containing:
raw_results: Data frame with raw results from all runs
aggregated_results: Data frame with results aggregated across seeds
summary_file: Path to the summary CSV file
win_rates_file: Path to the win rates CSV file
output_dir: Directory where results were saved
## Not run: # Run test mode with 2 cores results <- run_param_sweep(test = TRUE, cores = 2) # Run full sweep with 8 cores results <- run_param_sweep(test = FALSE, cores = 8) # Run with custom output directory results <- run_param_sweep(test = TRUE, cores = 2, output_dir = "my_results") # Run with custom parameter grid library(dplyr) custom_grid <- expand.grid( N = c(20, 50), K = c(2, 3), r = 2, M = 8, T_each = 200, cluster_sep_spatial = c(0.3, 0.6), cluster_sep_temporal = 0.6, cluster_sep_stability = 1.0, seed = 1:3, stringsAsFactors = FALSE ) custom_grid$run_id <- seq_len(nrow(custom_grid)) results <- run_param_sweep( param_grid = custom_grid, cores = 8, output_dir = "inst/paper/results_custom" ) # Access results directly head(results$raw_results) head(results$aggregated_results) ## End(Not run)## Not run: # Run test mode with 2 cores results <- run_param_sweep(test = TRUE, cores = 2) # Run full sweep with 8 cores results <- run_param_sweep(test = FALSE, cores = 8) # Run with custom output directory results <- run_param_sweep(test = TRUE, cores = 2, output_dir = "my_results") # Run with custom parameter grid library(dplyr) custom_grid <- expand.grid( N = c(20, 50), K = c(2, 3), r = 2, M = 8, T_each = 200, cluster_sep_spatial = c(0.3, 0.6), cluster_sep_temporal = 0.6, cluster_sep_stability = 1.0, seed = 1:3, stringsAsFactors = FALSE ) custom_grid$run_id <- seq_len(nrow(custom_grid)) results <- run_param_sweep( param_grid = custom_grid, cores = 8, output_dir = "inst/paper/results_custom" ) # Access results directly head(results$raw_results) head(results$aggregated_results) ## End(Not run)
Orchestrates a parameter sweep experiment to evaluate baseline method performance (SingleFA, SinglePCA, TwoStep_FA, TwoStep_PCA, MixtureFA, MixturePCA) using the v2 dynamic synergy simulator with three orthogonal control axes. This function focuses on method-level benchmarking rather than model comparison.
run_param_sweep_baselines( test = FALSE, grid_type = NULL, cores = 4, output_dir = NULL, param_grid = NULL, verbose = TRUE, align_basis = TRUE, refine_assignments = TRUE, parallel_strategy = c("grid", "sequential", "pbs", "future"), pbs_config = list(), pbs_submit = FALSE, pbs_wait = FALSE, future_backend = "multisession", future_resources = list() )run_param_sweep_baselines( test = FALSE, grid_type = NULL, cores = 4, output_dir = NULL, param_grid = NULL, verbose = TRUE, align_basis = TRUE, refine_assignments = TRUE, parallel_strategy = c("grid", "sequential", "pbs", "future"), pbs_config = list(), pbs_submit = FALSE, pbs_wait = FALSE, future_backend = "multisession", future_resources = list() )
test |
Logical. If TRUE, uses a smaller test grid for quick validation. Default is FALSE (full parameter grid). |
grid_type |
Character. Parameter grid type: "test", "paper_core", or
"paper_stress". If NULL (default), uses the |
cores |
Integer. Number of CPU cores to use for parallel processing. Default is 4. Set to 1 for sequential processing. |
output_dir |
Character. Directory to save results. Default is "inst/paper/results_baselines_v2" if it exists (repo use), otherwise "results_baselines_v2" in the current working directory. |
param_grid |
Optional. Custom parameter grid data frame. If NULL,
uses the built-in full or test grid based on the |
verbose |
Logical. If TRUE, prints progress information. Default is TRUE. |
align_basis |
Logical. If |
refine_assignments |
Logical. If |
parallel_strategy |
Character. Parallelization strategy:
Default is "grid". |
pbs_config |
List. PBS configuration options (only used when
parallel_strategy = "pbs"). See |
pbs_submit |
Logical. If TRUE and parallel_strategy = "pbs", submit the job to PBS. If FALSE, only generate scripts (dry run). Default is FALSE. |
pbs_wait |
Logical. If TRUE, wait for PBS job completion and aggregate results. Default is FALSE. |
future_backend |
Character. Backend for future parallelization (only used when parallel_strategy = "future"):
See |
future_resources |
List. HPC resource specifications for future.batchtools backends (e.g., list(walltime = "04:00:00", memory = "4gb")). |
This function complements run_param_sweep by focusing on
method-level benchmarking rather than model comparison. It evaluates:
6 methods: SingleFA, SinglePCA, TwoStep_FA, TwoStep_PCA, MixtureFA, MixturePCA
1 model type: Dynamic_v2 (with 3 orthogonal axes)
Metrics: ARI (clustering accuracy), VAF (reconstruction quality), BIC, SSE
Variable parameters: N, K, r, cluster_sep_spatial, cluster_sep_temporal, cluster_sep_stability
For parallel processing (cores > 1), the function uses parLapplyLB for
load balancing. If the pbapply package is installed, a progress bar
will be displayed.
Invisibly returns a list containing:
raw_results: Data frame with raw results from all runs
aggregated_results: Data frame with results aggregated across seeds
summary_file: Path to the summary CSV file
win_rates_file: Path to the win rates CSV file
output_dir: Directory where results were saved
When parallel_strategy = "pbs", this function generates PBS array job
scripts and optionally submits them. Each array task runs one parameter
combination. Results are saved as individual RDS files and can be aggregated
after job completion using aggregate_partial_results.
When parallel_strategy = "future", this function uses the future
framework for flexible parallelization. Local backends (multisession,
multicore) work out of the box. HPC backends (batchtools_torque,
batchtools_slurm) require the future.batchtools package and appropriate
cluster configuration.
compare_baselines for single-run baseline comparison,
run_param_sweep for model comparison parameter sweep,
plot_sweep_summary for visualization
## Not run: # Run test mode with 2 cores results <- run_param_sweep_baselines(test = TRUE, cores = 2) # Run full sweep with 8 cores results <- run_param_sweep_baselines(test = FALSE, cores = 8) # Run with custom output directory results <- run_param_sweep_baselines( test = TRUE, cores = 2, output_dir = "my_baselines_results" ) # Use future with local multisession backend results <- run_param_sweep_baselines( test = TRUE, parallel_strategy = "future", future_backend = "multisession", cores = 4 ) # Use PBS for HPC cluster results <- run_param_sweep_baselines( test = FALSE, parallel_strategy = "pbs", pbs_config = list(queue = "batch", walltime = "04:00:00", mem = "4gb"), pbs_submit = TRUE, pbs_wait = TRUE ) # Run with custom parameter grid library(dplyr) custom_grid <- expand.grid( N = c(20, 50), K = c(2, 3), r = 2, M = 8, T_each = 200, cluster_sep_spatial = c(0.3, 0.6), cluster_sep_temporal = 0.6, cluster_sep_stability = 1.0, seed = 1:3, stringsAsFactors = FALSE ) custom_grid$run_id <- seq_len(nrow(custom_grid)) results <- run_param_sweep_baselines( param_grid = custom_grid, cores = 8, output_dir = "inst/paper/results_baselines_custom" ) # Access results directly head(results$raw_results) head(results$aggregated_results) ## End(Not run)## Not run: # Run test mode with 2 cores results <- run_param_sweep_baselines(test = TRUE, cores = 2) # Run full sweep with 8 cores results <- run_param_sweep_baselines(test = FALSE, cores = 8) # Run with custom output directory results <- run_param_sweep_baselines( test = TRUE, cores = 2, output_dir = "my_baselines_results" ) # Use future with local multisession backend results <- run_param_sweep_baselines( test = TRUE, parallel_strategy = "future", future_backend = "multisession", cores = 4 ) # Use PBS for HPC cluster results <- run_param_sweep_baselines( test = FALSE, parallel_strategy = "pbs", pbs_config = list(queue = "batch", walltime = "04:00:00", mem = "4gb"), pbs_submit = TRUE, pbs_wait = TRUE ) # Run with custom parameter grid library(dplyr) custom_grid <- expand.grid( N = c(20, 50), K = c(2, 3), r = 2, M = 8, T_each = 200, cluster_sep_spatial = c(0.3, 0.6), cluster_sep_temporal = 0.6, cluster_sep_stability = 1.0, seed = 1:3, stringsAsFactors = FALSE ) custom_grid$run_id <- seq_len(nrow(custom_grid)) results <- run_param_sweep_baselines( param_grid = custom_grid, cores = 8, output_dir = "inst/paper/results_baselines_custom" ) # Access results directly head(results$raw_results) head(results$aggregated_results) ## End(Not run)
Orchestrates a comprehensive parameter sweep experiment that includes model selection (K, r) for each parameter combination. This function generates v2 dynamic synergy data, performs model selection using specified strategies, and evaluates performance metrics.
run_param_sweep_modelsel( test = FALSE, grid_type = NULL, mode = c("modelsel", "oracle_r", "oracle_Kr"), cores = 4, output_dir = NULL, param_grid = NULL, K_candidates = 1:5, r_candidates = 1:5, strategies = c("grid", "twostage"), methods = c("MFA", "MPCA"), criterion = c("ICL", "BIC"), icl_temperature = 2, parallel_strategy = c("grid", "sequential", "pbs", "future"), pbs_config = list(), pbs_submit = FALSE, pbs_wait = FALSE, future_backend = "multisession", future_resources = list(), max_iter = 50, nIterFA = 5, nIterPCA = 5, n_init = 1, tol = 0.001, use_kmeans_init = TRUE, n_threads = 1, save_models = FALSE, save_selection_summaries = TRUE, verbose = TRUE )run_param_sweep_modelsel( test = FALSE, grid_type = NULL, mode = c("modelsel", "oracle_r", "oracle_Kr"), cores = 4, output_dir = NULL, param_grid = NULL, K_candidates = 1:5, r_candidates = 1:5, strategies = c("grid", "twostage"), methods = c("MFA", "MPCA"), criterion = c("ICL", "BIC"), icl_temperature = 2, parallel_strategy = c("grid", "sequential", "pbs", "future"), pbs_config = list(), pbs_submit = FALSE, pbs_wait = FALSE, future_backend = "multisession", future_resources = list(), max_iter = 50, nIterFA = 5, nIterPCA = 5, n_init = 1, tol = 0.001, use_kmeans_init = TRUE, n_threads = 1, save_models = FALSE, save_selection_summaries = TRUE, verbose = TRUE )
test |
Logical. If TRUE, uses a smaller test grid for quick validation. Default is FALSE (full parameter grid). |
grid_type |
Character. Parameter grid type: "test", "paper_core", or
"paper_stress". If NULL (default), uses the |
mode |
Character. Selection mode controlling the search behavior:
Default is "modelsel". |
cores |
Integer. Number of CPU cores for parallel processing. Default is 4. Set to 1 for sequential processing. |
output_dir |
Character. Directory to save results. Default is "inst/paper/results_sweep_modelsel" if it exists, otherwise "results_sweep_modelsel" in the current working directory. |
param_grid |
Optional. Custom parameter grid data frame. If NULL,
uses the built-in full or test grid based on the |
K_candidates |
Integer vector. Candidate K values for model selection. Default is 1:5. |
r_candidates |
Integer vector. Candidate r values for model selection. Default is 1:5. |
strategies |
Character vector. Model selection strategies to evaluate. Options: "grid", "twostage". Default is c("grid", "twostage"). |
methods |
Character vector. Model types to evaluate. Options: "MFA", "MPCA". Default is c("MFA", "MPCA"). |
criterion |
Character. Model selection criterion: "ICL" or "BIC". Default is "ICL". |
icl_temperature |
Numeric. Temperature parameter for ICL entropy scaling. Higher values favor more clusters. Default is 2.0. |
parallel_strategy |
Character. Parallelization strategy:
Default is "grid". |
pbs_config |
List. PBS configuration options (only used when
parallel_strategy = "pbs"). See |
pbs_submit |
Logical. If TRUE and parallel_strategy = "pbs", submit the job to PBS. If FALSE, only generate scripts (dry run). Default is FALSE. |
pbs_wait |
Logical. If TRUE, wait for PBS job completion and aggregate results. Default is FALSE. |
future_backend |
Character. Backend for future parallelization (only used when parallel_strategy = "future"):
See |
future_resources |
List. HPC resource specifications for future.batchtools backends (e.g., list(walltime = "04:00:00", memory = "4gb")). |
max_iter |
Maximum EM iterations. Default is 50. |
nIterFA |
Sub-iterations for FA update. Default is 5. |
nIterPCA |
Sub-iterations for PCA update. Default is 5. |
n_init |
Number of random initializations. Default is 1. |
tol |
Convergence tolerance. Default is 1e-3. |
use_kmeans_init |
Whether to use k-means initialization. Default is TRUE. |
n_threads |
Number of OpenMP threads. Default is 1. |
save_models |
Logical. If TRUE, save fitted models. Default is FALSE. |
save_selection_summaries |
Logical. If TRUE, save BIC summaries for each run. Default is TRUE. |
verbose |
Logical. If TRUE, print progress information. Default is TRUE. |
The parameter sweep evaluates model selection performance across:
Methods: MFA, MPCA
Strategies: grid (full BIC grid search), twostage (K first, then r)
Metrics: ARI (clustering accuracy), VAF (reconstruction quality), BIC, selection accuracy (K_correct, r_correct, Kr_correct)
Variable parameters: N, K, r, cluster_sep_spatial, cluster_sep_temporal, cluster_sep_stability
Invisibly returns a list containing:
raw_results: Data frame with raw results from all runs
aggregated_results: Data frame with results aggregated across seeds
win_rates: Data frame with win rates by method/strategy
output_dir: Directory where results were saved
The raw_results data frame contains the following columns:
run_id, seed: Identifiers
N, K_true, r_true, M, T_each: True parameters
cluster_sep_spatial, cluster_sep_temporal, cluster_sep_stability: Separation parameters
method: "MFA" or "MPCA"
selection_strategy: "grid" or "twostage"
mode: Selection mode ("modelsel", "oracle_r", or "oracle_Kr")
r_mode: Always "global" (for future cluster-wise r extension)
K_hat, r_hat: Estimated parameters
K_correct, r_correct, Kr_correct: Selection accuracy
ARI, VAF, logLik, BIC: Performance metrics
subspace_similarity: Subspace recovery score (mean across clusters)
runtime_sec: Runtime in seconds
error_msg: Error message (empty string if successful)
## Not run: # Run test mode with 2 cores results <- run_param_sweep_modelsel(test = TRUE, cores = 2) # Run full sweep with 8 cores results <- run_param_sweep_modelsel(test = FALSE, cores = 8) # Run with custom strategies results <- run_param_sweep_modelsel( test = TRUE, cores = 4, strategies = c("twostage"), methods = c("MFA") ) ## End(Not run)## Not run: # Run test mode with 2 cores results <- run_param_sweep_modelsel(test = TRUE, cores = 2) # Run full sweep with 8 cores results <- run_param_sweep_modelsel(test = FALSE, cores = 8) # Run with custom strategies results <- run_param_sweep_modelsel( test = TRUE, cores = 4, strategies = c("twostage"), methods = c("MFA") ) ## End(Not run)
Executes a single parameter combination from the parameter grid. This function is called by PBS array job workers.
run_single_task( task_id, param_grid_file, output_dir, sweep_type = c("modelsel", "baselines"), methods = c("MFA", "MPCA"), strategies = c("grid", "twostage"), K_candidates = 1:5, r_candidates = 1:5, mode = c("modelsel", "oracle_r", "oracle_Kr"), criterion = c("ICL", "BIC"), icl_temperature = 2, max_iter = 50, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, align_basis = TRUE, refine_assignments = TRUE, verbose = TRUE )run_single_task( task_id, param_grid_file, output_dir, sweep_type = c("modelsel", "baselines"), methods = c("MFA", "MPCA"), strategies = c("grid", "twostage"), K_candidates = 1:5, r_candidates = 1:5, mode = c("modelsel", "oracle_r", "oracle_Kr"), criterion = c("ICL", "BIC"), icl_temperature = 2, max_iter = 50, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, align_basis = TRUE, refine_assignments = TRUE, verbose = TRUE )
task_id |
Integer. The task ID corresponding to run_id in the parameter grid. |
param_grid_file |
Character. Path to the RDS file containing the parameter grid. |
output_dir |
Character. Directory to save results. |
sweep_type |
Character. Type of sweep: "modelsel" or "baselines". |
methods |
Character vector. Methods to evaluate (e.g., c("MFA", "MPCA")). |
strategies |
Character vector. Selection strategies (e.g., c("grid", "twostage")). |
K_candidates |
Integer vector. Candidate K values for model selection. |
r_candidates |
Integer vector. Candidate r values for model selection. |
mode |
Character. Selection mode: "modelsel", "oracle_r", or "oracle_Kr". |
criterion |
Character. Model selection criterion: "ICL" or "BIC". |
icl_temperature |
Numeric. Temperature parameter for ICL entropy scaling. |
max_iter |
Integer. Maximum EM iterations. |
tol |
Numeric. Convergence tolerance. |
n_init |
Integer. Number of random initializations. |
use_kmeans_init |
Logical. Whether to use k-means initialization. |
align_basis |
Logical. For baselines sweep: whether to align basis vectors. |
refine_assignments |
Logical. For baselines sweep: whether to refine cluster assignments. |
verbose |
Logical. Whether to print progress. |
This function reads the parameter grid from a file, extracts the row corresponding to the given task_id, runs the computation, and saves the result to a separate file. This enables PBS array jobs where each task processes one parameter combination independently.
Invisibly returns TRUE on success.
## Not run: # Called from PBS script: # Rscript -e "synergyMixR::run_single_task( # task_id = as.integer(Sys.getenv('PBS_ARRAY_INDEX')), # param_grid_file = 'results/param_grid.rds', # output_dir = 'results' # )" ## End(Not run)## Not run: # Called from PBS script: # Rscript -e "synergyMixR::run_single_task( # task_id = as.integer(Sys.getenv('PBS_ARRAY_INDEX')), # param_grid_file = 'results/param_grid.rds', # output_dir = 'results' # )" ## End(Not run)
Executes a parameter sweep using the future framework for parallelization. This works with any future backend (local, PBS, SLURM, etc.).
run_sweep_future( param_grid, run_func, ..., future_backend = "multisession", workers = NULL, resources = list(), chunk_size = NULL, verbose = TRUE )run_sweep_future( param_grid, run_func, ..., future_backend = "multisession", workers = NULL, resources = list(), chunk_size = NULL, verbose = TRUE )
param_grid |
Data frame. Parameter grid to sweep. |
run_func |
Function. Function to run for each parameter combination. Should accept a single row of param_grid and return a data frame. |
... |
Additional arguments passed to run_func. |
future_backend |
Character. Backend to use (see |
workers |
Integer. Number of workers for local backends. |
resources |
List. HPC resources for batchtools backends. |
chunk_size |
Integer. Number of tasks per future (for load balancing). |
verbose |
Logical. Print progress information. |
Data frame with combined results from all parameter combinations.
## Not run: # Define a simple run function my_run_func <- function(p) { Sys.sleep(1) # Simulate work data.frame(run_id = p$run_id, result = p$x^2) } # Create parameter grid param_grid <- data.frame(run_id = 1:10, x = 1:10) # Run with local parallelization results <- run_sweep_future( param_grid, my_run_func, future_backend = "multisession", workers = 2 ) # Run with PBS results <- run_sweep_future( param_grid, my_run_func, future_backend = "batchtools_torque", resources = list(walltime = "01:00:00") ) ## End(Not run)## Not run: # Define a simple run function my_run_func <- function(p) { Sys.sleep(1) # Simulate work data.frame(run_id = p$run_id, result = p$x^2) } # Create parameter grid param_grid <- data.frame(run_id = 1:10, x = 1:10) # Run with local parallelization results <- run_sweep_future( param_grid, my_run_func, future_backend = "multisession", workers = 2 ) # Run with PBS results <- run_sweep_future( param_grid, my_run_func, future_backend = "batchtools_torque", resources = list(walltime = "01:00:00") ) ## End(Not run)
Returns a consistent color scale for discrete categories using viridis.
scale_color_mixsynergy(option = "viridis", ...)scale_color_mixsynergy(option = "viridis", ...)
option |
Viridis color option: "viridis" (default), "magma", "plasma", "inferno", "cividis", "rocket", "mako", "turbo" |
... |
Additional arguments passed to scale_color_viridis_d() |
A ggplot2 scale object
## Not run: library(ggplot2) ggplot(data, aes(x, y, color = cluster)) + geom_point() + scale_color_mixsynergy() ## End(Not run)## Not run: library(ggplot2) ggplot(data, aes(x, y, color = cluster)) + geom_point() + scale_color_mixsynergy() ## End(Not run)
Returns a consistent viridis color scale for continuous fill aesthetics. Uses the "viridis" option by default for colorblind-friendly visualization.
scale_fill_mixsynergy(option = "viridis", direction = 1, ...)scale_fill_mixsynergy(option = "viridis", direction = 1, ...)
option |
Viridis color option: "viridis" (default), "magma", "plasma", "inferno", "cividis", "rocket", "mako", "turbo" |
direction |
Direction of color scale: 1 (default) or -1 (reversed) |
... |
Additional arguments passed to scale_fill_viridis_c() |
A ggplot2 scale object
## Not run: library(ggplot2) ggplot(data, aes(x, y, fill = value)) + geom_tile() + scale_fill_mixsynergy() ## End(Not run)## Not run: library(ggplot2) ggplot(data, aes(x, y, fill = value)) + geom_tile() + scale_fill_mixsynergy() ## End(Not run)
Returns a consistent fill scale for discrete categories using viridis. Use this for bar plots, boxplots, and other geoms with discrete fill aesthetics.
scale_fill_mixsynergy_discrete(option = "viridis", ...)scale_fill_mixsynergy_discrete(option = "viridis", ...)
option |
Viridis color option: "viridis" (default), "magma", "plasma", "inferno", "cividis", "rocket", "mako", "turbo" |
... |
Additional arguments passed to scale_fill_viridis_d() |
A ggplot2 scale object
## Not run: library(ggplot2) ggplot(data, aes(x, y, fill = cluster)) + geom_col() + scale_fill_mixsynergy_discrete() ## End(Not run)## Not run: library(ggplot2) ggplot(data, aes(x, y, fill = cluster)) + geom_col() + scale_fill_mixsynergy_discrete() ## End(Not run)
Returns a consistent color scale for diverging data (e.g., correlations, loadings). Uses a diverging palette centered at zero.
scale_fill_mixsynergy_diverging( option = "RdBu", midpoint = 0, limits = NULL, ... )scale_fill_mixsynergy_diverging( option = "RdBu", midpoint = 0, limits = NULL, ... )
option |
Viridis color option for diverging scale (default: "RdBu") |
midpoint |
Midpoint value for diverging scale (default: 0) |
limits |
Limits for the color scale (default: NULL for automatic) |
... |
Additional arguments passed to scale_fill_gradient2() |
A ggplot2 scale object
## Not run: library(ggplot2) ggplot(data, aes(x, y, fill = correlation)) + geom_tile() + scale_fill_mixsynergy_diverging() ## End(Not run)## Not run: library(ggplot2) ggplot(data, aes(x, y, fill = correlation)) + geom_tile() + scale_fill_mixsynergy_diverging() ## End(Not run)
This function implements bootstrap stability selection for choosing the optimal number of clusters K. It assesses the stability of cluster assignments across bootstrap resamples and selects K that produces the most stable clustering.
select_K_bootstrap_stability( list_of_data, Kvec = 2:5, r = 2, B = 50, subsample_ratio = 0.8, max_iter = 50, n_init = 1, model_type = c("MFA", "MPCA"), verbose = TRUE )select_K_bootstrap_stability( list_of_data, Kvec = 2:5, r = 2, B = 50, subsample_ratio = 0.8, max_iter = 50, n_init = 1, model_type = c("MFA", "MPCA"), verbose = TRUE )
list_of_data |
A list of data matrices, each (T_i x M). |
Kvec |
Vector of candidate K values to test. |
r |
Number of factors (fixed). |
B |
Number of bootstrap iterations (default: 50). |
subsample_ratio |
Proportion of subjects to sample (default: 0.8). |
max_iter |
Maximum EM iterations per fit. |
n_init |
Number of random initializations per fit. |
model_type |
Either "MFA" or "MPCA" (default: "MFA"). |
verbose |
Print progress messages (default: TRUE). |
The stability selection procedure: 1. For each candidate K, perform B bootstrap iterations 2. In each iteration, subsample subjects and fit the model 3. Compute pairwise co-clustering matrix (1 if subjects i,j in same cluster) 4. Average co-clustering matrices across bootstrap samples 5. Compute stability score as mean of (max probability per subject - 1/K) 6. Select K with highest stability score
Higher stability indicates more consistent cluster assignments across resamples.
A list containing:
The selected optimal K based on stability
Stability score for each K
Data frame with K and stability scores
Ben-Hur, A., Elisseeff, A., & Guyon, I. (2001). A stability based method for discovering structure in clustered data. Pacific Symposium on Biocomputing.
This function implements K-fold cross-validation for choosing the optimal number of clusters K. It evaluates model generalization by computing log-likelihood on held-out subjects.
select_K_crossvalidation( list_of_data, Kvec = 2:5, r = 2, nfolds = 5, max_iter = 50, n_init = 1, model_type = c("MFA", "MPCA"), verbose = TRUE )select_K_crossvalidation( list_of_data, Kvec = 2:5, r = 2, nfolds = 5, max_iter = 50, n_init = 1, model_type = c("MFA", "MPCA"), verbose = TRUE )
list_of_data |
A list of data matrices, each (T_i x M). |
Kvec |
Vector of candidate K values to test. |
r |
Number of factors (fixed). |
nfolds |
Number of cross-validation folds (default: 5). |
max_iter |
Maximum EM iterations per fit. |
n_init |
Number of random initializations per fit. |
model_type |
Either "MFA" or "MPCA" (default: "MFA"). |
verbose |
Print progress messages (default: TRUE). |
The cross-validation procedure: 1. Split subjects into nfolds groups 2. For each K and each fold: - Train model on (nfolds-1) folds - Compute log-likelihood on held-out fold 3. Average log-likelihoods across folds for each K 4. Select K with highest average CV log-likelihood
Higher CV log-likelihood indicates better generalization.
A list containing:
The selected optimal K based on CV log-likelihood
Mean CV log-likelihood for each K
Standard error of CV log-likelihood for each K
Data frame with K, mean CV score, and SE
This function provides a unified interface for selecting optimal K (number of clusters) and r (factor dimension) for mixture models (MFA or MPCA). It supports multiple selection strategies including grid search and two-stage selection.
select_K_r( list_of_data, method = c("MFA", "MPCA"), strategy = c("grid", "twostage"), Kvec = 1:5, rvec = 1:5, r_fixed = 2, criterion = c("ICL", "BIC"), icl_max_iter = NULL, icl_temperature = 2, max_iter = 50, nIterFA = 5, nIterPCA = 5, tol = 0.001, mpca_method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores_grid = 1, mc_cores = 1, n_threads = 1, verbose = TRUE )select_K_r( list_of_data, method = c("MFA", "MPCA"), strategy = c("grid", "twostage"), Kvec = 1:5, rvec = 1:5, r_fixed = 2, criterion = c("ICL", "BIC"), icl_max_iter = NULL, icl_temperature = 2, max_iter = 50, nIterFA = 5, nIterPCA = 5, tol = 0.001, mpca_method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores_grid = 1, mc_cores = 1, n_threads = 1, verbose = TRUE )
list_of_data |
A list of data matrices, each (T_i x M). |
method |
Model type: "MFA" or "MPCA". |
strategy |
Selection strategy: "grid" for full grid search, "twostage" for two-stage sequential selection (K first, then r). |
Kvec |
Integer vector of candidate K values. Default is 1:5. |
rvec |
Integer vector of candidate r values. Default is 1:5. |
r_fixed |
Fixed r value for Stage 1 of twostage selection. Default is 2. |
criterion |
Model selection criterion: "ICL" (Integrated Completed Likelihood) or "BIC" (Bayesian Information Criterion). Default is "ICL". |
icl_max_iter |
Maximum iterations for ICL entropy calculation. Default is NULL (uses package default). |
icl_temperature |
Temperature parameter for ICL entropy scaling. Higher values favor more clusters. Default is 2.0. |
max_iter |
Maximum EM iterations. Default is 50. |
nIterFA |
Sub-iterations for FA update (MFA only). Default is 5. |
nIterPCA |
Sub-iterations for PCA update (MPCA only). Default is 5. |
tol |
Convergence tolerance. Default is 1e-3. |
mpca_method |
Method for MPCA: "EM" or "closed_form". Default is "EM". |
n_init |
Number of random initializations. Default is 1. |
use_kmeans_init |
Whether to use k-means initialization. Default is TRUE. |
subject_rdim_for_kmeans |
Dimension for k-means features. Default is 2. |
mc_cores_grid |
Number of cores for grid-level parallelization. Default is 1. |
mc_cores |
Number of cores for initialization-level parallelization. Default is 1. |
n_threads |
Number of OpenMP threads. Default is 1. |
verbose |
Logical; if TRUE, print progress messages. Default is TRUE. |
This function wraps the existing model selection functions to provide a unified interface for parameter sweep experiments. It handles:
Parallel safety: Prevents nested parallelization by forcing n_threads=1 when mc_cores_grid > 1
Windows compatibility: Falls back to sequential execution on Windows
Consistent output format: Returns the same structure regardless of method or strategy
Strategy: "grid" Performs full grid search over all (K, r) combinations using BIC for selection. This is thorough but computationally expensive.
Strategy: "twostage" Two-stage sequential selection:
Stage 1: Fix r at r_fixed, search for optimal K using BIC
Stage 2: Fix K at optimal value, search for optimal r using BIC
This is more stable and faster than full grid search.
A list with unified output structure:
best_KOptimal number of clusters (scalar).
best_rOptimal factor dimension (scalar).
best_modelFitted model object with optimal (K, r).
summary_dfData frame with selection summary. For grid strategy, contains all (K, r) combinations with BIC. For twostage, contains stage1 and stage2 summaries.
metaList with metadata: method, strategy, Kvec, rvec, etc.
select_optimal_K_r_mfa, select_optimal_K_r_mpca,
select_optimal_K_r_mfa_twostage, select_optimal_K_r_mpca_twostage
## Not run: # Grid search for MFA result <- select_K_r( list_of_data, method = "MFA", strategy = "grid", Kvec = 2:4, rvec = 2:4 ) print(result$best_K) print(result$best_r) # Two-stage selection for MPCA result <- select_K_r( list_of_data, method = "MPCA", strategy = "twostage", Kvec = 2:4, rvec = 2:4, r_fixed = 2 ) ## End(Not run)## Not run: # Grid search for MFA result <- select_K_r( list_of_data, method = "MFA", strategy = "grid", Kvec = 2:4, rvec = 2:4 ) print(result$best_K) print(result$best_r) # Two-stage selection for MPCA result <- select_K_r( list_of_data, method = "MPCA", strategy = "twostage", Kvec = 2:4, rvec = 2:4, r_fixed = 2 ) ## End(Not run)
This function tries all combinations of K in Kvec and r in rvec, fits a Mixture Factor Analysis (MFA) model using mfa_em_fit for each combination, computes BIC, and returns the best model by BIC.
select_optimal_K_r_mfa( list_of_data, Kvec = 1:5, rvec = 1:5, max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores_grid = 1, mc_cores = 1, n_threads = 1 )select_optimal_K_r_mfa( list_of_data, Kvec = 1:5, rvec = 1:5, max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores_grid = 1, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of data matrices, each (T_i x M). |
Kvec |
An integer vector of candidate K values. |
rvec |
An integer vector of candidate r values. |
max_iter |
Maximum EM iterations. |
nIterFA |
Sub-iterations within the factor-analyzer update in C++. |
tol |
Convergence tolerance. |
n_init |
Number of random initializations to try inside mfa_em_fit. |
use_kmeans_init |
Logical; whether to also try a k-means-based init. |
subject_rdim_for_kmeans |
Dimension for PCA-based features if use_kmeans_init=TRUE. |
mc_cores_grid |
Number of CPU cores for grid-level parallelization (default: 1). |
mc_cores |
Number of CPU cores for initialization-level parallelization within each (K, r) (default: 1). |
n_threads |
Number of OpenMP threads for EM-level parallelization (default: 1 to avoid nested parallelism). |
- Calls mfa_em_fit(..., n_init, use_kmeans_init, ...) for each (K, r). - After fitting, we compute log-likelihood by summing over all data (you can use the built-in logLik from the fit, or re-compute). - Then compute BIC = -2*logLik + p*log(N_total_rows). Here p = K*(M*r + 2*M) + (K - 1) by default (diagonal noise).
A list with:
summary |
A data.frame with columns K, r, logLik, BIC. |
best_model_info |
A list with (K, r, model, logLik, BIC) for the best BIC. |
all_models |
A list of all fits, each (K, r, model, logLik, BIC). |
This function implements a more stable two-stage approach to model selection: Stage 1: Fix r (e.g., r=2) and search for optimal K using BIC or ICL Stage 2: Fix K at the optimal value and search for optimal r using BIC
select_optimal_K_r_mfa_twostage( list_of_data, Kvec = 2:5, rvec = 1:5, r_fixed = 2, criterion = c("ICL", "BIC"), max_iter = 50, icl_max_iter = NULL, icl_temperature = 2, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )select_optimal_K_r_mfa_twostage( list_of_data, Kvec = 2:5, rvec = 1:5, r_fixed = 2, criterion = c("ICL", "BIC"), max_iter = 50, icl_max_iter = NULL, icl_temperature = 2, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of data matrices, each (T_i x M). |
Kvec |
An integer vector of candidate K values for Stage 1. |
rvec |
An integer vector of candidate r values for Stage 2. |
r_fixed |
Fixed r value to use in Stage 1 (default: 2). |
criterion |
Model selection criterion for K selection in Stage 1. Either "BIC" (default) or "ICL". ICL adds an entropy penalty that discourages uncertain cluster assignments, making it more conservative for K selection. Stage 2 (r selection) always uses BIC. |
max_iter |
Maximum EM iterations. |
icl_max_iter |
Maximum EM iterations for ICL entropy calculation (default: 10). Only used when criterion="ICL". This limits iterations to maintain soft cluster assignments (non-zero entropy), making ICL effective. If NULL, defaults to 10. Uses random initialization (not K-means) internally. |
icl_temperature |
Temperature parameter for ICL entropy scaling (default: 2.0). Higher values favor more clusters by scaling down the entropy penalty. |
nIterFA |
Sub-iterations within the factor-analyzer update in C++. |
tol |
Convergence tolerance. |
n_init |
Number of random initializations to try. |
use_kmeans_init |
Logical; whether to also try a k-means-based init. |
subject_rdim_for_kmeans |
Dimension for PCA-based features if use_kmeans_init=TRUE. |
mc_cores |
Number of CPU cores for initialization-level parallelization (default: 1). |
n_threads |
Number of OpenMP threads for EM-level parallelization (default: 1). |
This approach is more stable than simultaneous (K, r) grid search because K and r have strong interactions in mixture models.
This two-stage approach is recommended in the literature for mixture models because it avoids the instability of simultaneous (K, r) optimization. The default r_fixed=2 is a reasonable starting point for most applications.
When criterion="ICL", the Integrated Complete-data Likelihood is used for K selection. ICL adds an entropy penalty to BIC that discourages models with uncertain cluster assignments. This makes ICL more conservative than BIC and can help avoid overestimating K.
A list with:
stage1_summary |
Data frame with K search results (r fixed). Contains BIC and optionally ICL if criterion="ICL". |
stage2_summary |
Data frame with r search results (K fixed). |
best_K |
Optimal K from Stage 1. |
best_r |
Optimal r from Stage 2. |
best_model_info |
Final model with optimal (K, r). |
best_model |
The fitted model object. |
criterion |
The criterion used for K selection. |
Biernacki, C., Celeux, G., & Govaert, G. (2000). Assessing a mixture model for clustering with the integrated completed likelihood. IEEE Transactions on Pattern Analysis and Machine Intelligence, 22(7), 719-725.
This function tries all combinations of K in Kvec and r in rvec, fits a Mixture PCA (PPCA) model using mixture_pca_em_fit for each combination, computes BIC, and returns the best model by BIC.
select_optimal_K_r_mpca( list_of_data, Kvec = 1:5, rvec = 1:5, max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores_grid = 1, mc_cores = 1, n_threads = 1 )select_optimal_K_r_mpca( list_of_data, Kvec = 1:5, rvec = 1:5, max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores_grid = 1, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of data matrices, each (T_i x M). |
Kvec |
An integer vector of candidate K values. |
rvec |
An integer vector of candidate r values. |
max_iter |
Maximum EM iterations. |
nIterPCA |
Sub-iterations within the PCA/PPCA update in C++. |
tol |
Convergence tolerance. |
method |
"EM" or "closed_form" (passed to mixture_pca_em_fit). |
n_init |
Number of random initializations to try inside mixture_pca_em_fit. |
use_kmeans_init |
Logical; whether to also try a k-means-based init. |
subject_rdim_for_kmeans |
Dimension for PCA-based features if use_kmeans_init=TRUE. |
mc_cores_grid |
Number of CPU cores for grid-level parallelization (default: 1). |
mc_cores |
Number of CPU cores for initialization-level parallelization within each (K, r) (default: 1). |
n_threads |
Number of OpenMP threads for EM-level parallelization (default: 1 to avoid nested parallelism). |
- Calls mixture_pca_em_fit(..., n_init, use_kmeans_init, ...) for each (K, r). - Uses fit$logLik as the final log-likelihood. - BIC formula can be adjusted if needed. By default, we might do p = K*(M*r + r + M) + (K-1), for example, if we consider each cluster having: - W is M x r (or equivalently P x D) - mu is length M - sigma2 is 1 scalar - mixing proportions (K-1)
A list with:
summary |
A data.frame with columns K, r, logLik, BIC. |
best_model_info |
A list with (K, r, model, logLik, BIC) for the best BIC. |
all_models |
A list of all fits, each (K, r, model, logLik, BIC). |
This function implements a more stable two-stage approach to model selection: Stage 1: Fix r (e.g., r=2) and search for optimal K using BIC or ICL Stage 2: Fix K at the optimal value and search for optimal r using BIC
select_optimal_K_r_mpca_twostage( list_of_data, Kvec = 2:5, rvec = 1:5, r_fixed = 2, criterion = c("ICL", "BIC"), max_iter = 50, icl_max_iter = NULL, icl_temperature = 2, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )select_optimal_K_r_mpca_twostage( list_of_data, Kvec = 2:5, rvec = 1:5, r_fixed = 2, criterion = c("ICL", "BIC"), max_iter = 50, icl_max_iter = NULL, icl_temperature = 2, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of data matrices, each (T_i x M). |
Kvec |
An integer vector of candidate K values for Stage 1. |
rvec |
An integer vector of candidate r values for Stage 2. |
r_fixed |
Fixed r value to use in Stage 1 (default: 2). |
criterion |
Model selection criterion for K selection in Stage 1. Either "BIC" (default) or "ICL". ICL adds an entropy penalty that discourages uncertain cluster assignments, making it more conservative for K selection. Stage 2 (r selection) always uses BIC. |
max_iter |
Maximum EM iterations. |
icl_max_iter |
Maximum EM iterations for ICL entropy calculation (default: 10). Only used when criterion="ICL". This limits iterations to maintain soft cluster assignments (non-zero entropy), making ICL effective. If NULL, defaults to 10. Uses random initialization (not K-means) internally. |
icl_temperature |
Temperature parameter for ICL entropy scaling (default: 2.0). Higher values favor more clusters by scaling down the entropy penalty. |
nIterPCA |
Sub-iterations within the PCA/PPCA update in C++. |
tol |
Convergence tolerance. |
method |
"EM" or "closed_form" (passed to mixture_pca_em_fit). |
n_init |
Number of random initializations to try. |
use_kmeans_init |
Logical; whether to also try a k-means-based init. |
subject_rdim_for_kmeans |
Dimension for PCA-based features if use_kmeans_init=TRUE. |
mc_cores |
Number of CPU cores for initialization-level parallelization (default: 1). |
n_threads |
Number of OpenMP threads for EM-level parallelization (default: 1). |
This approach is more stable than simultaneous (K, r) grid search because K and r have strong interactions in mixture models.
This two-stage approach is recommended in the literature for mixture models because it avoids the instability of simultaneous (K, r) optimization. The default r_fixed=2 is a reasonable starting point for most applications.
When criterion="ICL", the Integrated Complete-data Likelihood is used for K selection. ICL adds an entropy penalty to BIC that discourages models with uncertain cluster assignments. This makes ICL more conservative than BIC and can help avoid overestimating K.
A list with:
stage1_summary |
Data frame with K search results (r fixed). Contains BIC and optionally ICL if criterion="ICL". |
stage2_summary |
Data frame with r search results (K fixed). |
best_K |
Optimal K from Stage 1. |
best_r |
Optimal r from Stage 2. |
best_model_info |
Final model with optimal (K, r). |
best_model |
The fitted model object. |
criterion |
The criterion used for K selection. |
Biernacki, C., Celeux, G., & Govaert, G. (2000). Assessing a mixture model for clustering with the integrated completed likelihood. IEEE Transactions on Pattern Analysis and Machine Intelligence, 22(7), 719-725.
Selects the optimal number of factors (r) for a given number of clusters (K) by minimizing the smoothness penalty of factor activation profiles, subject to constraints on VAF or BIC.
select_r_by_smoothness_mfa( list_of_data, K, rvec = 1:6, lambda_smooth = 0.001, vaf_threshold = 0.9, max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )select_r_by_smoothness_mfa( list_of_data, K, rvec = 1:6, lambda_smooth = 0.001, vaf_threshold = 0.9, max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of N matrices, each (T_i x M). |
K |
Number of clusters (fixed). |
rvec |
Vector of candidate r values to evaluate. |
lambda_smooth |
Smoothness penalty weight. Default is 1e-3. |
vaf_threshold |
Minimum VAF threshold. Models with VAF below this are excluded. Default is 0.9. |
max_iter |
Maximum EM iterations. |
nIterFA |
Sub-iterations for FA update. |
tol |
Convergence tolerance. |
n_init |
Number of random initializations. |
use_kmeans_init |
Whether to use k-means initialization. |
subject_rdim_for_kmeans |
Dimension for k-means features. |
mc_cores |
Number of cores for parallelization. |
n_threads |
Number of OpenMP threads. |
This function fits MFA models for each r in rvec with fixed K, computes factor scores, and evaluates the smoothness penalty. The optimal r is selected by minimizing:
among models satisfying VAF >= vaf_threshold.
A list with:
best_r |
The selected r value. |
summary |
A data.frame with columns r, BIC, VAF, smoothness, penalized_score. |
best_model |
The fitted model for the selected r. |
## Not run: result <- select_r_by_smoothness_mfa( list_of_data, K = 3, rvec = 1:5, lambda_smooth = 1e-3, vaf_threshold = 0.9 ) print(result$summary) best_model <- result$best_model ## End(Not run)## Not run: result <- select_r_by_smoothness_mfa( list_of_data, K = 3, rvec = 1:5, lambda_smooth = 1e-3, vaf_threshold = 0.9 ) print(result$summary) best_model <- result$best_model ## End(Not run)
Selects the optimal number of factors (r) for a given number of clusters (K) by minimizing the smoothness penalty of PC activation profiles, subject to constraints on VAF or BIC.
select_r_by_smoothness_mpca( list_of_data, K, rvec = 1:6, lambda_smooth = 0.001, vaf_threshold = 0.9, max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )select_r_by_smoothness_mpca( list_of_data, K, rvec = 1:6, lambda_smooth = 0.001, vaf_threshold = 0.9, max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of N matrices, each (T_i x M). |
K |
Number of clusters (fixed). |
rvec |
Vector of candidate r values to evaluate. |
lambda_smooth |
Smoothness penalty weight. Default is 1e-3. |
vaf_threshold |
Minimum VAF threshold. Models with VAF below this are excluded. Default is 0.9. |
max_iter |
Maximum EM iterations. |
nIterPCA |
Sub-iterations for PCA update. |
tol |
Convergence tolerance. |
method |
"EM" or "closed_form". |
n_init |
Number of random initializations. |
use_kmeans_init |
Whether to use k-means initialization. |
subject_rdim_for_kmeans |
Dimension for k-means features. |
mc_cores |
Number of cores for parallelization. |
n_threads |
Number of OpenMP threads. |
This function fits MPCA models for each r in rvec with fixed K, computes PC scores, and evaluates the smoothness penalty. The optimal r is selected by minimizing:
among models satisfying VAF >= vaf_threshold.
A list with:
best_r |
The selected r value. |
summary |
A data.frame with columns r, BIC, VAF, smoothness, penalized_score. |
best_model |
The fitted model for the selected r. |
## Not run: result <- select_r_by_smoothness_mpca( list_of_data, K = 3, rvec = 1:5, lambda_smooth = 1e-3, vaf_threshold = 0.9 ) print(result$summary) best_model <- result$best_model ## End(Not run)## Not run: result <- select_r_by_smoothness_mpca( list_of_data, K = 3, rvec = 1:5, lambda_smooth = 1e-3, vaf_threshold = 0.9 ) print(result$summary) best_model <- result$best_model ## End(Not run)
This function implements a traditional EMG synergy approach: select the minimum r (number of factors) that achieves a target VAF (Variance Accounted For) threshold. This is commonly used in motor control research where VAF >= 90-95 percent is desired.
select_r_by_vaf_mfa( list_of_data, K, rvec = 1:5, vaf_threshold = 0.9, max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )select_r_by_vaf_mfa( list_of_data, K, rvec = 1:5, vaf_threshold = 0.9, max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of data matrices, each (T_i x M). |
K |
Number of clusters (must be pre-specified). |
rvec |
Vector of candidate r values to test. |
vaf_threshold |
Target VAF threshold (default: 0.90 for 90 percent). |
max_iter |
Maximum EM iterations. |
nIterFA |
Sub-iterations within the factor-analyzer update. |
tol |
Convergence tolerance. |
n_init |
Number of random initializations. |
use_kmeans_init |
Whether to use k-means initialization. |
subject_rdim_for_kmeans |
Dimension for PCA-based features. |
mc_cores |
Number of CPU cores for parallelization. |
n_threads |
Number of OpenMP threads. |
This function fits MFA models for each r in rvec with fixed K, computes both VAF and BIC, and returns: 1. The minimum r that achieves the VAF threshold (traditional approach) 2. The optimal r by BIC (statistical approach)
Users can compare both criteria to make informed model selection decisions.
A list containing: summary (data frame with r, VAF, BIC for each r), best_r_vaf (minimum r achieving VAF threshold), best_r_bic (optimal r by BIC), best_model_vaf (model with minimum r achieving threshold), and best_model_bic (model with optimal BIC).
This function implements a traditional EMG synergy approach: select the minimum r (number of principal components) that achieves a target VAF threshold. This is commonly used in motor control research where VAF >= 90-95 percent is desired.
select_r_by_vaf_mpca( list_of_data, K, rvec = 1:5, vaf_threshold = 0.9, max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )select_r_by_vaf_mpca( list_of_data, K, rvec = 1:5, vaf_threshold = 0.9, max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of data matrices, each (T_i x M). |
K |
Number of clusters (must be pre-specified). |
rvec |
Vector of candidate r values to test. |
vaf_threshold |
Target VAF threshold (default: 0.90 for 90 percent). |
max_iter |
Maximum EM iterations. |
nIterPCA |
Sub-iterations within the PCA/PPCA update. |
tol |
Convergence tolerance. |
method |
"EM" or "closed_form". |
n_init |
Number of random initializations. |
use_kmeans_init |
Whether to use k-means initialization. |
subject_rdim_for_kmeans |
Dimension for PCA-based features. |
mc_cores |
Number of CPU cores for parallelization. |
n_threads |
Number of OpenMP threads. |
This function fits MPCA models for each r in rvec with fixed K, computes both VAF and BIC, and returns: 1. The minimum r that achieves the VAF threshold (traditional approach) 2. The optimal r by BIC (statistical approach)
Users can compare both criteria to make informed model selection decisions.
A list containing: summary (data frame with r, VAF, BIC for each r), best_r_vaf (minimum r achieving VAF threshold), best_r_bic (optimal r by BIC), best_model_vaf (model with minimum r achieving threshold), and best_model_bic (model with optimal BIC).
Selects the optimal number of factors (r) for a given number of clusters (K) by maximizing the VSS (Very Simple Structure) criterion, subject to constraints on VAF or BIC.
select_r_by_vss_mfa( list_of_data, K, rvec = 1:6, vss_threshold = 0.5, vaf_threshold = 0.9, max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )select_r_by_vss_mfa( list_of_data, K, rvec = 1:6, vss_threshold = 0.5, vaf_threshold = 0.9, max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of N matrices, each (T_i x M). |
K |
Number of clusters (fixed). |
rvec |
Vector of candidate r values to evaluate. |
vss_threshold |
Threshold for determining strong vs weak loadings. Default is 0.5. |
vaf_threshold |
Minimum VAF threshold. Models with VAF below this are excluded. Default is 0.9. |
max_iter |
Maximum EM iterations. |
nIterFA |
Sub-iterations for FA update. |
tol |
Convergence tolerance. |
n_init |
Number of random initializations. |
use_kmeans_init |
Whether to use k-means initialization. |
subject_rdim_for_kmeans |
Dimension for k-means features. |
mc_cores |
Number of cores for parallelization. |
n_threads |
Number of OpenMP threads. |
This function fits MFA models for each r in rvec with fixed K, and evaluates the VSS criterion. The optimal r is selected by maximizing VSS among models satisfying VAF >= vaf_threshold.
Higher VSS values indicate better simple structure, where each muscle loads strongly on exactly one synergy.
A list with:
best_r |
The selected r value. |
summary |
A data.frame with columns r, BIC, VAF, VSS. |
best_model |
The fitted model for the selected r. |
## Not run: result <- select_r_by_vss_mfa( list_of_data, K = 3, rvec = 1:5, vss_threshold = 0.5, vaf_threshold = 0.9 ) print(result$summary) best_model <- result$best_model ## End(Not run)## Not run: result <- select_r_by_vss_mfa( list_of_data, K = 3, rvec = 1:5, vss_threshold = 0.5, vaf_threshold = 0.9 ) print(result$summary) best_model <- result$best_model ## End(Not run)
Selects the optimal number of factors (r) for a given number of clusters (K) by maximizing the VSS (Very Simple Structure) criterion, subject to constraints on VAF or BIC.
select_r_by_vss_mpca( list_of_data, K, rvec = 1:6, vss_threshold = 0.5, vaf_threshold = 0.9, max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )select_r_by_vss_mpca( list_of_data, K, rvec = 1:6, vss_threshold = 0.5, vaf_threshold = 0.9, max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of N matrices, each (T_i x M). |
K |
Number of clusters (fixed). |
rvec |
Vector of candidate r values to evaluate. |
vss_threshold |
Threshold for determining strong vs weak loadings. Default is 0.5. |
vaf_threshold |
Minimum VAF threshold. Models with VAF below this are excluded. Default is 0.9. |
max_iter |
Maximum EM iterations. |
nIterPCA |
Sub-iterations for PCA update. |
tol |
Convergence tolerance. |
method |
"EM" or "closed_form". |
n_init |
Number of random initializations. |
use_kmeans_init |
Whether to use k-means initialization. |
subject_rdim_for_kmeans |
Dimension for k-means features. |
mc_cores |
Number of cores for parallelization. |
n_threads |
Number of OpenMP threads. |
This function fits MPCA models for each r in rvec with fixed K, and evaluates the VSS criterion. The optimal r is selected by maximizing VSS among models satisfying VAF >= vaf_threshold.
Higher VSS values indicate better simple structure, where each muscle loads strongly on exactly one synergy.
A list with:
best_r |
The selected r value. |
summary |
A data.frame with columns r, BIC, VAF, VSS. |
best_model |
The fitted model for the selected r. |
## Not run: result <- select_r_by_vss_mpca( list_of_data, K = 3, rvec = 1:5, vss_threshold = 0.5, vaf_threshold = 0.9 ) print(result$summary) best_model <- result$best_model ## End(Not run)## Not run: result <- select_r_by_vss_mpca( list_of_data, K = 3, rvec = 1:5, vss_threshold = 0.5, vaf_threshold = 0.9 ) print(result$summary) best_model <- result$best_model ## End(Not run)
Selects the optimal number of factors (r) by evaluating each cluster separately, rather than averaging metrics across all clusters. This approach is useful when different clusters may have different optimal r values.
select_r_clusterwise_mfa( list_of_data, K, rvec = 1:6, criteria = c("VAF", "VSS", "smoothness"), agg_method = c("max", "mean", "min", "majority"), vaf_threshold = NULL, vss_threshold = 0.5, vss_method = c("threshold", "ratio"), vss_rotate = c("none", "varimax"), lambda_smooth = 0.001, weights = c(VAF = 0.4, VSS = 0.4, smoothness = 0.2), vss_normalize = c("logr", "max", "r", "r2", "none"), w_elbow = 0, w_r = 0, vaf_degeneracy_threshold = 0.6, max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1, verbose = FALSE, mode = c("clusterwise", "global-first"), global_model = c("PPCA", "FA"), global_criterion = c("CV", "ParallelAnalysis"), global_folds = 5, global_seed = NULL, r_init = NULL )select_r_clusterwise_mfa( list_of_data, K, rvec = 1:6, criteria = c("VAF", "VSS", "smoothness"), agg_method = c("max", "mean", "min", "majority"), vaf_threshold = NULL, vss_threshold = 0.5, vss_method = c("threshold", "ratio"), vss_rotate = c("none", "varimax"), lambda_smooth = 0.001, weights = c(VAF = 0.4, VSS = 0.4, smoothness = 0.2), vss_normalize = c("logr", "max", "r", "r2", "none"), w_elbow = 0, w_r = 0, vaf_degeneracy_threshold = 0.6, max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1, verbose = FALSE, mode = c("clusterwise", "global-first"), global_model = c("PPCA", "FA"), global_criterion = c("CV", "ParallelAnalysis"), global_folds = 5, global_seed = NULL, r_init = NULL )
list_of_data |
A list of N matrices, each (T_i x M). |
K |
Number of clusters (fixed). |
rvec |
Vector of candidate r values to evaluate. Default is 1:6. |
criteria |
Character vector specifying which criteria to use for selection. Options: "VAF", "VSS", "smoothness". Default is c("VAF", "VSS", "smoothness"). |
agg_method |
Method for aggregating cluster-specific r values. Options: "max" (conservative, takes maximum r across clusters), "mean" (average r, rounded), "min" (minimum r across clusters), "majority" (most common r value). Default is "max". |
vaf_threshold |
Minimum VAF threshold for each cluster. Set to NULL to disable hard filtering. Default is NULL (disabled). |
vss_threshold |
Threshold for VSS criterion. Default is 0.5. |
vss_method |
Method for computing VSS. Options: "threshold" (count variables with exactly one strong loading above threshold), "ratio" (compute concentration ratio max(lambda^2)/sum(lambda^2) for each variable). Default is "threshold". The "ratio" method is more robust when loadings are small in absolute magnitude. |
vss_rotate |
Rotation method to apply before computing VSS. Options: "none" (no rotation), "varimax" (orthogonal rotation). Default is "none". VSS on unrotated FA loadings is rotation-dependent and often uninformative. Rotation is recommended for meaningful VSS. |
lambda_smooth |
Smoothness penalty weight (deprecated, use weights instead). Default is 1e-3. |
weights |
Named vector of weights for combining criteria. Default is c(VAF=0.4, VSS=0.4, smoothness=0.2). |
vss_normalize |
Method for normalizing VSS to account for r-dependence. Options: "logr" (divide by log(r)), "max" (divide by max VSS), "r" (divide by r), "r2" (divide by r^2), "none". Default is "logr". |
w_elbow |
Weight for DeltaVAF (elbow detection). Higher values emphasize diminishing returns in VAF. Default is 0 (disabled). |
w_r |
Weight for direct r penalty (AIC/BIC style). Higher values penalize larger r. Default is 0 (disabled). |
vaf_degeneracy_threshold |
Threshold for detecting degenerate clusters. If max VAF across all r values is below this threshold, the cluster is considered degenerate and a warning is issued. Default is 0.6. |
max_iter |
Maximum EM iterations for initial clustering. |
nIterFA |
Sub-iterations for FA update. |
tol |
Convergence tolerance. |
n_init |
Number of random initializations for initial clustering. |
use_kmeans_init |
Whether to use k-means initialization. |
subject_rdim_for_kmeans |
Dimension for k-means features. |
mc_cores |
Number of cores for parallelization. |
n_threads |
Number of OpenMP threads. |
verbose |
Logical. If TRUE, print detailed diagnostic information during r selection, including per-r metrics for each cluster and warnings about NA values or degenerate clusters. Default is FALSE. |
mode |
Selection mode. Options: "clusterwise" (default, evaluate r separately per cluster), "global-first" (first estimate global r using FA/PPCA on pooled data, then use for MFA). The "global-first" mode is recommended as it provides a cluster-independent baseline. |
global_model |
Model for global r estimation (only used when mode = "global-first"). Options: "PPCA" (default), "FA". PPCA is more stable for mixture models. |
global_criterion |
Criterion for global r selection (only used when mode = "global-first"). Options: "CV" (default), "ParallelAnalysis". CV is the primary criterion. |
global_folds |
Number of CV folds for global r selection (only used when mode = "global-first"). Default is 5. |
global_seed |
Random seed for global r selection (only used when mode = "global-first"). Default is NULL. |
r_init |
Initial r value for the first-stage clustering (only used when mode = "clusterwise"). If NULL (default), uses median(rvec). When called from hybrid mode in select_r_mixture(), this is set to r_global to use the global estimate as initialization. |
This function implements a two-stage approach:
Fit an initial MFA model with K clusters and a reasonable r value (using the median of rvec) to obtain cluster assignments.
For each cluster k, subset the data to subjects assigned to that cluster, and evaluate different r values using cluster-specific metrics.
Select the optimal r_k for each cluster based on normalized scoring that combines VAF (higher is better), VSS (higher is better, normalized by log(r)), and smoothness (lower is better) with specified weights.
Aggregate the cluster-specific r values using the specified method.
The scoring approach addresses the issue where VAF monotonically increases with r by normalizing all metrics per cluster and using weighted combination. VSS is normalized by log(r) to account for the fact that more factors naturally lead to more complex structures. Smoothness acts as a penalty (subtracted from score).
The cluster-wise approach is particularly useful when:
Different motor control strategies require different numbers of synergies
Averaging metrics across clusters masks cluster-specific structure
You want to understand the heterogeneity in synergy complexity
Important Note: The cluster-wise MFA(K=1) approach is experimental and can be unstable. Each cluster is evaluated independently using a single-cluster MFA model, which may not capture the full complexity of the data. Use with caution and carefully inspect the verbose output and degeneracy warnings.
A list with:
cluster_r |
Named vector of optimal r for each cluster. |
agg_r |
Aggregated r value across clusters. |
cluster_metrics |
List of data frames with metrics for each cluster. |
initial_fit |
The initial MFA fit used to determine cluster assignments. |
agg_method |
The aggregation method used. |
mode |
The selection mode used. |
global_result |
(Only for mode = "global-first") The result from select_r_global_mfa(). |
## Not run: # Basic usage with default weights (clusterwise mode) result <- select_r_clusterwise_mfa( list_of_data, K = 3, rvec = 2:6, criteria = c("VAF", "VSS", "smoothness") ) print(result$cluster_r) # r for each cluster print(result$agg_r) # aggregated r # Global-first mode (recommended) result <- select_r_clusterwise_mfa( list_of_data, K = 3, rvec = 2:6, mode = "global-first", global_model = "PPCA", global_criterion = "CV" ) print(result$agg_r) # global r estimate # Custom weights emphasizing VAF (clusterwise mode) result <- select_r_clusterwise_mfa( list_of_data, K = 3, rvec = 2:6, mode = "clusterwise", criteria = c("VAF", "VSS", "smoothness"), weights = c(VAF = 0.6, VSS = 0.3, smoothness = 0.1) ) ## End(Not run)## Not run: # Basic usage with default weights (clusterwise mode) result <- select_r_clusterwise_mfa( list_of_data, K = 3, rvec = 2:6, criteria = c("VAF", "VSS", "smoothness") ) print(result$cluster_r) # r for each cluster print(result$agg_r) # aggregated r # Global-first mode (recommended) result <- select_r_clusterwise_mfa( list_of_data, K = 3, rvec = 2:6, mode = "global-first", global_model = "PPCA", global_criterion = "CV" ) print(result$agg_r) # global r estimate # Custom weights emphasizing VAF (clusterwise mode) result <- select_r_clusterwise_mfa( list_of_data, K = 3, rvec = 2:6, mode = "clusterwise", criteria = c("VAF", "VSS", "smoothness"), weights = c(VAF = 0.6, VSS = 0.3, smoothness = 0.1) ) ## End(Not run)
Selects the optimal number of principal components (r) by evaluating each cluster separately, rather than averaging metrics across all clusters.
select_r_clusterwise_mpca( list_of_data, K, rvec = 1:6, criteria = c("VAF", "VSS", "smoothness"), agg_method = c("max", "mean", "min", "majority"), vaf_threshold = NULL, vss_threshold = 0.5, vss_method = c("threshold", "ratio"), vss_rotate = c("none", "varimax"), lambda_smooth = 0.001, weights = c(VAF = 0.4, VSS = 0.4, smoothness = 0.2), vss_normalize = c("logr", "max", "r", "r2", "none"), w_elbow = 0, w_r = 0, vaf_degeneracy_threshold = 0.6, max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1, verbose = FALSE, mode = c("clusterwise", "global-first"), global_model = c("PPCA", "FA"), global_criterion = c("CV", "ParallelAnalysis"), global_folds = 5, global_seed = NULL, r_init = NULL )select_r_clusterwise_mpca( list_of_data, K, rvec = 1:6, criteria = c("VAF", "VSS", "smoothness"), agg_method = c("max", "mean", "min", "majority"), vaf_threshold = NULL, vss_threshold = 0.5, vss_method = c("threshold", "ratio"), vss_rotate = c("none", "varimax"), lambda_smooth = 0.001, weights = c(VAF = 0.4, VSS = 0.4, smoothness = 0.2), vss_normalize = c("logr", "max", "r", "r2", "none"), w_elbow = 0, w_r = 0, vaf_degeneracy_threshold = 0.6, max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1, verbose = FALSE, mode = c("clusterwise", "global-first"), global_model = c("PPCA", "FA"), global_criterion = c("CV", "ParallelAnalysis"), global_folds = 5, global_seed = NULL, r_init = NULL )
list_of_data |
A list of N matrices, each (T_i x M). |
K |
Number of clusters (fixed). |
rvec |
Vector of candidate r values to evaluate. Default is 1:6. |
criteria |
Character vector specifying which criteria to use for selection. Options: "VAF", "VSS", "smoothness". Default is c("VAF", "VSS", "smoothness"). |
agg_method |
Method for aggregating cluster-specific r values. Options: "max", "mean", "min", "majority". Default is "max". |
vaf_threshold |
Minimum VAF threshold for each cluster. Set to NULL to disable hard filtering. Default is NULL (disabled). |
vss_threshold |
Threshold for VSS criterion. Default is 0.5. |
vss_method |
Method for computing VSS. Options: "threshold" (count variables with exactly one strong loading above threshold), "ratio" (compute concentration ratio max(lambda^2)/sum(lambda^2) for each variable). Default is "threshold". The "ratio" method is more robust when loadings are small in absolute magnitude. |
vss_rotate |
Rotation method to apply before computing VSS. Options: "none" (no rotation), "varimax" (orthogonal rotation). Default is "none". VSS on unrotated FA loadings is rotation-dependent and often uninformative. Rotation is recommended for meaningful VSS. |
lambda_smooth |
Smoothness penalty weight (deprecated, use weights instead). Default is 1e-3. |
weights |
Named vector of weights for combining criteria. Default is c(VAF=0.4, VSS=0.4, smoothness=0.2). |
vss_normalize |
Method for normalizing VSS to account for r-dependence. Options: "logr" (divide by log(r)), "max" (divide by max VSS), "r" (divide by r), "r2" (divide by r^2), "none". Default is "logr". |
w_elbow |
Weight for DeltaVAF (elbow detection). Higher values emphasize diminishing returns in VAF. Default is 0 (disabled). |
w_r |
Weight for direct r penalty (AIC/BIC style). Higher values penalize larger r. Default is 0 (disabled). |
vaf_degeneracy_threshold |
Threshold for detecting degenerate clusters. If max VAF across all r values is below this threshold, the cluster is considered degenerate and a warning is issued. Default is 0.6. |
max_iter |
Maximum EM iterations for initial clustering. |
nIterPCA |
Sub-iterations for PCA update. |
tol |
Convergence tolerance. |
method |
"EM" or "closed_form". |
n_init |
Number of random initializations for initial clustering. |
use_kmeans_init |
Whether to use k-means initialization. |
subject_rdim_for_kmeans |
Dimension for k-means features. |
mc_cores |
Number of cores for parallelization. |
n_threads |
Number of OpenMP threads. |
verbose |
Logical. If TRUE, print detailed diagnostic information during r selection, including per-r metrics for each cluster and warnings about NA values or degenerate clusters. Default is FALSE. |
mode |
Selection mode. Options: "clusterwise" (default, evaluate r separately per cluster), "global-first" (first estimate global r using FA/PPCA on pooled data, then use for MPCA). The "global-first" mode is recommended as it provides a cluster-independent baseline. |
global_model |
Model for global r estimation (only used when mode = "global-first"). Options: "PPCA" (default), "FA". PPCA is more stable for mixture models. |
global_criterion |
Criterion for global r selection (only used when mode = "global-first"). Options: "CV" (default), "ParallelAnalysis". CV is the primary criterion. |
global_folds |
Number of CV folds for global r selection (only used when mode = "global-first"). Default is 5. |
global_seed |
Random seed for global r selection (only used when mode = "global-first"). Default is NULL. |
r_init |
Initial r value for the first-stage clustering (only used when mode = "clusterwise"). If NULL (default), uses median(rvec). When called from hybrid mode in select_r_mixture(), this is set to r_global to use the global estimate as initialization. |
This function implements the same two-stage approach as
select_r_clusterwise_mfa, but for Mixture PCA models.
See select_r_clusterwise_mfa for details on the scoring approach.
Important Note: The cluster-wise MPCA(K=1) approach is experimental and can be unstable. Each cluster is evaluated independently using a single-cluster MPCA model, which may not capture the full complexity of the data. Use with caution and carefully inspect the verbose output and degeneracy warnings.
A list with:
cluster_r |
Named vector of optimal r for each cluster. |
agg_r |
Aggregated r value across clusters. |
cluster_metrics |
List of data frames with metrics for each cluster. |
initial_fit |
The initial MPCA fit used to determine cluster assignments. |
agg_method |
The aggregation method used. |
mode |
The selection mode used. |
global_result |
(Only for mode = "global-first") The result from select_r_global_mfa(). |
## Not run: result <- select_r_clusterwise_mpca( list_of_data, K = 3, rvec = 2:6, criteria = c("VAF", "VSS", "smoothness") ) print(result$cluster_r) print(result$agg_r) ## End(Not run)## Not run: result <- select_r_clusterwise_mpca( list_of_data, K = 3, rvec = 2:6, criteria = c("VAF", "VSS", "smoothness") ) print(result$cluster_r) print(result$agg_r) ## End(Not run)
Estimates the optimal number of factors (r) using a global Factor Analysis (FA) or Probabilistic PCA (PPCA) model on pooled data. This function is designed for use before fitting mixture models (MFA/MPCA), as it provides a cluster-independent estimate of r based on the overall data structure.
select_r_global_mfa( list_of_data, rvec = 1:6, model = c("PPCA", "FA"), criterion = c("CV", "ParallelAnalysis"), folds = 5, cv_metric = c("negLogLik", "frobenius"), n_permutations = 100, seed = NULL, verbose = FALSE )select_r_global_mfa( list_of_data, rvec = 1:6, model = c("PPCA", "FA"), criterion = c("CV", "ParallelAnalysis"), folds = 5, cv_metric = c("negLogLik", "frobenius"), n_permutations = 100, seed = NULL, verbose = FALSE )
list_of_data |
A list of N matrices, each (T_i x M). |
rvec |
Vector of candidate r values to evaluate. Default is 1:6. |
model |
Model type for global r estimation. Options: "PPCA" (Probabilistic PCA, default), "FA" (Factor Analysis). PPCA is recommended as it is more stable and theory-consistent for mixture models. |
criterion |
Selection criterion. Options: "CV" (Cross-Validation, default), "ParallelAnalysis" (Parallel Analysis). CV is the primary criterion as it is stable and works for both FA and PPCA. Parallel Analysis is optional and lower priority. |
folds |
Number of folds for cross-validation. Default is 5. CV is performed at the subject level (not time-window level) to respect the generative structure. |
cv_metric |
Metric for CV evaluation. Options: "negLogLik" (negative log-likelihood, default), "frobenius" (Frobenius norm of reconstruction error). Negative log-likelihood is the principled choice for probabilistic models. |
n_permutations |
Number of permutations for Parallel Analysis. Default is 100. Only used when criterion = "ParallelAnalysis". |
seed |
Random seed for reproducibility (CV fold assignment and PA permutations). Default is NULL (no seed set). |
verbose |
Logical. If TRUE, print detailed diagnostic information during r selection. Default is FALSE. |
This function implements model-based r estimation for use before mixture model fitting. The key design principles are:
Why Global Model? The global r must be estimated using FA or PPCA on pooled data, NOT using MFA(K>1). Estimating r from a mixture model is cluster-dependent and unstable, as different cluster configurations yield different r estimates. A global model provides a cluster-independent baseline.
Cross-Validation Design: CV is performed at the subject level, not time-window level. Time-window CV would leak subject-level covariance structure and provide overly optimistic estimates. Subject-level CV properly reflects the generative structure where subjects are the independent units.
For each fold:
Split subjects into training and test sets
Fit FA/PPCA on training data (pooled across subjects)
Evaluate reconstruction error or log-likelihood on test data
Average across folds to get CV error for each r
The optimal r is selected by minimizing CV error (or using the one-standard-error rule for parsimony).
Parallel Analysis: PA compares observed eigenvalues to those from permuted data. The optimal r is where observed eigenvalues exceed the 95th percentile of permuted eigenvalues. Note: PA is theoretically questionable for FA (as it assumes isotropic noise), so CV is preferred.
A list with:
r_global |
The selected optimal r value. |
summary |
A data.frame with columns r and criterion-specific metrics (e.g., cv_error, cv_se). |
criterion |
The criterion used for selection. |
model |
The model type used (FA or PPCA). |
cv_curve |
For CV: ggplot object showing CV error vs r (if ggplot2 available). |
vaf_curve |
For CV: ggplot object showing VAF vs r (if ggplot2 available). |
pa_curve |
For PA: ggplot object showing observed vs permuted eigenvalues (if ggplot2 available). |
diagnostics |
Additional diagnostic information. |
## Not run: # Basic usage with default PPCA and CV result <- select_r_global_mfa( list_of_data, rvec = 2:6, model = "PPCA", criterion = "CV", folds = 5 ) print(result$r_global) print(result$summary) # With FA model result_fa <- select_r_global_mfa( list_of_data, rvec = 2:6, model = "FA", criterion = "CV" ) # Using Parallel Analysis result_pa <- select_r_global_mfa( list_of_data, rvec = 2:6, criterion = "ParallelAnalysis", n_permutations = 100 ) ## End(Not run)## Not run: # Basic usage with default PPCA and CV result <- select_r_global_mfa( list_of_data, rvec = 2:6, model = "PPCA", criterion = "CV", folds = 5 ) print(result$r_global) print(result$summary) # With FA model result_fa <- select_r_global_mfa( list_of_data, rvec = 2:6, model = "FA", criterion = "CV" ) # Using Parallel Analysis result_pa <- select_r_global_mfa( list_of_data, rvec = 2:6, criterion = "ParallelAnalysis", n_permutations = 100 ) ## End(Not run)
Estimates the optimal number of principal components (r) using a global Probabilistic PCA (PPCA) model on pooled data. This function is designed for use before fitting mixture MPCA models, as it provides a cluster-independent estimate of r based on the overall data structure.
select_r_global_mpca( list_of_data, rvec = 1:6, model = c("PPCA", "FA"), criterion = c("CV", "ParallelAnalysis"), folds = 5, cv_metric = c("negLogLik", "frobenius"), n_permutations = 100, seed = NULL, verbose = FALSE )select_r_global_mpca( list_of_data, rvec = 1:6, model = c("PPCA", "FA"), criterion = c("CV", "ParallelAnalysis"), folds = 5, cv_metric = c("negLogLik", "frobenius"), n_permutations = 100, seed = NULL, verbose = FALSE )
list_of_data |
A list of N matrices, each (T_i x M). |
rvec |
Vector of candidate r values to evaluate. Default is 1:6. |
model |
Model type for global r estimation. Options: "PPCA" (Probabilistic PCA, default), "FA" (Factor Analysis). PPCA is recommended as it is more stable and theory-consistent for mixture models. |
criterion |
Selection criterion. Options: "CV" (Cross-Validation, default), "ParallelAnalysis" (Parallel Analysis). CV is the primary criterion as it is stable and works for both FA and PPCA. Parallel Analysis is optional and lower priority. |
folds |
Number of folds for cross-validation. Default is 5. CV is performed at the subject level (not time-window level) to respect the generative structure. |
cv_metric |
Metric for CV evaluation. Options: "negLogLik" (negative log-likelihood, default), "frobenius" (Frobenius norm of reconstruction error). Negative log-likelihood is the principled choice for probabilistic models. |
n_permutations |
Number of permutations for Parallel Analysis. Default is 100. Only used when criterion = "ParallelAnalysis". |
seed |
Random seed for reproducibility (CV fold assignment and PA permutations). Default is NULL (no seed set). |
verbose |
Logical. If TRUE, print detailed diagnostic information during r selection. Default is FALSE. |
This function implements model-based r estimation for use before mixture MPCA fitting. The key design principles are:
Why Global Model? The global r must be estimated using PPCA (or FA) on pooled data, NOT using MPCA(K>1). Estimating r from a mixture model is cluster-dependent and unstable, as different cluster configurations yield different r estimates. A global model provides a cluster-independent baseline.
Cross-Validation Design: CV is performed at the subject level, not time-window level. Time-window CV would leak subject-level covariance structure and provide overly optimistic estimates. Subject-level CV properly reflects the generative structure where subjects are the independent units.
For each fold:
Split subjects into training and test sets
Fit PPCA/FA on training data (pooled across subjects)
Evaluate reconstruction error or log-likelihood on test data
Average across folds to get CV error for each r
The optimal r is selected by minimizing CV error (or using the one-standard-error rule for parsimony).
Parallel Analysis: PA compares observed eigenvalues to those from permuted data. The optimal r is where observed eigenvalues exceed the 95th percentile of permuted eigenvalues. Note: PA is theoretically questionable for FA (as it assumes isotropic noise), so CV is preferred.
A list with:
r_global |
The selected optimal r value. |
summary |
A data.frame with columns r and criterion-specific metrics (e.g., cv_error, cv_se). |
criterion |
The criterion used for selection. |
model |
The model type used (FA or PPCA). |
cv_curve |
For CV: ggplot object showing CV error vs r (if ggplot2 available). |
vaf_curve |
For CV: ggplot object showing VAF vs r (if ggplot2 available). |
pa_curve |
For PA: ggplot object showing observed vs permuted eigenvalues (if ggplot2 available). |
diagnostics |
Additional diagnostic information. |
## Not run: # Basic usage with default PPCA and CV result <- select_r_global_mpca( list_of_data, rvec = 2:6, model = "PPCA", criterion = "CV", folds = 5 ) print(result$r_global) print(result$summary) # With FA model result_fa <- select_r_global_mpca( list_of_data, rvec = 2:6, model = "FA", criterion = "CV" ) # Using Parallel Analysis result_pa <- select_r_global_mpca( list_of_data, rvec = 2:6, criterion = "ParallelAnalysis", n_permutations = 100 ) ## End(Not run)## Not run: # Basic usage with default PPCA and CV result <- select_r_global_mpca( list_of_data, rvec = 2:6, model = "PPCA", criterion = "CV", folds = 5 ) print(result$r_global) print(result$summary) # With FA model result_fa <- select_r_global_mpca( list_of_data, rvec = 2:6, model = "FA", criterion = "CV" ) # Using Parallel Analysis result_pa <- select_r_global_mpca( list_of_data, rvec = 2:6, criterion = "ParallelAnalysis", n_permutations = 100 ) ## End(Not run)
This function provides a unified interface for selecting the optimal number of factors (r) in mixture models. It supports three modes: "clusterwise" (evaluate r separately per cluster), "global-first" (estimate r from pooled data first), and "hybrid" (combine both approaches).
select_r_mixture( list_of_data, K, rvec = 1:6, mode = c("clusterwise", "global-first", "hybrid"), model_type = c("MFA", "MPCA"), criteria = c("VAF", "VSS", "smoothness"), agg_method = c("max", "mean", "min", "majority", "global"), global_model = c("PPCA", "FA"), global_criterion = c("CV", "ParallelAnalysis"), global_folds = 5, global_seed = NULL, weights = c(VAF = 0.4, VSS = 0.4, smoothness = 0.2), vss_threshold = 0.5, vss_method = c("threshold", "ratio"), vss_rotate = c("none", "varimax"), vss_normalize = c("logr", "max", "r", "r2", "none"), max_iter = 50, nIterFA = 5, nIterPCA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1, verbose = FALSE, refit_final = TRUE )select_r_mixture( list_of_data, K, rvec = 1:6, mode = c("clusterwise", "global-first", "hybrid"), model_type = c("MFA", "MPCA"), criteria = c("VAF", "VSS", "smoothness"), agg_method = c("max", "mean", "min", "majority", "global"), global_model = c("PPCA", "FA"), global_criterion = c("CV", "ParallelAnalysis"), global_folds = 5, global_seed = NULL, weights = c(VAF = 0.4, VSS = 0.4, smoothness = 0.2), vss_threshold = 0.5, vss_method = c("threshold", "ratio"), vss_rotate = c("none", "varimax"), vss_normalize = c("logr", "max", "r", "r2", "none"), max_iter = 50, nIterFA = 5, nIterPCA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1, verbose = FALSE, refit_final = TRUE )
list_of_data |
A list of N matrices, each (T_i x M). |
K |
Number of clusters (fixed). |
rvec |
Vector of candidate r values to evaluate. Default is 1:6. |
mode |
Selection mode. Options:
|
model_type |
Model type. Options: "MFA" (Mixture Factor Analysis, default), "MPCA" (Mixture Principal Component Analysis). |
criteria |
Character vector specifying which criteria to use for clusterwise selection. Options: "VAF", "VSS", "smoothness". Default is c("VAF", "VSS", "smoothness"). Only used when mode = "clusterwise" or "hybrid". |
agg_method |
Method for aggregating cluster-specific r values. Options: "max" (conservative, takes maximum r across clusters), "mean" (average r, rounded), "min" (minimum r across clusters), "majority" (most common r value), "global" (use the global r estimate r_global as the final r; only valid in hybrid mode). Default is "max". In clusterwise mode, only "max", "mean", "min", "majority" are allowed. In hybrid mode, you may additionally use "global" to set r_final = r_global. Ignored when mode = "global-first". |
global_model |
Model for global r estimation. Options: "PPCA" (default), "FA". Only used when mode = "global-first" or "hybrid". |
global_criterion |
Criterion for global r selection. Options: "CV" (default), "ParallelAnalysis". Only used when mode = "global-first" or "hybrid". |
global_folds |
Number of CV folds for global r selection. Default is 5. Only used when mode = "global-first" or "hybrid" with criterion = "CV". |
global_seed |
Random seed for global r selection. Default is NULL. |
weights |
Named vector of weights for combining criteria in clusterwise mode. Default is c(VAF=0.4, VSS=0.4, smoothness=0.2). |
vss_threshold |
Threshold for VSS criterion. Default is 0.5. |
vss_method |
Method for computing VSS. Options: "threshold", "ratio". Default is "threshold". |
vss_rotate |
Rotation method for VSS. Options: "none", "varimax". Default is "none". |
vss_normalize |
Method for normalizing VSS. Options: "logr", "max", "r", "r2", "none". Default is "logr". |
max_iter |
Maximum EM iterations for model fitting. |
nIterFA |
Sub-iterations for FA update (MFA only). |
nIterPCA |
Sub-iterations for PCA update (MPCA only). |
tol |
Convergence tolerance. |
n_init |
Number of random initializations for mixture model fitting. |
use_kmeans_init |
Whether to use k-means initialization. |
subject_rdim_for_kmeans |
Dimension for k-means features. |
mc_cores |
Number of cores for parallelization. |
n_threads |
Number of OpenMP threads. |
verbose |
Logical. If TRUE, print detailed diagnostic information. |
refit_final |
Logical. If TRUE, refit the final model with selected r_final. Default is TRUE. |
This function provides a unified interface for r selection in mixture models, integrating three complementary approaches:
Mode: "global-first"
Pool all data and fit a global FA/PPCA model
Select r using cross-validation or parallel analysis
Return r_global as the final estimate
This mode is fast and provides a cluster-independent baseline. It's recommended when you want a simple, stable estimate that doesn't depend on cluster structure.
Mode: "clusterwise"
Fit initial mixture model with median(rvec) to get cluster assignments
For each cluster, evaluate different r values using cluster-specific metrics
Aggregate cluster-specific r values using specified method
This mode is useful when different clusters may require different numbers of factors.
Mode: "hybrid"
Estimate r_global using global FA/PPCA (as in "global-first")
Use r_global as initialization for clusterwise evaluation
Evaluate r values around r_global for each cluster
Aggregate cluster-specific r values
This mode combines the stability of global estimation with the flexibility of cluster-specific evaluation.
A list with class "mixture_r_selection" containing:
r_final |
The final selected r value. |
r_global |
Global r estimate (if mode = "global-first" or "hybrid"). |
r_cluster |
Named vector of cluster-specific r values (if mode = "clusterwise" or "hybrid"). |
initial_fit |
Initial mixture model fit used for cluster assignments (if applicable). |
final_fit |
Final mixture model fit with r_final (if refit_final = TRUE). |
diagnostics |
List containing detailed diagnostic information. |
mode |
The selection mode used. |
model_type |
The model type used (MFA or MPCA). |
agg_method |
The aggregation method used (if applicable). |
## Not run: # Global-first mode (recommended for simplicity) result <- select_r_mixture( list_of_data, K = 3, rvec = 2:6, mode = "global-first", model_type = "MFA" ) print(result$r_final) # Clusterwise mode result <- select_r_mixture( list_of_data, K = 3, rvec = 2:6, mode = "clusterwise", model_type = "MFA", agg_method = "max" ) # Hybrid mode result <- select_r_mixture( list_of_data, K = 3, rvec = 2:6, mode = "hybrid", model_type = "MPCA" ) ## End(Not run)## Not run: # Global-first mode (recommended for simplicity) result <- select_r_mixture( list_of_data, K = 3, rvec = 2:6, mode = "global-first", model_type = "MFA" ) print(result$r_final) # Clusterwise mode result <- select_r_mixture( list_of_data, K = 3, rvec = 2:6, mode = "clusterwise", model_type = "MFA", agg_method = "max" ) # Hybrid mode result <- select_r_mixture( list_of_data, K = 3, rvec = 2:6, mode = "hybrid", model_type = "MPCA" ) ## End(Not run)
Selects the optimal number of factors (r) for a given number of clusters (K) by combining multiple criteria: BIC, VAF, smoothness penalty, and VSS.
select_r_multicriteria_mfa( list_of_data, K, rvec = 1:6, vaf_threshold = 0.9, lambda_smooth = 0.001, vss_threshold = 0.5, weights = c(BIC = 1, VAF = 1, smoothness = 1, VSS = 1), max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )select_r_multicriteria_mfa( list_of_data, K, rvec = 1:6, vaf_threshold = 0.9, lambda_smooth = 0.001, vss_threshold = 0.5, weights = c(BIC = 1, VAF = 1, smoothness = 1, VSS = 1), max_iter = 50, nIterFA = 5, tol = 0.001, n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of N matrices, each (T_i x M). |
K |
Number of clusters (fixed). |
rvec |
Vector of candidate r values to evaluate. Default is 1:6. |
vaf_threshold |
Minimum VAF threshold. Models with VAF below this are excluded. Default is 0.9. |
lambda_smooth |
Smoothness penalty weight. Default is 1e-3. |
vss_threshold |
Threshold for VSS criterion. Default is 0.5. |
weights |
Named vector of weights for each criterion. Default is c(BIC = 1, VAF = 1, smoothness = 1, VSS = 1). |
max_iter |
Maximum EM iterations. |
nIterFA |
Sub-iterations for FA update. |
tol |
Convergence tolerance. |
n_init |
Number of random initializations. |
use_kmeans_init |
Whether to use k-means initialization. |
subject_rdim_for_kmeans |
Dimension for k-means features. |
mc_cores |
Number of cores for parallelization. |
n_threads |
Number of OpenMP threads. |
This function combines multiple criteria to select r:
BIC: Lower is better (penalizes complexity)
VAF: Higher is better (rewards fit quality)
Smoothness: Lower is better (penalizes wiggly factors)
VSS: Higher is better (rewards simple structure)
Each criterion is normalized to [0, 1] range, then combined using weights:
The r with the minimum composite score is selected among models satisfying VAF >= vaf_threshold.
A list with:
best_r |
The selected r value. |
summary |
A data.frame with columns r, BIC, VAF, smoothness, VSS, composite_score. |
best_model |
The fitted model for the selected r. |
## Not run: result <- select_r_multicriteria_mfa( list_of_data, K = 3, rvec = 1:5, vaf_threshold = 0.9, lambda_smooth = 1e-3, weights = c(BIC = 1, VAF = 1, smoothness = 1, VSS = 1) ) print(result$summary) best_model <- result$best_model ## End(Not run)## Not run: result <- select_r_multicriteria_mfa( list_of_data, K = 3, rvec = 1:5, vaf_threshold = 0.9, lambda_smooth = 1e-3, weights = c(BIC = 1, VAF = 1, smoothness = 1, VSS = 1) ) print(result$summary) best_model <- result$best_model ## End(Not run)
Selects the optimal number of factors (r) for a given number of clusters (K) by combining multiple criteria: BIC, VAF, smoothness penalty, and VSS.
select_r_multicriteria_mpca( list_of_data, K, rvec = 1:6, vaf_threshold = 0.9, lambda_smooth = 0.001, vss_threshold = 0.5, weights = c(BIC = 1, VAF = 1, smoothness = 1, VSS = 1), max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )select_r_multicriteria_mpca( list_of_data, K, rvec = 1:6, vaf_threshold = 0.9, lambda_smooth = 0.001, vss_threshold = 0.5, weights = c(BIC = 1, VAF = 1, smoothness = 1, VSS = 1), max_iter = 50, nIterPCA = 5, tol = 0.001, method = "EM", n_init = 1, use_kmeans_init = TRUE, subject_rdim_for_kmeans = 2, mc_cores = 1, n_threads = 1 )
list_of_data |
A list of N matrices, each (T_i x M). |
K |
Number of clusters (fixed). |
rvec |
Vector of candidate r values to evaluate. Default is 1:6. |
vaf_threshold |
Minimum VAF threshold. Models with VAF below this are excluded. Default is 0.9. |
lambda_smooth |
Smoothness penalty weight. Default is 1e-3. |
vss_threshold |
Threshold for VSS criterion. Default is 0.5. |
weights |
Named vector of weights for each criterion. Default is c(BIC = 1, VAF = 1, smoothness = 1, VSS = 1). |
max_iter |
Maximum EM iterations. |
nIterPCA |
Sub-iterations for PCA update. |
tol |
Convergence tolerance. |
method |
"EM" or "closed_form". |
n_init |
Number of random initializations. |
use_kmeans_init |
Whether to use k-means initialization. |
subject_rdim_for_kmeans |
Dimension for k-means features. |
mc_cores |
Number of cores for parallelization. |
n_threads |
Number of OpenMP threads. |
This function combines multiple criteria to select r:
BIC: Lower is better (penalizes complexity)
VAF: Higher is better (rewards fit quality)
Smoothness: Lower is better (penalizes wiggly factors)
VSS: Higher is better (rewards simple structure)
Each criterion is normalized to [0, 1] range, then combined using weights:
The r with the minimum composite score is selected among models satisfying VAF >= vaf_threshold.
A list with:
best_r |
The selected r value. |
summary |
A data.frame with columns r, BIC, VAF, smoothness, VSS, composite_score. |
best_model |
The fitted model for the selected r. |
## Not run: result <- select_r_multicriteria_mpca( list_of_data, K = 3, rvec = 1:5, vaf_threshold = 0.9, lambda_smooth = 1e-3, weights = c(BIC = 1, VAF = 1, smoothness = 1, VSS = 1) ) print(result$summary) best_model <- result$best_model ## End(Not run)## Not run: result <- select_r_multicriteria_mpca( list_of_data, K = 3, rvec = 1:5, vaf_threshold = 0.9, lambda_smooth = 1e-3, weights = c(BIC = 1, VAF = 1, smoothness = 1, VSS = 1) ) print(result$summary) best_model <- result$best_model ## End(Not run)
Configures the future backend for parallel execution. Supports local multicore, PBS/TORQUE, SLURM, and other HPC schedulers via future.batchtools.
setup_future_backend( backend = c("multisession", "multicore", "cluster", "sequential", "batchtools_torque", "batchtools_slurm", "batchtools_sge", "batchtools_lsf"), workers = NULL, resources = list(), template = NULL, verbose = TRUE )setup_future_backend( backend = c("multisession", "multicore", "cluster", "sequential", "batchtools_torque", "batchtools_slurm", "batchtools_sge", "batchtools_lsf"), workers = NULL, resources = list(), template = NULL, verbose = TRUE )
backend |
Character. Backend type:
|
workers |
Integer. Number of workers for local backends. |
resources |
List. HPC resource specifications for batchtools backends:
|
template |
Character. Path to batchtools template file (optional). |
verbose |
Logical. Print setup information. |
This function is a wrapper around future::plan() that simplifies
HPC backend configuration. For PBS/TORQUE, it uses
future.batchtools::batchtools_torque.
Invisibly returns the previous plan.
## Not run: # Local multicore setup_future_backend("multisession", workers = 4) # PBS/TORQUE with resources setup_future_backend( "batchtools_torque", resources = list(walltime = "02:00:00", memory = "8gb") ) # Reset to sequential setup_future_backend("sequential") ## End(Not run)## Not run: # Local multicore setup_future_backend("multisession", workers = 4) # PBS/TORQUE with resources setup_future_backend( "batchtools_torque", resources = list(walltime = "02:00:00", memory = "8gb") ) # Reset to sequential setup_future_backend("sequential") ## End(Not run)
Displays a summary of available parallelization strategies and their current availability status.
show_parallel_options()show_parallel_options()
Invisibly returns a list with availability status.
show_parallel_options()show_parallel_options()
This function extends simulate_dynamic_synergy_data() to systematically
evaluate how different motor control strategies affect muscle synergy structures.
The simulation model includes three orthogonal control axes:
(1) Spatial structure, (2) Temporal coordination, and (3) Stability-Adaptability.
These axes represent complementary aspects of motor control diversity observed
in both rehabilitation and sports science contexts.
simulate_dynamic_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 1, cluster_sep_temporal = 1, cluster_sep_stability = 1, freq_range = c(0.5, 3), amp_range = c(0.5, 1.5), base_level = 0.05, rectify_output = TRUE, seed = 123 )simulate_dynamic_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 1, cluster_sep_temporal = 1, cluster_sep_stability = 1, freq_range = c(0.5, 3), amp_range = c(0.5, 1.5), base_level = 0.05, rectify_output = TRUE, seed = 123 )
N |
Number of subjects (time series). Default is 30. |
K |
Number of clusters (subgroups). Default is 3. |
r |
Number of synergies per cluster. Default is 3. |
M |
Number of observed channels (muscles). Default is 8. |
T_each |
Time-series length per subject. Default is 200. |
cluster_sep_spatial |
Numeric scalar (0-2) controlling spatial structure differentiation between clusters. Higher values create more distinct spatial modules. Default is 1.0. |
cluster_sep_temporal |
Numeric scalar (0-2) controlling temporal coordination differentiation between clusters. Higher values create more distinct temporal patterns. Default is 1.0. |
cluster_sep_stability |
Numeric scalar (0-2) controlling stability-adaptability differentiation between clusters. Higher values create more distinct noise profiles. Default is 1.0. |
freq_range |
Numeric vector of length 2 specifying the range of base frequencies (in Hz) for the periodic activation signals. Default is c(0.5, 3.0). |
amp_range |
Numeric vector of length 2 specifying the range of amplitudes for the periodic activation signals. Default is c(0.5, 1.5). |
base_level |
Numeric scalar specifying the baseline activation level added to C(t) to avoid all-zero activations. Default is 0.05. |
rectify_output |
Logical; if TRUE, apply half-wave rectification to X(t) to produce non-negative EMG-like signals. Default is TRUE. |
seed |
Random seed for reproducibility. Default is 123. |
Each cluster (k = 1, ..., K) is assigned a unique combination of parameters along these three axes, emulating distinct movement control strategies (e.g., proximal-dominant, alternating coordination, or adaptive noisy control).
A list with the following components:
X_listList of length N; each element is a (T_each x M) matrix of generated EMG signals.
C_listList of length N; each element is a (T_each x r) matrix of synergy activation signals.
Lambda_listList of length K; each element is a (M x r) matrix of cluster-specific synergy loadings (non-negative).
z_trueInteger vector of length N indicating true cluster assignments (1 to K).
spatial_paramsList containing spatial structure parameters for each cluster (bias patterns).
temporal_paramsList containing temporal coordination parameters for each cluster (frequencies, phase offsets).
stability_paramsList containing stability-adaptability parameters for each cluster (noise levels, filter lengths).
The spatial axis defines how strongly each muscle group contributes to each synergy component. For each cluster k, the synergy matrix (Lambda_k) is generated with cluster-specific bias patterns (B_k) that shift the activation balance among proximal, distal, or antagonistic muscle groups.
The parameter cluster_sep_spatial controls the degree of differentiation
between clusters, ranging from 0 (identical synergy weights) to 2 (strongly
distinct spatial modules).
The temporal axis governs how synergies are activated over time, including their onset timing, overlap, and rhythmic frequency. For each cluster, the activation matrix C_i^(k)(t) is generated with cluster-specific frequencies (f_k) and phase offsets (phi_ij^(k)).
Three representative temporal coordination modes:
Cluster 1: Co-contraction/rigid (all synergies in-phase, strong overlap)
Cluster 2: Alternating/efficient (phases evenly distributed, minimal overlap)
Cluster 3: Adaptive/reactive (random phases, heterogeneous frequencies)
The parameter cluster_sep_temporal (0-2) scales the magnitude of
inter-cluster differences in phase and frequency.
The stability axis introduces physiological and measurement variability into the EMG signal. Each cluster k is assigned distinct noise parameters to simulate differences in control precision and adaptability.
Three representative control profiles:
Cluster 1: Stable control (minimal noise, elite or late rehab)
Cluster 2: Moderate control (balanced smoothness vs flexibility)
Cluster 3: Adaptive/exploratory (variable, early rehab or fatigue)
## Not run: # Basic usage with default parameters sim_v2 <- simulate_dynamic_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200 ) # High spatial separation, low temporal separation sim_spatial <- simulate_dynamic_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 2.0, cluster_sep_temporal = 0.5, cluster_sep_stability = 1.0, seed = 456 ) # Factorial design: 3x3x3 combinations spatial_levels <- c(0.5, 1.0, 2.0) temporal_levels <- c(0.5, 1.0, 2.0) stability_levels <- c(0.5, 1.0, 2.0) results <- list() idx <- 1 for (sp in spatial_levels) { for (tp in temporal_levels) { for (st in stability_levels) { results[[idx]] <- simulate_dynamic_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = sp, cluster_sep_temporal = tp, cluster_sep_stability = st, seed = 100 + idx ) idx <- idx + 1 } } } ## End(Not run)## Not run: # Basic usage with default parameters sim_v2 <- simulate_dynamic_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200 ) # High spatial separation, low temporal separation sim_spatial <- simulate_dynamic_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = 2.0, cluster_sep_temporal = 0.5, cluster_sep_stability = 1.0, seed = 456 ) # Factorial design: 3x3x3 combinations spatial_levels <- c(0.5, 1.0, 2.0) temporal_levels <- c(0.5, 1.0, 2.0) stability_levels <- c(0.5, 1.0, 2.0) results <- list() idx <- 1 for (sp in spatial_levels) { for (tp in temporal_levels) { for (st in stability_levels) { results[[idx]] <- simulate_dynamic_synergy_data( N = 30, K = 3, r = 3, M = 8, T_each = 200, cluster_sep_spatial = sp, cluster_sep_temporal = tp, cluster_sep_stability = st, seed = 100 + idx ) idx <- idx + 1 } } } ## End(Not run)
Functions for comparing different methods (SingleFA, SinglePCA, MixtureFA, MixturePCA) on simulated data.
Functions for visualizing simulation results, including ARI plots, BIC heatmaps, and VAF/reconstruction error visualizations.
Removes all attributes from an object except for names, row.names, and class. This is useful for testing scenarios where you want to simulate data frames without custom attributes (e.g., fitted model objects stored as attributes).
strip_attributes(x)strip_attributes(x)
x |
An R object (typically a data frame) |
The same object with all non-essential attributes removed
## Not run: # Create a data frame with custom attributes df <- data.frame(x = 1:3, y = 4:6) attr(df, "custom_attr") <- "some_value" # Strip custom attributes df_clean <- strip_attributes(df) # df_clean will have only names, row.names, and class attributes ## End(Not run)## Not run: # Create a data frame with custom attributes df <- data.frame(x = 1:3, y = 4:6) attr(df, "custom_attr") <- "some_value" # Strip custom attributes df_clean <- strip_attributes(df) # df_clean will have only names, row.names, and class attributes ## End(Not run)
A simplified wrapper for submitting parameter sweeps to HPC clusters. Automatically selects the appropriate parallelization strategy based on the specified cluster type.
submit_hpc_sweep( cluster_type = c("local", "pbs", "slurm", "sge"), queue = NULL, walltime = "04:00:00", memory = NULL, test = FALSE, cores = 4, output_dir = NULL, submit = TRUE, verbose = TRUE )submit_hpc_sweep( cluster_type = c("local", "pbs", "slurm", "sge"), queue = NULL, walltime = "04:00:00", memory = NULL, test = FALSE, cores = 4, output_dir = NULL, submit = TRUE, verbose = TRUE )
cluster_type |
Character. Type of HPC cluster:
|
queue |
Character. Queue/partition name for the cluster. Required for HPC clusters. |
walltime |
Character. Maximum wall time per job (default: "04:00:00"). |
memory |
Character. Memory per job (default: "4gb" for PBS, "4096" for SLURM). |
test |
Logical. If TRUE, use test parameter grid. Default is FALSE. |
cores |
Integer. Number of cores for local execution. Default is 4. |
output_dir |
Character. Output directory for results. |
submit |
Logical. If TRUE, submit jobs. If FALSE, just generate scripts. Default is TRUE. |
verbose |
Logical. Print progress messages. Default is TRUE. |
This function provides a simplified interface for the most common HPC use cases. It automatically:
Selects the appropriate future backend for the cluster type
Configures resource specifications
Handles PBS vs SLURM differences
For more control over the submission, use run_param_sweep_modelsel
directly with parallel_strategy = "future" or "pbs".
Invisibly returns the result from run_param_sweep_modelsel.
run_param_sweep_modelsel, setup_future_backend
## Not run: # Local execution (8 cores) submit_hpc_sweep("local", cores = 8, test = TRUE) # PBS cluster submit_hpc_sweep("pbs", queue = "batch", walltime = "02:00:00") # SLURM cluster submit_hpc_sweep("slurm", queue = "compute", memory = "8192") # Dry run (generate scripts without submitting) submit_hpc_sweep("pbs", queue = "batch", submit = FALSE) ## End(Not run)## Not run: # Local execution (8 cores) submit_hpc_sweep("local", cores = 8, test = TRUE) # PBS cluster submit_hpc_sweep("pbs", queue = "batch", walltime = "02:00:00") # SLURM cluster submit_hpc_sweep("slurm", queue = "compute", memory = "8192") # Dry run (generate scripts without submitting) submit_hpc_sweep("pbs", queue = "batch", submit = FALSE) ## End(Not run)
Prepares and optionally submits a PBS array job for parameter sweep.
submit_pbs_sweep( param_grid, output_dir, pbs_config = list(), sweep_type = c("modelsel", "baselines"), sweep_config = list(), submit = FALSE, verbose = TRUE )submit_pbs_sweep( param_grid, output_dir, pbs_config = list(), sweep_type = c("modelsel", "baselines"), sweep_config = list(), submit = FALSE, verbose = TRUE )
param_grid |
Data frame. Parameter grid to sweep. |
output_dir |
Character. Directory for output files. |
pbs_config |
List. PBS configuration options (see |
sweep_type |
Character. Type of sweep: "modelsel" or "baselines". |
sweep_config |
List. Sweep-specific configuration. |
submit |
Logical. If TRUE, submit the job. If FALSE, only generate scripts. |
verbose |
Logical. Print progress messages. |
List containing:
job_id: PBS job ID (if submitted)
script_file: Path to the PBS script
param_grid_file: Path to the saved parameter grid
output_dir: Output directory
n_tasks: Number of tasks
## Not run: # Generate scripts only (dry run) result <- submit_pbs_sweep( param_grid = make_param_grid_test(), output_dir = "results", submit = FALSE ) # Submit job result <- submit_pbs_sweep( param_grid = make_param_grid_paper_core(), output_dir = "results", pbs_config = list(queue = "batch"), submit = TRUE ) ## End(Not run)## Not run: # Generate scripts only (dry run) result <- submit_pbs_sweep( param_grid = make_param_grid_test(), output_dir = "results", submit = FALSE ) # Submit job result <- submit_pbs_sweep( param_grid = make_param_grid_paper_core(), output_dir = "results", pbs_config = list(queue = "batch"), submit = TRUE ) ## End(Not run)
Computes total SSE and VAF across all subjects, and optionally by cluster.
summarize_vaf_sse_mfa(mfa_fit, list_of_data, by_cluster = FALSE)summarize_vaf_sse_mfa(mfa_fit, list_of_data, by_cluster = FALSE)
mfa_fit |
A fitted MFA model (with z, Lambda, Psi, mu, etc.). |
list_of_data |
The data list (a list of (T_i x M) matrices). |
by_cluster |
Logical; if TRUE, returns a data.frame with SSE/VAF per cluster. |
If by_cluster=FALSE, returns a named vector with SSE and VAF.
If by_cluster=TRUE, returns a data.frame with columns
Cluster, SSE, T, SSE_per_time, VAF.
Summary Method for mixture_r_selection Objects
## S3 method for class 'mixture_r_selection' summary(object, ...)## S3 method for class 'mixture_r_selection' summary(object, ...)
object |
A mixture_r_selection object. |
... |
Additional arguments (ignored). |
Summary Method for preprocessed_emg Objects
## S3 method for class 'preprocessed_emg' summary(object, ...)## S3 method for class 'preprocessed_emg' summary(object, ...)
object |
A preprocessed_emg object |
... |
Additional arguments (ignored) |
This file provides consistent theme and style definitions for all visualization functions in the synergyMixR package, ensuring publication-quality graphics with unified aesthetics. Get Unified Theme for synergyMixR Plots
theme_mixsynergy(base_size = 11, base_family = "")theme_mixsynergy(base_size = 11, base_family = "")
base_size |
Base font size (default: 11) |
base_family |
Base font family (default: "") |
Returns a consistent ggplot2 theme for all package visualizations. Based on theme_minimal() with customizations for publication quality.
A ggplot2 theme object
## Not run: library(ggplot2) ggplot(data, aes(x, y)) + geom_point() + theme_mixsynergy() ## End(Not run)## Not run: library(ggplot2) ggplot(data, aes(x, y)) + geom_point() + theme_mixsynergy() ## End(Not run)
Returns a specialized theme for heatmap visualizations with minimal grid lines.
theme_mixsynergy_heatmap(base_size = 11, base_family = "")theme_mixsynergy_heatmap(base_size = 11, base_family = "")
base_size |
Base font size (default: 11) |
base_family |
Base font family (default: "") |
A ggplot2 theme object optimized for heatmaps
## Not run: library(ggplot2) ggplot(data, aes(x, y, fill = value)) + geom_tile() + theme_mixsynergy_heatmap() ## End(Not run)## Not run: library(ggplot2) ggplot(data, aes(x, y, fill = value)) + geom_tile() + theme_mixsynergy_heatmap() ## End(Not run)
A consistent theme for parameter sweep visualization that ensures readable text, clear facets, and prevents layout collapse.
theme_sweep(base_size = 12, base_family = "")theme_sweep(base_size = 12, base_family = "")
base_size |
Base font size. Default is 12. |
base_family |
Base font family. Default is "". |
A ggplot2 theme object
## Not run: library(ggplot2) ggplot(mtcars, aes(wt, mpg)) + geom_point() + theme_sweep() ## End(Not run)## Not run: library(ggplot2) ggplot(mtcars, aes(wt, mpg)) + geom_point() + theme_sweep() ## End(Not run)
This file contains visualization functions to diagnose failures in the Two-step algorithm (fit_two_step_baseline). These functions help identify issues with basis alignment, clustering, and reconstruction.
Blocks until a PBS job completes.
wait_for_pbs_job( job_id, check_interval = 60, timeout = NULL, initial_wait = 5, output_dir = NULL, n_tasks = NULL, verbose = TRUE )wait_for_pbs_job( job_id, check_interval = 60, timeout = NULL, initial_wait = 5, output_dir = NULL, n_tasks = NULL, verbose = TRUE )
job_id |
Character. PBS job ID. |
check_interval |
Integer. Seconds between status checks. |
timeout |
Integer. Maximum seconds to wait (NULL for no timeout). |
initial_wait |
Integer. Seconds to wait before first status check. This gives time for the job to be registered in the queue. |
output_dir |
Character. If provided, also monitors partial_results directory to track progress. |
n_tasks |
Integer. Total number of expected tasks (used with output_dir). |
verbose |
Logical. Print progress messages. |
Logical. TRUE if job completed, FALSE if timeout.
## Not run: wait_for_pbs_job("12345", timeout = 3600) # Wait up to 1 hour ## End(Not run)## Not run: wait_for_pbs_job("12345", timeout = 3600) # Wait up to 1 hour ## End(Not run)