{"id":34029145,"url":"https://github.com/sipemu/anofox-statistics-rs","last_synced_at":"2026-01-13T15:01:18.053Z","repository":{"id":328039016,"uuid":"1112365200","full_name":"sipemu/anofox-statistics-rs","owner":"sipemu","description":"Statistical tests in Rust","archived":false,"fork":false,"pushed_at":"2025-12-17T22:16:49.000Z","size":468,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-21T08:47:04.283Z","etag":null,"topics":["r","rust","rust-lang","statistical-testing","statistical-tests","statistics"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sipemu.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-08T14:22:46.000Z","updated_at":"2025-12-17T22:15:10.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sipemu/anofox-statistics-rs","commit_stats":null,"previous_names":["sipemu/anofox-statistics-rs"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/sipemu/anofox-statistics-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sipemu%2Fanofox-statistics-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sipemu%2Fanofox-statistics-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sipemu%2Fanofox-statistics-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sipemu%2Fanofox-statistics-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sipemu","download_url":"https://codeload.github.com/sipemu/anofox-statistics-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sipemu%2Fanofox-statistics-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28389198,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T14:36:09.778Z","status":"ssl_error","status_checked_at":"2026-01-13T14:35:19.697Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["r","rust","rust-lang","statistical-testing","statistical-tests","statistics"],"created_at":"2025-12-13T17:27:59.384Z","updated_at":"2026-01-13T15:01:18.044Z","avatar_url":"https://github.com/sipemu.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# anofox-statistics\n\n[![CI](https://github.com/sipemu/anofox-statistics-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/sipemu/anofox-statistics-rs/actions/workflows/ci.yml)\n[![Crates.io](https://img.shields.io/crates/v/anofox-statistics.svg)](https://crates.io/crates/anofox-statistics)\n[![Documentation](https://docs.rs/anofox-statistics/badge.svg)](https://docs.rs/anofox-statistics)\n[![codecov](https://codecov.io/gh/sipemu/anofox-statistics-rs/branch/main/graph/badge.svg)](https://codecov.io/gh/sipemu/stattests-rs)\n[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)\n[![Code Health](https://img.shields.io/badge/code%20health-85%25-brightgreen)](.)\n\nA statistical hypothesis testing library for Rust, validated against R ([VALIDATION](R/VALIDATION.md)).\n\nThis library provides a wide range of statistical tests commonly used in data analysis, all validated against R's implementations to ensure numerical accuracy.\n\n## Features\n\n- **Math Primitives**\n  - Mean, variance, standard deviation, median\n  - Numerically stable mean and variance (Welford's algorithm)\n  - Trimmed mean (robust to outliers)\n  - Skewness and kurtosis (Fisher's definition, matching R's e1071)\n\n- **Parametric Tests**\n  - T-tests (Welch, Student, Paired) with all alternatives\n  - Yuen's test (robust t-test using trimmed means)\n  - Brown-Forsythe test (homogeneity of variances)\n  - One-way ANOVA (Fisher's and Welch's)\n  - Two-way ANOVA (factorial design with Type III SS)\n  - Repeated measures ANOVA (with Mauchly's sphericity test and GG/HF corrections)\n\n- **Nonparametric Tests**\n  - Ranking with average tie handling\n  - Mann-Whitney U test (Wilcoxon rank-sum)\n  - Wilcoxon signed-rank test (paired)\n  - Kruskal-Wallis test (k-sample)\n  - Brunner-Munzel test (robust rank-based test for stochastic equality)\n\n- **Distributional Tests**\n  - Shapiro-Wilk normality test (Royston AS R94)\n  - D'Agostino's K-squared test (omnibus normality test using skewness and kurtosis)\n\n- **Correlation Analysis**\n  - Pearson's product-moment correlation with CI\n  - Spearman's rank correlation\n  - Kendall's tau (tau-a, tau-b, tau-c variants)\n  - Partial and semi-partial correlation\n  - Distance correlation (detects non-linear dependence)\n  - Intraclass correlation coefficient (ICC, 6 variants)\n\n- **Categorical Data Analysis**\n  - Chi-square test (independence and goodness-of-fit)\n  - Fisher's exact test for 2x2 tables\n  - G-test (log-likelihood ratio)\n  - McNemar's test (standard and exact)\n  - Effect sizes: Cramér's V, phi coefficient, contingency coefficient\n  - Cohen's kappa (unweighted and weighted)\n  - Proportion tests (one-sample and two-sample)\n  - Exact binomial test\n\n- **Resampling Methods**\n  - Permutation engine with custom statistics\n  - Permutation t-test\n  - Stationary bootstrap (for dependent data)\n  - Circular block bootstrap\n\n- **Modern Distribution Tests**\n  - Energy distance test (univariate and multivariate)\n  - Maximum Mean Discrepancy (MMD) with multiple kernels (Gaussian, Linear, Polynomial, Laplacian)\n\n- **Forecast Evaluation**\n  - Diebold-Mariano test for comparing predictive accuracy\n  - Clark-West test for nested model comparison\n  - Superior Predictive Ability (SPA) test for multiple model comparison\n  - MSPE-Adjusted SPA test for multiple nested models (Clark-West + bootstrap)\n  - Model Confidence Set (Hansen, Lunde, \u0026 Nason, 2011)\n\n- **Equivalence Testing (TOST)**\n  - TOST for means: one-sample, two-sample, and paired t-tests\n  - TOST for correlations (Pearson and Spearman)\n  - TOST for proportions (one-sample and two-sample)\n  - Wilcoxon TOST (non-parametric equivalence)\n  - Bootstrap TOST (resampling-based)\n  - Yuen TOST (robust trimmed means)\n\n## Installation\n\nAdd to your `Cargo.toml`:\n\n```toml\n[dependencies]\nanofox-statistics = \"0.2\"\n```\n\n## Examples\n\nThe library includes runnable examples demonstrating each major feature:\n\n```bash\ncargo run --example quickstart      # Overview: t-test, Mann-Whitney, Shapiro-Wilk, permutation test\ncargo run --example parametric      # T-tests, Yuen's robust test, Brown-Forsythe\ncargo run --example nonparametric   # Ranking, Mann-Whitney, Wilcoxon, Kruskal-Wallis, Brunner-Munzel\ncargo run --example normality       # Shapiro-Wilk, D'Agostino's K-squared\ncargo run --example resampling      # Permutation tests, bootstrap methods\ncargo run --example modern          # Energy distance, MMD with different kernels\ncargo run --example forecast        # Diebold-Mariano, Clark-West, SPA, MCS\ncargo run --example correlation     # Pearson, Spearman, Kendall, partial, distance, ICC\ncargo run --example categorical     # Chi-square, Fisher, McNemar, Cramér's V, kappa\n```\n\n## Quick Start\n\n### T-Tests\n\n```rust\nuse anofox_statistics::{t_test, TTestKind, Alternative};\n\nlet group1 = vec![1.2, 2.3, 3.4, 4.5, 5.6];\nlet group2 = vec![2.1, 3.2, 4.3, 5.4, 6.5];\n\n// Welch t-test (unequal variances), mu=0.0 tests if mean difference equals zero\nlet result = t_test(\u0026group1, \u0026group2, TTestKind::Welch, Alternative::TwoSided, 0.0, None)\n    .expect(\"t-test should succeed\");\n\nprintln!(\"t-statistic: {:.4}\", result.statistic);\nprintln!(\"p-value: {:.4}\", result.p_value);\nprintln!(\"degrees of freedom: {:.4}\", result.df);\n\n// Student t-test (equal variances assumed)\nlet result = t_test(\u0026group1, \u0026group2, TTestKind::Student, Alternative::TwoSided, 0.0, None)?;\n\n// Paired t-test\nlet result = t_test(\u0026group1, \u0026group2, TTestKind::Paired, Alternative::Less, 0.0, None)?;\n\n// Test if mean difference equals 0.5 (non-zero null hypothesis)\nlet result = t_test(\u0026group1, \u0026group2, TTestKind::Welch, Alternative::TwoSided, 0.5, None)?;\n\n// T-test with 95% confidence interval\nlet result = t_test(\u0026group1, \u0026group2, TTestKind::Welch, Alternative::TwoSided, 0.0, Some(0.95))?;\nif let Some(ci) = result.conf_int {\n    println!(\"95% CI: [{:.3}, {:.3}]\", ci.lower, ci.upper);\n}\n```\n\n### Yuen's Robust T-Test\n\n```rust\nuse anofox_statistics::{yuen_test, Alternative};\n\n// 20% trimmed means (robust to outliers)\nlet result = yuen_test(\u0026group1, \u0026group2, 0.2, Alternative::TwoSided)?;\n\nprintln!(\"Test statistic: {:.4}\", result.statistic);\nprintln!(\"p-value: {:.4}\", result.p_value);\n```\n\n### Brown-Forsythe Test\n\n```rust\nuse anofox_statistics::brown_forsythe;\n\nlet groups = vec![\n    vec![1.0, 2.0, 3.0],\n    vec![4.0, 5.0, 6.0],\n    vec![7.0, 8.0, 9.0],\n];\n\nlet result = brown_forsythe(\u0026groups)?;\n\nprintln!(\"F-statistic: {:.4}\", result.statistic);\nprintln!(\"p-value: {:.4}\", result.p_value);\n```\n\n### One-Way ANOVA\n\n```rust\nuse anofox_statistics::{one_way_anova, AnovaKind};\n\nlet group1 = vec![1.0, 2.0, 3.0, 4.0, 5.0];\nlet group2 = vec![2.0, 3.0, 4.0, 5.0, 6.0];\nlet group3 = vec![3.0, 4.0, 5.0, 6.0, 7.0];\nlet groups: Vec\u003c\u0026[f64]\u003e = vec![\u0026group1, \u0026group2, \u0026group3];\n\n// Fisher's ANOVA (assumes equal variances)\nlet result = one_way_anova(\u0026groups, AnovaKind::Fisher)?;\nprintln!(\"F-statistic: {:.4}\", result.statistic);\nprintln!(\"p-value: {:.4}\", result.p_value);\nprintln!(\"Group means: {:?}\", result.group_means);\n\n// Welch's ANOVA (robust to unequal variances)\nlet result = one_way_anova(\u0026groups, AnovaKind::Welch)?;\n```\n\n### Two-Way ANOVA\n\n```rust\nuse anofox_statistics::two_way_anova;\n\n// Values with factor level arrays (long format)\nlet values = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];\nlet factor_a = vec![0, 0, 0, 0, 1, 1, 1, 1];  // 2 levels\nlet factor_b = vec![0, 0, 1, 1, 0, 0, 1, 1];  // 2 levels\n\nlet result = two_way_anova(\u0026values, \u0026factor_a, \u0026factor_b)?;\n\nprintln!(\"Factor A: F={:.4}, p={:.4}\", result.factor_a.f_statistic.unwrap(), result.factor_a.p_value.unwrap());\nprintln!(\"Factor B: F={:.4}, p={:.4}\", result.factor_b.f_statistic.unwrap(), result.factor_b.p_value.unwrap());\nprintln!(\"Interaction: F={:.4}, p={:.4}\", result.interaction.f_statistic.unwrap(), result.interaction.p_value.unwrap());\n```\n\n### Repeated Measures ANOVA\n\n```rust\nuse anofox_statistics::repeated_measures_anova;\n\n// Matrix format: rows = subjects, columns = conditions\nlet subject1 = vec![1.0, 2.0, 3.0];\nlet subject2 = vec![2.0, 3.0, 4.0];\nlet subject3 = vec![1.5, 2.5, 3.5];\nlet data: Vec\u003c\u0026[f64]\u003e = vec![\u0026subject1, \u0026subject2, \u0026subject3];\n\nlet result = repeated_measures_anova(\u0026data, true)?;  // compute sphericity\n\nprintln!(\"F-statistic: {:.4}\", result.within_subjects.f_statistic.unwrap());\nprintln!(\"p-value: {:.4}\", result.within_subjects.p_value.unwrap());\nprintln!(\"Condition means: {:?}\", result.condition_means);\n\n// Sphericity test (Mauchly's W) - only for k \u003e= 3 conditions\nif let Some(sphericity) = \u0026result.sphericity {\n    println!(\"Mauchly's W: {:.4}, p={:.4}\", sphericity.w, sphericity.p_value);\n}\n\n// Greenhouse-Geisser corrected p-value\nif let Some(gg) = \u0026result.greenhouse_geisser {\n    println!(\"GG epsilon: {:.4}, corrected p={:.4}\", gg.epsilon, gg.p_value);\n}\n```\n\n### Nonparametric Tests\n\n```rust\nuse anofox_statistics::{mann_whitney_u, wilcoxon_signed_rank, kruskal_wallis, rank, brunner_munzel, Alternative};\n\n// Ranking\nlet data = vec![3.0, 1.0, 4.0, 1.0, 5.0];\nlet ranks = rank(\u0026data)?;\n\n// Mann-Whitney U test (two-sided, no continuity correction, normal approximation)\nlet result = mann_whitney_u(\u0026group1, \u0026group2, Alternative::TwoSided, false, false, None, None)?;\n\n// With exact p-values (for small samples without ties)\nlet result = mann_whitney_u(\u0026group1, \u0026group2, Alternative::TwoSided, false, true, None, None)?;\n\n// With confidence interval (Hodges-Lehmann estimate)\nlet result = mann_whitney_u(\u0026group1, \u0026group2, Alternative::TwoSided, false, true, Some(0.95), None)?;\nif let Some(ci) = result.conf_int {\n    println!(\"95% CI: [{:.3}, {:.3}]\", ci.lower, ci.upper);\n}\n\n// Test if location shift equals 0.5 (non-zero null hypothesis)\nlet result = mann_whitney_u(\u0026group1, \u0026group2, Alternative::TwoSided, false, false, None, Some(0.5))?;\n\n// Wilcoxon signed-rank test (paired)\nlet result = wilcoxon_signed_rank(\u0026group1, \u0026group2, Alternative::TwoSided, false, false, None, None)?;\n\n// Wilcoxon with non-zero null hypothesis (test if median difference equals 0.5)\nlet result = wilcoxon_signed_rank(\u0026group1, \u0026group2, Alternative::TwoSided, false, false, None, Some(0.5))?;\n\n// Kruskal-Wallis test\nlet result = kruskal_wallis(\u0026groups)?;\n\n// Brunner-Munzel test (robust alternative to Mann-Whitney)\nlet result = brunner_munzel(\u0026group1, \u0026group2, Alternative::TwoSided, None)?;\nprintln!(\"Estimate P(X \u003c Y): {:.4}\", result.estimate);\n\n// Brunner-Munzel with 95% confidence interval\nlet result = brunner_munzel(\u0026group1, \u0026group2, Alternative::TwoSided, Some(0.05))?;\nif let Some(ci) = result.conf_int {\n    println!(\"95% CI for P(X \u003c Y): [{:.3}, {:.3}]\", ci.lower, ci.upper);\n}\n```\n\n### Normality Tests\n\n```rust\nuse anofox_statistics::{shapiro_wilk, dagostino_k_squared};\n\nlet data = vec![1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8];\n\n// Shapiro-Wilk test\nlet result = shapiro_wilk(\u0026data)?;\nprintln!(\"W statistic: {:.4}\", result.statistic);\nprintln!(\"p-value: {:.4}\", result.p_value);\n\n// D'Agostino's K-squared test (omnibus test using skewness and kurtosis)\nlet result = dagostino_k_squared(\u0026data)?;\nprintln!(\"K-squared: {:.4}\", result.statistic);\nprintln!(\"p-value: {:.4}\", result.p_value);\n```\n\n### Resampling Methods\n\n```rust\nuse anofox_statistics::resampling::{permutation_t_test, StationaryBootstrap, CircularBlockBootstrap};\n\n// Permutation t-test\nlet result = permutation_t_test(\u0026group1, \u0026group2, 10000, Some(42))?;\nprintln!(\"p-value: {:.4}\", result.p_value);\n\n// Stationary bootstrap for time series\nlet bootstrap = StationaryBootstrap::new(\u0026time_series, 10.0, Some(42))?;\nlet samples: Vec\u003cVec\u003cf64\u003e\u003e = bootstrap.take(1000).collect();\n\n// Circular block bootstrap\nlet bootstrap = CircularBlockBootstrap::new(\u0026time_series, 5, Some(42))?;\n```\n\n### Modern Distribution Tests\n\n```rust\nuse anofox_statistics::modern::{energy_distance_test, mmd_test, Kernel};\n\n// Energy distance test\nlet result = energy_distance_test(\u0026sample1, \u0026sample2, 1000, Some(42))?;\nprintln!(\"Energy distance: {:.4}\", result.statistic);\nprintln!(\"p-value: {:.4}\", result.p_value);\n\n// Maximum Mean Discrepancy with Gaussian kernel\nlet result = mmd_test(\u0026sample1, \u0026sample2, Kernel::Gaussian(1.0), 1000, Some(42))?;\nprintln!(\"MMD: {:.4}\", result.statistic);\nprintln!(\"p-value: {:.4}\", result.p_value);\n\n// MMD with automatic bandwidth selection\nlet result = mmd_test(\u0026sample1, \u0026sample2, Kernel::GaussianMedian, 1000, Some(42))?;\n```\n\n### Correlation Analysis\n\n```rust\nuse anofox_statistics::{pearson, spearman, kendall, partial_cor, distance_cor, icc,\n                        KendallVariant, ICCType};\n\nlet x = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];\nlet y = vec![2.1, 3.9, 6.1, 7.9, 10.1, 11.9, 14.1, 15.9, 18.1, 19.9];\n\n// Pearson correlation with 95% CI\nlet result = pearson(\u0026x, \u0026y, Some(0.95))?;\nprintln!(\"Pearson r = {:.4}, p = {:.4}\", result.estimate, result.p_value);\n\n// Spearman rank correlation\nlet result = spearman(\u0026x, \u0026y, None)?;\nprintln!(\"Spearman rho = {:.4}\", result.estimate);\n\n// Kendall's tau-b (default, matches R)\nlet result = kendall(\u0026x, \u0026y, KendallVariant::TauB)?;\nprintln!(\"Kendall tau = {:.4}\", result.estimate);\n\n// Partial correlation (controlling for z)\nlet z = vec![1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5];\nlet result = partial_cor(\u0026x, \u0026y, \u0026[\u0026z])?;\nprintln!(\"Partial r = {:.4}\", result.estimate);\n\n// Distance correlation (detects non-linear dependence)\nlet result = distance_cor(\u0026x, \u0026y)?;\nprintln!(\"Distance correlation = {:.4}\", result.dcor);\n\n// ICC for inter-rater reliability\nlet ratings = vec![\n    vec![9.0, 2.0, 5.0, 8.0],\n    vec![6.0, 1.0, 3.0, 2.0],\n    vec![8.0, 4.0, 6.0, 8.0],\n];\nlet result = icc(\u0026ratings, ICCType::ICC2)?;\nprintln!(\"ICC(2,1) = {:.4}\", result.icc);\n```\n\n### Categorical Data Analysis\n\n```rust\nuse anofox_statistics::{chisq_test, chisq_goodness_of_fit, fisher_exact, mcnemar_test,\n                        cramers_v, phi_coefficient, cohen_kappa, binom_test, Alternative};\n\n// Chi-square test of independence\nlet observed = vec![\n    vec![10, 20, 30],\n    vec![15, 25, 35],\n];\nlet result = chisq_test(\u0026observed, false)?;\nprintln!(\"Chi-square = {:.4}, p = {:.4}\", result.statistic, result.p_value);\n\n// Chi-square goodness-of-fit (test if die is fair)\nlet rolls = vec![16, 18, 14, 17, 15, 20];\nlet result = chisq_goodness_of_fit(\u0026rolls, None)?;\nprintln!(\"Chi-square = {:.4}, p = {:.4}\", result.statistic, result.p_value);\n\n// Fisher's exact test for 2x2 tables\nlet table = [[3, 1], [1, 3]];\nlet result = fisher_exact(\u0026table, Alternative::TwoSided)?;\nprintln!(\"p-value = {:.4}, odds ratio = {:.4}\", result.p_value, result.odds_ratio);\n\n// McNemar's test for paired data\nlet before_after = [[10, 20], [5, 65]];\nlet result = mcnemar_test(\u0026before_after, false)?;\nprintln!(\"Chi-square = {:.4}, p = {:.4}\", result.statistic, result.p_value);\n\n// Effect sizes\nlet result = cramers_v(\u0026observed)?;\nprintln!(\"Cramér's V = {:.4}\", result.estimate);\n\nlet result = phi_coefficient(\u0026table)?;\nprintln!(\"Phi = {:.4}\", result.estimate);\n\n// Cohen's kappa for inter-rater agreement\nlet confusion = vec![\n    vec![20, 5, 0],\n    vec![10, 30, 5],\n    vec![0, 5, 25],\n];\nlet result = cohen_kappa(\u0026confusion, false)?;\nprintln!(\"Kappa = {:.4}, p = {:.4}\", result.kappa, result.p_value);\n\n// Exact binomial test\nlet result = binom_test(7, 10, 0.5, Alternative::TwoSided)?;\nprintln!(\"p-value = {:.4}\", result.p_value);\n```\n\n### Forecast Evaluation\n\n```rust\nuse anofox_statistics::{diebold_mariano, clark_west, spa_test, mspe_adjusted_spa,\n                        model_confidence_set, LossFunction, MCSStatistic, Alternative};\n\n// Forecast errors from two competing models\nlet errors_model1 = vec![0.1, -0.2, 0.3, -0.1, 0.2];\nlet errors_model2 = vec![0.2, -0.3, 0.4, -0.2, 0.3];\n\n// Diebold-Mariano test (two-sided)\nlet result = diebold_mariano(\u0026errors_model1, \u0026errors_model2, LossFunction::SquaredError, 1, Alternative::TwoSided)?;\nprintln!(\"DM statistic: {:.4}\", result.statistic);\nprintln!(\"p-value: {:.4}\", result.p_value);\n\n// Clark-West test for nested models (e.g., AR(1) vs AR(2))\nlet restricted_errors = vec![0.3, -0.2, 0.4, -0.3, 0.2];   // Benchmark/restricted model\nlet unrestricted_errors = vec![0.2, -0.1, 0.3, -0.2, 0.1]; // Alternative/unrestricted model\nlet result = clark_west(\u0026restricted_errors, \u0026unrestricted_errors, 1)?;\nprintln!(\"CW statistic: {:.4}\", result.statistic);\nprintln!(\"p-value (one-sided): {:.4}\", result.p_value);\n\n// Superior Predictive Ability test (compare benchmark vs multiple models)\nlet benchmark_losses = vec![0.5, 0.6, 0.4, 0.7, 0.5];\nlet model_losses = vec![\n    vec![0.4, 0.5, 0.3, 0.6, 0.4],  // Model 1\n    vec![0.6, 0.7, 0.5, 0.8, 0.6],  // Model 2\n];\nlet result = spa_test(\u0026benchmark_losses, \u0026model_losses, 1000, 10.0, Some(42))?;\nprintln!(\"SPA statistic: {:.4}\", result.statistic);\nprintln!(\"p-value: {:.4}\", result.p_value_consistent);\n\n// MSPE-Adjusted SPA for multiple nested models\n// Combines Clark-West adjustment with bootstrap for multiple testing\nlet benchmark_errors = vec![0.5, 0.4, 0.6, 0.3, 0.5];\nlet nested_model_errors = vec![\n    vec![0.4, 0.3, 0.5, 0.2, 0.4],  // Nested model 1\n    vec![0.3, 0.2, 0.4, 0.1, 0.3],  // Nested model 2\n];\nlet result = mspe_adjusted_spa(\u0026benchmark_errors, \u0026nested_model_errors, 1000, 5.0, Some(42))?;\nprintln!(\"Best model: {:?}\", result.best_model_idx);\nprintln!(\"p-value (adjusted): {:.4}\", result.p_value_consistent);\n\n// Model Confidence Set - identify the set of best models\nlet losses = vec![\n    vec![0.5, 0.6, 0.4, 0.7, 0.5],  // Model 0\n    vec![0.4, 0.5, 0.3, 0.6, 0.4],  // Model 1\n    vec![0.8, 0.9, 0.7, 1.0, 0.8],  // Model 2 (worst)\n];\nlet result = model_confidence_set(\u0026losses, 0.10, MCSStatistic::Range, 1000, 5.0, Some(42))?;\nprintln!(\"Models in MCS: {:?}\", result.included_models);\nprintln!(\"Eliminated: {:?}\", result.eliminated_models);\n```\n\n### Equivalence Testing (TOST)\n\nTOST (Two One-Sided Tests) tests whether an effect is small enough to be considered practically equivalent to zero, rather than just testing if it differs from zero.\n\n```rust\nuse anofox_statistics::{tost_t_test_two_sample, tost_correlation, tost_yuen,\n                        EquivalenceBounds, CorrelationTostMethod};\n\nlet group1 = vec![10.1, 10.0, 9.9, 10.2, 10.0, 9.8, 10.1, 10.0];\nlet group2 = vec![10.0, 10.1, 9.9, 10.0, 10.2, 9.9, 10.0, 10.1];\n\n// Two-sample TOST: test if mean difference is within ±0.5\nlet bounds = EquivalenceBounds::Symmetric { delta: 0.5 };\nlet result = tost_t_test_two_sample(\u0026group1, \u0026group2, \u0026bounds, 0.05, false)?;\nprintln!(\"Equivalent: {}\", result.equivalent);\nprintln!(\"TOST p-value: {:.4}\", result.tost_p_value);\nprintln!(\"90% CI: [{:.4}, {:.4}]\", result.ci.0, result.ci.1);\n\n// Using Cohen's d effect size bounds (±0.5 SD)\nlet bounds = EquivalenceBounds::CohenD { d: 0.5 };\nlet result = tost_t_test_two_sample(\u0026group1, \u0026group2, \u0026bounds, 0.05, false)?;\n\n// Correlation TOST: test if correlation is equivalent to zero\nlet x = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];\nlet y = vec![5.1, 4.9, 5.0, 5.2, 4.8, 5.1, 4.9, 5.0, 5.1, 4.9];  // Near-zero correlation\nlet bounds = EquivalenceBounds::Symmetric { delta: 0.3 };\nlet result = tost_correlation(\u0026x, \u0026y, 0.0, \u0026bounds, 0.05, CorrelationTostMethod::Pearson)?;\n\n// Robust TOST using trimmed means (resistant to outliers)\nlet data_with_outlier = vec![10.0, 11.0, 12.0, 13.0, 14.0, 100.0];  // Outlier\nlet normal_data = vec![10.1, 11.1, 12.1, 13.1, 14.1, 15.1];\nlet bounds = EquivalenceBounds::Symmetric { delta: 2.0 };\nlet result = tost_yuen(\u0026data_with_outlier, \u0026normal_data, \u0026bounds, 0.05, 0.2)?;  // 20% trim\n```\n\n## Validation\n\nThis library is developed using Test-Driven Development (TDD) with R as the oracle (ground truth). All implementations are validated against R's statistical functions:\n\n| Rust Function | R Equivalent | Package |\n|---------------|--------------|---------|\n| `t_test()` | `t.test()` | stats |\n| `yuen_test()` | `yuen()` | WRS2 |\n| `brown_forsythe()` | `leveneTest(center=median)` | car |\n| `one_way_anova()` | `oneway.test()`, `aov()` | stats |\n| `two_way_anova()` | `Anova(type=\"III\")` | car |\n| `repeated_measures_anova()` | `ezANOVA()` | ez |\n| `mann_whitney_u()`, `wilcoxon_signed_rank()` | `wilcox.test()` | stats |\n| `kruskal_wallis()` | `kruskal.test()` | stats |\n| `brunner_munzel()` | `brunner.munzel.test()` | lawstat |\n| `shapiro_wilk()` | `shapiro.test()` | stats |\n| `dagostino_k_squared()` | `agostino.test()`, `anscombe.test()` | moments |\n| `skewness()`, `kurtosis()` | `skewness()`, `kurtosis()` | e1071 |\n| `diebold_mariano()` | `dm.test()` | forecast |\n| `pearson()`, `spearman()` | `cor.test()` | stats |\n| `kendall()` | `cor.test(method=\"kendall\")` | stats |\n| `partial_cor()`, `semi_partial_cor()` | `pcor.test()`, `spcor.test()` | ppcor |\n| `distance_cor()` | `dcor()` | energy |\n| `icc()` | `ICC()` | psych |\n| `chisq_test()` | `chisq.test()` | stats |\n| `chisq_goodness_of_fit()` | `chisq.test(p=...)` | stats |\n| `fisher_exact()` | `fisher.test()` | stats |\n| `g_test()` | `GTest()` | DescTools |\n| `mcnemar_test()` | `mcnemar.test()` | stats |\n| `cramers_v()` | `CramerV()` | DescTools |\n| `phi_coefficient()` | `phi()` | psych |\n| `cohen_kappa()` | `cohen.kappa()` | psych |\n| `binom_test()` | `binom.test()` | stats |\n| `prop_test_one()`, `prop_test_two()` | `prop.test()` | stats |\n| `tost_t_test_*()` | `TOSTone()`, `TOSTtwo()`, `TOSTpaired()` | TOSTER |\n| `tost_correlation()` | `TOSTr()` | TOSTER |\n| `tost_prop_*()` | `TOSTtwo.prop()` | TOSTER |\n| `tost_wilcoxon_*()` | `wilcox_TOST()` | TOSTER |\n| `tost_bootstrap()` | `boot_t_TOST()` | TOSTER |\n| `tost_yuen()` | `yuen.TOST()` | WRS2 |\n\nAll 303 test cases ensure numerical agreement with R within appropriate tolerances (typically 1e-10, with documented exceptions for algorithm-dependent tests like Shapiro-Wilk).\n\n**For complete transparency on the validation process, see [`R/VALIDATION.md`](R/VALIDATION.md)**, which documents:\n- All 76 reference data files and their R generation code\n- Tolerance rationale for each test category\n- Step-by-step reproduction instructions\n- R package dependencies\n\n## Dependencies\n\n- [statrs](https://crates.io/crates/statrs) - Statistical distributions\n- [thiserror](https://crates.io/crates/thiserror) - Error handling\n- [rand](https://crates.io/crates/rand) - Random number generation for resampling\n\n## Attribution\n\nThis library incorporates Rust implementations of algorithms from several open-source projects. See [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for complete attribution and license information.\n\n- **statrs** (MIT) - Statistical distributions\n- **rand** (MIT/Apache-2.0) - Random number generation\n- **R Statistical Computing** - Algorithm validation and methodology\n\n## License\n\nMIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsipemu%2Fanofox-statistics-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsipemu%2Fanofox-statistics-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsipemu%2Fanofox-statistics-rs/lists"}