This vignette provides a comprehensive guide to selecting the optimal number of clusters (K) and factors (r) in mixture-based muscle synergy analysis. While individual selection methods are documented elsewhere, this guide focuses on:
In mixture models, K (number of clusters) and r (number of factors) have strong interactions. Simultaneously searching over all (K, r) combinations can be:
The two-stage approach addresses these issues by:
Stage 1: K Selection (r fixed)
├── Fix r = r_fixed (default: 2)
├── For each K in Kvec:
│ └── Fit model, compute BIC
└── Select best_K = argmin(BIC)
Stage 2: r Selection (K fixed)
├── Fix K = best_K
├── For each r in rvec:
│ └── Fit model, compute BIC
└── Select best_r = argmin(BIC)
# Two-stage selection for MFA
result_2stage <- select_optimal_K_r_mfa_twostage(
list_of_data,
Kvec = 2:5, # Candidates for K
rvec = 1:6, # Candidates for r
r_fixed = 2, # Fixed r for Stage 1
max_iter = 50,
n_init = 3,
use_kmeans_init = TRUE
)
# Results
cat("=== Two-Stage Selection Results ===\n")
cat("Stage 1 (K search with r =", 2, "):\n")
print(result_2stage$stage1_summary)
cat("\nStage 2 (r search with K =", result_2stage$best_K, "):\n")
print(result_2stage$stage2_summary)
cat("\nFinal selection: K =", result_2stage$best_K, ", r =", result_2stage$best_r, "\n")The r_fixed parameter in Stage 1 affects the K
selection. Guidelines:
| r_fixed | When to Use |
|---|---|
| 2 (default) | Safe default for most applications |
| 3-4 | When you expect moderate synergy complexity |
| 1 | When data is very noisy or sample size is small |
If you have prior knowledge about r (e.g., from literature or global r estimation), use that value:
| Method | Complexity | Stability | Optimality |
|---|---|---|---|
| Grid Search | O( | Kvec | × |
| Two-Stage | O( | Kvec | + |
Recommendation: - Use two-stage for initial exploration or when computation is limited - Use grid search for final model selection when resources allow
After running a grid search, you may want to compare multiple (K, r) candidates beyond just BIC. The post-hoc evaluation functions provide additional metrics.
This function computes additional metrics for all models from a grid search:
| Column | Description | Good Value |
|---|---|---|
K |
Number of clusters | - |
r |
Number of factors | - |
logLik |
Log-likelihood | Higher is better |
BIC |
Bayesian Information Criterion | Lower is better |
GlobalVAF |
Variance Accounted For | > 0.85 |
minClusterSize |
Smallest cluster size | > N/(2K) |
maxClusterSize |
Largest cluster size | < N - N/(2K) |
Extreme cluster size imbalance can indicate:
n_initRetrieve a specific model for detailed analysis:
# Get a model that's not BIC-optimal but has other desirable properties
# e.g., higher VAF, more balanced clusters
alt_model <- get_model_by_K_r(grid_result, K_target = 3, r_target = 4)
if (!is.null(alt_model)) {
# Analyze this model
alt_model <- compute_factor_scores_mfa(alt_model, list_of_data)
# Visualize synergy patterns
plot_cluster_synergy_loadings_mfa(alt_model, plot_type = "heatmap")
# Check factor score smoothness
smoothness <- compute_smoothness_penalty(alt_model$factor_scores)
cat("Smoothness penalty:", smoothness, "\n")
}# Compare top 3 candidates by different criteria
top_by_bic <- df_posthoc[order(df_posthoc$BIC), ][1:3, ]
top_by_vaf <- df_posthoc[order(-df_posthoc$GlobalVAF), ][1:3, ]
cat("Top 3 by BIC:\n")
print(top_by_bic[, c("K", "r", "BIC", "GlobalVAF")])
cat("\nTop 3 by VAF:\n")
print(top_by_vaf[, c("K", "r", "BIC", "GlobalVAF")])
# If different, investigate bothThis section presents the recommended end-to-end workflow for analysts.
┌─────────────────────────────────────────────────────────────────┐
│ Phase 1: Preliminary Investigation │
├─────────────────────────────────────────────────────────────────┤
│ 1. Global r estimation (K-independent) │
│ select_r_global_mfa(list_of_data, rvec = 2:6) │
│ → Obtain r_global as baseline │
│ │
│ 2. Visualize CV curve │
│ plot(result, type = "global_cv") │
└────────────────────┬────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Phase 2: Joint K,r Selection │
├─────────────────────────────────────────────────────────────────┤
│ Option A: Grid Search (comprehensive) │
│ select_optimal_K_r_mfa(Kvec = 1:5, rvec = r_global ± 1) │
│ │
│ Option B: Two-Stage (efficient) │
│ select_optimal_K_r_mfa_twostage(Kvec = 2:5, rvec = 1:6, │
│ r_fixed = r_global) │
│ │
│ Option C: Hybrid r-Selection (for fixed K) │
│ select_r_mixture(K = 3, rvec = 2:6, mode = "hybrid") │
└────────────────────┬────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Phase 3: Diagnostics and Visualization │
├─────────────────────────────────────────────────────────────────┤
│ 1. Summary statistics │
│ print(result); summary(result) │
│ │
│ 2. Visualizations │
│ plot(result, type = "overview") │
│ plot_cluster_synergy_loadings_mfa(best_model) │
│ plot_all_factor_scores_mfa(best_model, list_of_data) │
│ │
│ 3. Check for issues │
│ - Boundary r values │
│ - Unbalanced clusters │
│ - Non-smooth factor scores │
└────────────────────┬────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Phase 4: Post-Hoc Evaluation and Final Decision │
├─────────────────────────────────────────────────────────────────┤
│ 1. Compare multiple candidates │
│ df <- posthoc_mfa_evaluation(list_of_data, grid_result) │
│ │
│ 2. Retrieve alternative models │
│ alt <- get_model_by_K_r(grid_result, K = 3, r = 4) │
│ │
│ 3. Final decision based on: │
│ - BIC vs VAF trade-off │
│ - Cluster balance │
│ - Physiological interpretability │
│ - Factor score smoothness │
└─────────────────────────────────────────────────────────────────┘
# ========================================
# Phase 1: Preliminary Investigation
# ========================================
cat("=== Phase 1: Global r Estimation ===\n")
global_result <- select_r_global_mfa(
list_of_data,
rvec = 2:6,
criterion = "CV"
)
r_global <- global_result$r_global
cat("Estimated r_global:", r_global, "\n")
# ========================================
# Phase 2: Joint K,r Selection
# ========================================
cat("\n=== Phase 2: Grid Search ===\n")
# Focus search around r_global
rvec_focused <- max(1, r_global - 1):min(8, r_global + 2)
grid_result <- select_optimal_K_r_mfa(
list_of_data,
Kvec = 1:5,
rvec = rvec_focused,
n_init = 5,
use_kmeans_init = TRUE
)
best_K <- grid_result$best_model_info$K
best_r <- grid_result$best_model_info$r
cat("BIC-optimal: K =", best_K, ", r =", best_r, "\n")
# ========================================
# Phase 3: Diagnostics
# ========================================
cat("\n=== Phase 3: Diagnostics ===\n")
best_model <- grid_result$best_model_info$model
# Compute factor scores
best_model <- compute_factor_scores_mfa(best_model, list_of_data)
# Check cluster sizes
cluster_sizes <- table(best_model$z)
cat("Cluster sizes:", paste(cluster_sizes, collapse = ", "), "\n")
# Check VAF
vaf <- compute_global_vaf_mfa(list_of_data, best_model)
cat("Global VAF:", round(vaf, 4), "\n")
# Check smoothness
smoothness <- compute_smoothness_penalty(best_model$factor_scores)
cat("Smoothness penalty:", round(smoothness, 2), "\n")
# Visualize
plot_cluster_synergy_loadings_mfa(best_model, plot_type = "heatmap")
# ========================================
# Phase 4: Post-Hoc Evaluation
# ========================================
cat("\n=== Phase 4: Post-Hoc Comparison ===\n")
df_posthoc <- posthoc_mfa_evaluation(list_of_data, grid_result)
print(head(df_posthoc, 10))
# Final decision checklist
cat("\n=== Final Decision Checklist ===\n")
cat("[ ] VAF >= 0.85:", vaf >= 0.85, "\n")
cat("[ ] BIC is optimal or near-optimal\n")
cat("[ ] Clusters are reasonably balanced:",
min(cluster_sizes) >= length(list_of_data) / (2 * best_K), "\n")
cat("[ ] r is not at boundary:",
best_r > min(rvec_focused) & best_r < max(rvec_focused), "\n")
cat("[ ] Synergy loadings are interpretable: (visual inspection)\n")
cat("[ ] Factor scores are smooth: (visual inspection)\n")Use this checklist for final model selection:
| Check | How to Verify | Good Status |
|---|---|---|
| VAF sufficient | compute_global_vaf_mfa() |
>= 0.85-0.90 |
| BIC near optimal | grid_result$summary |
Within 10 of minimum |
| Clusters balanced | table(model$z) |
min >= N/(2K) |
| r not at boundary | Check best_r vs rvec |
Not at edges |
| Loadings interpretable | plot_cluster_synergy_loadings_mfa() |
Clear structure |
| Scores smooth | plot_all_factor_scores_mfa() |
No high-frequency noise |
Scenario 1: r at boundary
if (best_r == max(rvec_focused)) {
cat("Warning: r at upper boundary. Expand rvec.\n")
# Re-run with expanded range
}Scenario 2: Unbalanced clusters
if (min(cluster_sizes) < 5) {
cat("Warning: Very small cluster. Consider:\n")
cat(" - Reducing K\n")
cat(" - Checking for outliers\n")
cat(" - Using more initializations\n")
}Scenario 3: Low VAF
This guide covered three key aspects of model selection:
select_optimal_K_r_mfa_twostage()r_fixed based on global r estimate or domain
knowledgeposthoc_mfa_evaluation() for comprehensive
metricsget_model_by_K_r() to retrieve specific modelsKey Recommendations:
vignette("r_selection_framework"): Detailed r-selection
methodsvignette("metrics_reference"): Understanding each
metricvignette("tutorial"): Basic MFA/MPCA usage