single_statistics/testing/
mod.rs1use std::collections::HashMap;
2
3pub mod inference;
4pub mod correction;
5pub mod effect;
6
7pub mod utils;
8
9#[derive(Debug, Clone, Copy)]
10pub enum TestMethod {
11 TTest(TTestType),
12 MannWhitney,
13 NegativeBinomial,
14 ZeroInflated,
15}
16
17#[derive(Debug, Clone, Copy)]
18pub enum TTestType {
19 Student, Welch, }
22
23#[derive(Debug, Clone, Copy)]
24pub enum Alternative {
25 TwoSided,
26 Less,
27 Greater,
28}
29
30#[derive(Debug, Clone)]
31pub struct TestResult {
32 pub statistic: f64,
34 pub p_value: f64,
36 pub confidence_interval: Option<(f64, f64)>,
38 pub degrees_of_freedom: Option<f64>,
40 pub effect_size: Option<f64>,
42 pub standard_error: Option<f64>,
44 pub metadata: HashMap<String, f64>,
46}
47
48impl TestResult {
49 pub fn new(statistic: f64, p_value: f64) -> Self {
51 TestResult {
52 statistic,
53 p_value,
54 confidence_interval: None,
55 degrees_of_freedom: None,
56 effect_size: None,
57 standard_error: None,
58 metadata: HashMap::new(),
59 }
60 }
61
62 pub fn with_effect_size(statistic: f64, p_value: f64, effect_size: f64) -> Self {
64 TestResult {
65 statistic,
66 p_value,
67 confidence_interval: None,
68 degrees_of_freedom: None,
69 effect_size: Some(effect_size),
70 standard_error: None,
71 metadata: HashMap::new(),
72 }
73 }
74
75 pub fn with_confidence_interval(mut self, lower: f64, upper: f64) -> Self {
77 self.confidence_interval = Some((lower, upper));
78 self
79 }
80
81 pub fn with_degrees_of_freedom(mut self, df: f64) -> Self {
83 self.degrees_of_freedom = Some(df);
84 self
85 }
86
87 pub fn with_standard_error(mut self, se: f64) -> Self {
89 self.standard_error = Some(se);
90 self
91 }
92
93 pub fn with_metadata(mut self, key: &str, value: f64) -> Self {
95 self.metadata.insert(key.to_string(), value);
96 self
97 }
98
99 pub fn is_significant(&self, alpha: f64) -> bool {
101 self.p_value < alpha
102 }
103}
104
105#[derive(Debug, Clone)]
106pub struct MultipleTestResults {
107 pub statistics: Vec<f64>,
109 pub p_values: Vec<f64>,
111 pub adjusted_p_values: Option<Vec<f64>>,
113 pub effect_sizes: Option<Vec<f64>>,
115 pub confidence_intervals: Option<Vec<(f64, f64)>>,
117 pub feature_metadata: Option<Vec<HashMap<String, f64>>>,
119 pub global_metadata: HashMap<String, String>,
121}
122
123impl MultipleTestResults {
124 pub fn new(statistics: Vec<f64>, p_values: Vec<f64>) -> Self {
126 MultipleTestResults {
127 statistics,
128 p_values,
129 adjusted_p_values: None,
130 effect_sizes: None,
131 confidence_intervals: None,
132 feature_metadata: None,
133 global_metadata: HashMap::new(),
134 }
135 }
136
137 pub fn with_adjusted_p_values(mut self, adjusted_p_values: Vec<f64>) -> Self {
139 self.adjusted_p_values = Some(adjusted_p_values);
140 self
141 }
142
143 pub fn with_effect_sizes(mut self, effect_sizes: Vec<f64>) -> Self {
145 self.effect_sizes = Some(effect_sizes);
146 self
147 }
148
149 pub fn with_confidence_intervals(mut self, confidence_intervals: Vec<(f64, f64)>) -> Self {
151 self.confidence_intervals = Some(confidence_intervals);
152 self
153 }
154
155 pub fn with_global_metadata(mut self, key: &str, value: &str) -> Self {
157 self.global_metadata.insert(key.to_string(), value.to_string());
158 self
159 }
160
161 pub fn significant_indices(&self, alpha: f64) -> Vec<usize> {
163 match &self.adjusted_p_values {
164 Some(adj_p_values) => adj_p_values.iter()
165 .enumerate()
166 .filter_map(|(i, &p)| if p < alpha { Some(i) } else { None })
167 .collect(),
168 None => self.p_values.iter()
169 .enumerate()
170 .filter_map(|(i, &p)| if p < alpha { Some(i) } else { None })
171 .collect(),
172 }
173 }
174
175 pub fn num_significant(&self, alpha: f64) -> usize {
177 self.significant_indices(alpha).len()
178 }
179
180 pub fn top_features(&self, n: usize) -> Vec<usize> {
182 let p_values = match &self.adjusted_p_values {
183 Some(adj_p) => adj_p,
184 None => &self.p_values,
185 };
186
187 let mut indices: Vec<usize> = (0..p_values.len()).collect();
188 indices.sort_by(|&a, &b| p_values[a].partial_cmp(&p_values[b]).unwrap_or(std::cmp::Ordering::Equal));
189 indices.truncate(n);
190 indices
191 }
192}