Selecting the optimal number of factors (r) is a critical step in
mixture-based muscle synergy analysis. The synergyMixR
package provides a unified framework for r-selection that integrates
three complementary approaches:
This vignette demonstrates how to use the unified
select_r_mixture() function and interpret the results using
the built-in visualization methods.
We’ll use synthetic data to demonstrate the r-selection framework. This allows us to know the true r value and evaluate how well each method recovers it.
# Generate synthetic data with known structure
# N = 50 subjects, K = 3 clusters, r = 4 true synergies, M = 8 muscles
sim_data <- generate_synergy_data(
N = 50,
K = 3,
r = 4, # True number of synergies
M = 8,
T_each = 100,
cluster_sep_spatial = 1.0,
seed = 123
)
list_of_data <- sim_data$list_of_data
z_true <- sim_data$true_cluster
cat("Generated data with", length(list_of_data), "subjects\n")
cat("True cluster sizes:", table(z_true), "\n")
cat("True r = 4\n")The global-first mode estimates r by pooling all data together, ignoring cluster structure. This provides a fast, cluster-independent baseline estimate.
# Estimate r using global-first mode
result_global <- select_r_mixture(
list_of_data = list_of_data,
K = 3,
rvec = 2:6, # Candidate r values to evaluate
mode = "global-first",
model_type = "MFA",
global_model = "PPCA", # Use PPCA for global estimation
global_criterion = "CV", # Cross-validation
global_folds = 5,
verbose = TRUE
)
# View results
print(result_global)
summary(result_global)The clusterwise mode evaluates r separately for each cluster, then aggregates the results. This allows different clusters to have different optimal r values.
# Estimate r using clusterwise mode
result_cluster <- select_r_mixture(
list_of_data = list_of_data,
K = 3,
rvec = 2:6,
mode = "clusterwise",
model_type = "MFA",
criteria = c("VAF", "VSS", "smoothness"), # Multiple criteria
agg_method = "max", # Take maximum r across clusters
weights = c(VAF = 0.4, VSS = 0.4, smoothness = 0.2),
verbose = TRUE
)
# View results
print(result_cluster)
summary(result_cluster)
# Check cluster-specific r values
cat("Cluster-specific r values:\n")
print(result_cluster$r_cluster)
cat("Aggregated r_final:", result_cluster$r_final, "\n")The agg_method parameter controls how cluster-specific r
values are combined:
# Compare different aggregation methods
methods <- c("max", "mean", "min", "majority")
results <- lapply(methods, function(method) {
res <- select_r_mixture(
list_of_data = list_of_data,
K = 3,
rvec = 2:6,
mode = "clusterwise",
model_type = "MFA",
agg_method = method,
verbose = FALSE
)
c(method = method, r_final = res$r_final)
})
cat("Comparison of aggregation methods:\n")
do.call(rbind, results)# Overview: shows cluster metrics heatmap and cluster scores
plot(result_cluster)
# Individual plot types
plot(result_cluster, type = "cluster_metrics") # Heatmap
plot(result_cluster, type = "cluster_scores") # Line plotsThe heatmap shows how each cluster’s composite score varies with r. Blue squares mark the selected r for each cluster.
The hybrid mode combines the best of both approaches: it uses global estimation to get a stable initialization, then refines with cluster-specific evaluation.
# Estimate r using hybrid mode
result_hybrid <- select_r_mixture(
list_of_data = list_of_data,
K = 3,
rvec = 2:6,
mode = "hybrid",
model_type = "MFA",
global_model = "PPCA",
global_criterion = "CV",
criteria = c("VAF", "VSS", "smoothness"),
agg_method = "max", # Can also use "global" to skip clusterwise
verbose = TRUE
)
# View results
print(result_hybrid)
summary(result_hybrid)
# Compare global vs cluster-specific estimates
cat("\nComparison:\n")
cat("Global r:", result_hybrid$r_global, "\n")
cat("Cluster-specific r:", result_hybrid$r_cluster, "\n")
cat("Final r:", result_hybrid$r_final, "\n")In hybrid mode, you can use agg_method = "global" to
directly use r_global without clusterwise refinement:
# Overview: shows all available plots
plot(result_hybrid)
# Individual plot types
plot(result_hybrid, type = "global_cv") # CV curve
plot(result_hybrid, type = "r_comparison") # Bar plot comparing r values
plot(result_hybrid, type = "cluster_metrics") # Heatmap
plot(result_hybrid, type = "cluster_scores") # Line plotsThe r_comparison plot is particularly useful in hybrid mode, showing how r_global compares to cluster-specific estimates and the final r_final.
The framework supports both Mixture Factor Analysis (MFA) and Mixture PCA (MPCA). Here’s how to use MPCA:
# Use MPCA instead of MFA
result_mpca <- select_r_mixture(
list_of_data = list_of_data,
K = 3,
rvec = 2:6,
mode = "hybrid",
model_type = "MPCA", # Change to MPCA
global_model = "PPCA", # PPCA for global estimation
verbose = TRUE
)
print(result_mpca)
plot(result_mpca)When to use MFA vs MPCA:
For more control, you can directly use the underlying clusterwise functions:
# Direct call to clusterwise function
result_direct <- select_r_clusterwise_mfa(
list_of_data = list_of_data,
K = 3,
rvec = 2:6,
mode = "clusterwise",
criteria = c("VAF", "VSS"),
agg_method = "max",
r_init = 4, # Specify initial r for clustering (Phase 3 feature)
verbose = TRUE
)
cat("Selected r:", result_direct$agg_r, "\n")The r_init parameter (added in Phase 3) allows you to
specify the initial r value used for the first-stage clustering. This is
automatically set to r_global in hybrid mode.
Always visualize the results to ensure the selection makes sense:
For large datasets, consider: - Using mc_cores > 1
for parallelization - Reducing n_init (number of random
initializations) - Starting with global-first for quick exploration
Solution: This suggests cluster structure is important. Use hybrid mode and examine cluster-specific estimates:
Solution: Expand your rvec range:
Solution: Check for degenerate clusters (too few subjects or low VAF):
# Run with verbose=TRUE to see warnings
result_verbose <- select_r_mixture(
list_of_data = list_of_data,
K = 3,
rvec = 2:6,
mode = "clusterwise",
verbose = TRUE # Shows degeneracy warnings
)
# Check cluster sizes
if (!is.null(result_verbose$initial_fit)) {
cat("Cluster sizes:", table(result_verbose$initial_fit$z), "\n")
}When you want to combine multiple metrics with custom weights, use
select_r_multicriteria_mfa():
# Multi-criteria selection with custom weights
result_multi <- select_r_multicriteria_mfa(
list_of_data = list_of_data,
K = 3,
rvec = 2:6,
vaf_threshold = 0.85, # Minimum VAF required
weights = c(BIC = 1, VAF = 1, smoothness = 1, VSS = 1)
)
# View detailed summary
print(result_multi$summary)
cat("Selected r:", result_multi$best_r, "\n")The multi-criteria approach combines four metrics:
Each metric is normalized to [0, 1], then combined:
score = w_BIC × BIC_norm + w_VAF × (1 - VAF_norm)
+ w_smooth × smooth_norm + w_VSS × (1 - VSS_norm)
The r with the minimum score (among those satisfying VAF threshold) is selected.
| Scenario | Recommended Weights | Rationale |
|---|---|---|
| Interpretation focus | VSS = 2, others = 1 |
Prioritize simple, interpretable loadings |
| Generalization focus | BIC = 2, others = 1 |
Avoid overfitting |
| EMG time-series | smoothness = 2, others = 1 |
Leverage temporal structure |
| Balanced (default) | All = 1 | Equal consideration |
# Example: Emphasize interpretability
result_interpret <- select_r_multicriteria_mfa(
list_of_data, K = 3, rvec = 2:6,
weights = c(BIC = 1, VAF = 1, smoothness = 1, VSS = 2)
)
# Example: Emphasize generalization
result_general <- select_r_multicriteria_mfa(
list_of_data, K = 3, rvec = 2:6,
weights = c(BIC = 2, VAF = 1, smoothness = 1, VSS = 1)
)
cat("Interpretation-focused r:", result_interpret$best_r, "\n")
cat("Generalization-focused r:", result_general$best_r, "\n")This section provides detailed explanations of each metric used in r-selection.
Purpose: Estimate generalization performance by testing on held-out subjects.
Method: Leave-one-subject-out cross-validation
When to use: Primary criterion for global r estimation
Interpretation: - Lower CV error = better generalization - Look for “elbow” in the CV curve - Selected r minimizes CV error
Purpose: Measure how much variance the model explains. \[ \text{VAF} = 1 - \frac{\sum_i \|X_i - \hat{X}_i\|^2}{\sum_i \|X_i - \bar{X}\|^2} \]
Interpretation: - VAF = 0.90 means 90% of variance explained - Increases monotonically with r (more factors = more variance explained) - Cannot detect overfitting alone
Typical thresholds (muscle synergy literature): - Minimum acceptable: 0.80 - Good: 0.85-0.90 - Excellent: > 0.95
Caution: Use with other metrics; VAF alone favors larger r.
Purpose: Detect overfitting by measuring temporal smoothness of factor scores.
Method: Sum of squared second-order differences \[ \text{Smoothness} = \sum_{i,j,t} (z_{i,j,t} - 2z_{i,j,t-1} + z_{i,j,t-2})^2 \]
Interpretation: - Low smoothness = smooth, physiologically plausible activations - High smoothness = “wiggly” factors fitting high-frequency noise - EMG-specific: leverages expected temporal structure
When to use: Particularly useful for EMG/muscle synergy analysis where factor scores should vary smoothly over time.
Purpose: Evaluate interpretability of factor loadings.
Concept: Each muscle should load strongly on few (ideally one) synergy.
Two methods:
Interpretation: - High VSS = each muscle clearly associated with one synergy - Low VSS = complex, hard-to-interpret loadings
Note: Apply after varimax rotation for meaningful results:
Purpose: Determine r by comparing eigenvalues to random data.
Method: 1. Compute eigenvalues of pooled covariance matrix 2. Generate random permutations of data 3. Compute 95th percentile of random eigenvalues 4. Select r = number of observed eigenvalues exceeding random threshold
Interpretation: - Conservative estimate (often underestimates r) - Good for exploratory analysis - Less suitable when cluster structure is strong
Purpose: Balance model fit and complexity. \[ \text{BIC} = -2 \log L + p \log(n) \]
where p = number of parameters, n = sample size.
Interpretation: - Lower BIC = better model - Automatically penalizes complexity - Used in K,r grid search for joint selection
The unified r-selection framework provides three complementary approaches:
| Mode | Speed | Stability | Flexibility | Recommended Use |
|---|---|---|---|---|
| Global-first | Fast | High | Low | Quick baseline, large datasets |
| Clusterwise | Moderate | Moderate | High | Heterogeneous populations |
| Hybrid | Slow | High | High | Default recommendation |
Key takeaways:
select_r_mixture() as the unified entry pointmode = "hybrid" for most applicationsplot(result)verbose = TRUE to understand the selection
processFor more information on the underlying methods:
?select_r_global_mfa for CV and Parallel Analysis?select_r_clusterwise_mfa for metrics and aggregation