""" RTX-Neuro Example: Statistical Analysis This example demonstrates how to perform statistical tests on neuroimaging data using the rtx_neuro library. Available functions: - ttest_1samp: One-sample t-test - ttest_ind: Independent samples t-test (Welch's) - ttest_rel: Paired samples t-test - permutation_t_test: Non-parametric permutation test - fdr_correction: Benjamini-Hochberg FDR correction - bonferroni_correction: Bonferroni correction """ import rtx_neuro as rtx import numpy as np # Set random seed for reproducibility np.random.seed(42) # Example 1: One-sample t-test def ttest_1samp_example(): """Test if sample mean differs from a hypothesized value.""" # Generate sample data (e.g., ERP amplitudes) # True mean = 2.0 data = np.random.normal(loc=2.0, scale=0.5, size=30) # Test against null hypothesis: mean = 0 t_stat, p_value = rtx.stats.ttest_1samp(data, popmean=0.0) print("One-Sample T-Test") print(f" Sample mean: {np.mean(data):.3f}") print(f" t-statistic: {t_stat:.3f}") print(f" p-value: {p_value:.6f}") print(f" Significant at alpha=0.05: {p_value < 0.05}") # Test against different null t_stat2, p_value2 = rtx.stats.ttest_1samp(data, popmean=2.0) print(f"\nTest against true mean (2.0):") print(f" p-value: {p_value2:.6f} (should be > 0.05)") return t_stat, p_value # Example 2: Independent samples t-test def ttest_ind_example(): """Compare means of two independent groups.""" # Group 1: Control condition control = np.random.normal(loc=5.0, scale=1.0, size=25) # Group 2: Treatment condition (with effect) treatment = np.random.normal(loc=6.5, scale=1.0, size=25) t_stat, p_value = rtx.stats.ttest_ind(control, treatment) print("\nIndependent Samples T-Test (Welch's)") print(f" Control mean: {np.mean(control):.3f}") print(f" Treatment mean: {np.mean(treatment):.3f}") print(f" t-statistic: {t_stat:.3f}") print(f" p-value: {p_value:.6f}") print(f" Significant at alpha=0.05: {p_value < 0.05}") return t_stat, p_value # Example 3: Paired samples t-test def ttest_rel_example(): """Compare means of paired observations (e.g., pre/post).""" # Pre-treatment measurements pre = np.array([4.5, 5.2, 4.8, 5.1, 4.9, 5.3, 4.7, 5.0, 4.6, 5.4]) # Post-treatment (with improvement) post = pre + np.random.normal(loc=1.0, scale=0.3, size=10) t_stat, p_value = rtx.stats.ttest_rel(pre, post) print("\nPaired Samples T-Test") print(f" Pre mean: {np.mean(pre):.3f}") print(f" Post mean: {np.mean(post):.3f}") print(f" Mean difference: {np.mean(post - pre):.3f}") print(f" t-statistic: {t_stat:.3f}") print(f" p-value: {p_value:.6f}") print(f" Significant at alpha=0.05: {p_value < 0.05}") return t_stat, p_value # Example 4: Permutation test def permutation_test_example(): """Non-parametric test using permutation of labels.""" # Two groups with small sample sizes (good for permutation) group_a = np.array([3.2, 3.8, 4.1, 3.5, 4.0, 3.9]) group_b = np.array([5.1, 4.8, 5.3, 5.0, 4.9, 5.2]) # Run permutation test obs_stat, p_value = rtx.stats.permutation_t_test( group_a, group_b, n_permutations=10000, seed=42 # For reproducibility ) print("\nPermutation T-Test") print(f" Group A mean: {np.mean(group_a):.3f}") print(f" Group B mean: {np.mean(group_b):.3f}") print(f" Observed statistic: {obs_stat:.3f}") print(f" p-value: {p_value:.6f}") print(f" Significant at alpha=0.05: {p_value < 0.05}") return obs_stat, p_value # Example 5: Multiple comparison correction def multiple_comparison_example(): """Correct for multiple comparisons (e.g., many channels/timepoints).""" # Simulate p-values from 100 tests # Mix of true effects and null effects n_tests = 100 n_true_effects = 10 # Generate p-values p_values = np.ones(n_tests) # True effects (small p-values) true_effect_indices = np.random.choice(n_tests, n_true_effects, replace=False) for idx in true_effect_indices: p_values[idx] = np.random.uniform(0.001, 0.01) # Null effects (uniform p-values) null_indices = np.setdiff1d(np.arange(n_tests), true_effect_indices) p_values[null_indices] = np.random.uniform(0.05, 1.0, len(null_indices)) # Add some borderline cases p_values[0] = 0.04 p_values[1] = 0.03 print("\nMultiple Comparison Correction") print(f" Number of tests: {n_tests}") print(f" True effects: {n_true_effects}") print(f" Uncorrected significant (p<0.05): {np.sum(p_values < 0.05)}") # FDR correction (less conservative) rejected_fdr, pvals_fdr = rtx.stats.fdr_correction(p_values, alpha=0.05) print(f"\n FDR (Benjamini-Hochberg) correction:") print(f" Rejected: {np.sum(rejected_fdr)}") print(f" Min corrected p-value: {np.min(pvals_fdr):.6f}") # Bonferroni correction (more conservative) rejected_bonf, pvals_bonf = rtx.stats.bonferroni_correction(p_values, alpha=0.05) print(f"\n Bonferroni correction:") print(f" Rejected: {np.sum(rejected_bonf)}") print(f" Min corrected p-value: {np.min(pvals_bonf):.6f}") return rejected_fdr, rejected_bonf # Example 6: Realistic neuroimaging workflow def neuroimaging_workflow_example(): """ Complete workflow: Load data, compute statistics, correct for multiple comparisons. """ print("\n" + "=" * 50) print("Complete Neuroimaging Statistics Workflow") print("=" * 50) # Simulate epoched data: 20 subjects, 64 channels, 100 timepoints n_subjects = 20 n_channels = 64 n_timepoints = 100 # Condition A (baseline) condition_a = np.random.normal(0, 1, (n_subjects, n_channels, n_timepoints)) # Condition B (with effect in channels 10-15, timepoints 50-70) condition_b = condition_a.copy() condition_b[:, 10:15, 50:70] += np.random.normal(0.8, 0.3, (n_subjects, 5, 20)) print(f"\nData shape: {n_subjects} subjects x {n_channels} channels x {n_timepoints} timepoints") print(f"True effect: channels 10-15, timepoints 50-70") # Perform paired t-tests at each channel-timepoint p_values = np.zeros((n_channels, n_timepoints)) for ch in range(n_channels): for t in range(n_timepoints): # Get data for this channel-timepoint across subjects a = condition_a[:, ch, t] b = condition_b[:, ch, t] _, p = rtx.stats.ttest_rel(a, b) p_values[ch, t] = p # Flatten for correction p_flat = p_values.flatten() # Apply FDR correction rejected, _ = rtx.stats.fdr_correction(p_flat, alpha=0.05) rejected_2d = rejected.reshape(n_channels, n_timepoints) # Count discoveries n_significant = np.sum(rejected) n_true_region = 5 * 20 # channels 10-15, timepoints 50-70 # Check true positive region true_positives = np.sum(rejected_2d[10:15, 50:70]) false_positives = n_significant - true_positives print(f"\nResults after FDR correction:") print(f" Total significant: {n_significant}") print(f" True positives (in effect region): {true_positives}") print(f" False positives: {false_positives}") print(f" Sensitivity: {true_positives / n_true_region:.2%}") return p_values, rejected_2d if __name__ == "__main__": print("RTX-Neuro Statistical Analysis Examples") print("=" * 50) # Run all examples ttest_1samp_example() ttest_ind_example() ttest_rel_example() permutation_test_example() multiple_comparison_example() neuroimaging_workflow_example() print("\n" + "=" * 50) print("All examples completed successfully!")