mod association;
mod chisq;
mod fisher;
mod mcnemar;
mod proportions;
pub use association::{
cohen_kappa, contingency_coef, cramers_v, phi_coefficient, AssociationResult, KappaResult,
};
pub use chisq::{chisq_goodness_of_fit, chisq_test, g_test, ChiSquareResult};
pub use fisher::{fisher_exact, FisherResult};
pub use mcnemar::{mcnemar_exact, mcnemar_test, McNemarkExactResult, McNemarkResult};
pub use proportions::{binom_test, prop_test_one, prop_test_two, BinomTestResult, PropTestResult};
pub use crate::parametric::Alternative;
use crate::error::{Result, StatError};
pub(crate) fn validate_contingency_table(observed: &[Vec<usize>]) -> Result<(usize, usize)> {
if observed.is_empty() {
return Err(StatError::EmptyData);
}
let n_rows = observed.len();
let n_cols = observed[0].len();
if n_cols == 0 {
return Err(StatError::EmptyData);
}
for (i, row) in observed.iter().enumerate() {
if row.len() != n_cols {
return Err(StatError::InvalidParameter(format!(
"Row {} has {} columns, expected {}",
i,
row.len(),
n_cols
)));
}
}
Ok((n_rows, n_cols))
}
pub(crate) fn validate_2x2_table(table: &[[usize; 2]; 2]) -> Result<()> {
let total: usize = table.iter().map(|row| row.iter().sum::<usize>()).sum();
if total == 0 {
return Err(StatError::EmptyData);
}
Ok(())
}
pub(crate) fn marginals(observed: &[Vec<usize>]) -> (Vec<usize>, Vec<usize>, usize) {
let n_cols = observed[0].len();
let row_totals: Vec<usize> = observed.iter().map(|row| row.iter().sum()).collect();
let col_totals: Vec<usize> = (0..n_cols)
.map(|j| observed.iter().map(|row| row[j]).sum())
.collect();
let total: usize = row_totals.iter().sum();
(row_totals, col_totals, total)
}
pub(crate) fn expected_frequencies(observed: &[Vec<usize>]) -> Vec<Vec<f64>> {
let (row_totals, col_totals, total) = marginals(observed);
let n_rows = observed.len();
let n_cols = observed[0].len();
let total_f = total as f64;
let mut expected = vec![vec![0.0; n_cols]; n_rows];
for i in 0..n_rows {
for j in 0..n_cols {
expected[i][j] = (row_totals[i] as f64 * col_totals[j] as f64) / total_f;
}
}
expected
}