1use crate::probability::CDHResult;
2use std::collections::HashMap;
3
4
5pub struct DataSet<T>(pub Vec<T>);
8
9impl DataSet<f64> {
10 pub fn new(data: Vec<f64>) -> Self {
18 DataSet(data)
19 }
20
21 pub fn mean(&self) -> CDHResult<f64> {
25 let len = self.0.len() as f64;
26 if len == 0.0 {
27 return Err("Cannot compute mean of an empty dataset.".to_string());
28 }
29 Ok(self.0.iter().sum::<f64>() / len)
30 }
31
32 pub fn median(&self) -> CDHResult<f64> {
35 let len = self.0.len();
36 if len == 0 {
37 return Err("Cannot compute median of an empty dataset.".to_string());
38 }
39 let mut sorted_arr = self.0.clone();
40 sorted_arr.sort_by(|a, b| a.total_cmp(b));
41
42 match len {
43 a if a % 2 == 1 => Ok(sorted_arr[(a + 1) / 2 - 1]),
44 _ => {
45 let center = len / 2;
46 let center_elem = sorted_arr[center - 1];
47 let next_elem = sorted_arr[center];
48 Ok((center_elem + next_elem) / 2.0)
49 }
50 }
51 }
52
53 pub fn mode(&self) -> CDHResult<Option<f64>> {
59 if self.0.is_empty() {
60 return Err("Cannot compute mode of an empty dataset.".to_string());
61 }
62
63 let mut frequencies: HashMap<u64, usize> = HashMap::with_capacity(self.0.len());
64 let mut max_count = 0;
65
66 for &num in &self.0 {
68 let bits = num.to_bits();
69 let count = frequencies.entry(bits).or_insert(0);
70 *count += 1;
71 if *count > max_count {
72 max_count = *count;
73 }
74 }
75
76 let modes: Vec<u64> = frequencies
78 .iter()
79 .filter(|&(_, &count)| count == max_count)
80 .map(|(&bits, _)| bits)
81 .collect();
82
83 if modes.len() == frequencies.len() && max_count == 1 {
85 return Ok(None);
86 }
87
88 if modes.len() > 1 {
90 Ok(None)
91 } else {
92 Ok(Some(f64::from_bits(modes[0])))
93 }
94 }
95
96 pub fn range(&self) -> CDHResult<f64> {
100 if self.0.is_empty() {
101 return Err("Cannot compute range of an empty dataset.".to_string());
102 }
103 Ok(self.max()? - self.min()?)
104 }
105
106 pub fn has(&self, value: f64, other: Option<&[f64]>) -> CDHResult<bool> {
111 let set = match other {
112 None => &self.0,
113 Some(slice) => slice,
114 };
115 Ok(set.iter().any(|&v| v == value))
116 }
117
118 pub fn sample_variation_x2(&self) -> CDHResult<f64> {
122 let n = self.0.len() as f64;
123 if n == 0.0 { return Err("Empty dataset context.".to_string()); }
124 let xsqrsum = self.0.iter().fold(0.0, |acc, b| acc + b.powi(2));
125 let xsum = self.0.iter().sum::<f64>();
126 Ok(xsqrsum - xsum.powi(2) / n)
127 }
128
129 pub fn sample_variation_y2(&self, y: &[f64]) -> CDHResult<f64> {
133 let n = y.len() as f64;
134 if n == 0.0 { return Err("Input slice cannot be empty.".to_string()); }
135 let ysqrsum = y.iter().fold(0.0, |acc, b| acc + b.powi(2));
136 let ysum = y.iter().sum::<f64>();
137 Ok(ysqrsum - ysum.powi(2) / n)
138 }
139
140 pub fn sample_variance(&self) -> CDHResult<f64> {
144 let len = self.0.len();
145 if len <= 1 {
146 return Err("Sample variance requires at least 2 data points.".to_string());
147 }
148 Ok(self.sample_variation_x2()? / ((len - 1) as f64))
149 }
150
151 pub fn sample_std_deviation(&self) -> CDHResult<f64> {
153 Ok(self.sample_variance()?.sqrt())
154 }
155
156 pub fn sample_coeff_of_variation(&self) -> CDHResult<f64> {
160 let mean = self.mean()?;
161 if mean == 0.0 {
162 return Err("Coefficient of variation undefined for a zero mean.".to_string());
163 }
164 Ok(self.sample_std_deviation()? / mean)
165 }
166
167 pub fn kth_central_moment(&self, k: f64) -> CDHResult<f64> {
171 let n = self.0.len() as f64;
172 if n == 0.0 { return Err("Empty dataset context.".to_string()); }
173 let mean = self.mean()?;
174 Ok(self.0.iter().fold(0.0, |acc, b| acc + (b - mean).powf(k)) / n)
175 }
176
177 pub fn skewness(&self) -> CDHResult<f64> {
179 let denom = self.population_std_deviation()?.powi(3);
180 if denom == 0.0 { return Ok(0.0); }
181 Ok(self.kth_central_moment(3.0)? / denom)
182 }
183
184 pub fn kurtosis(&self) -> CDHResult<f64> {
186 let denom = self.population_std_deviation()?.powi(4);
187 if denom == 0.0 { return Ok(0.0); }
188 Ok((self.kth_central_moment(4.0)? / denom) - 3.0)
189 }
190
191 pub fn sample_variation_xy(&self, y: &[f64]) -> CDHResult<f64> {
195 if y.len() != self.0.len() {
196 return Err("Length of y should be equal to length of dataset".to_string());
197 }
198 let n = y.len() as f64;
199 let xysum = self.0.iter().zip(y.iter()).fold(0.0, |acc, b| acc + (b.0 * b.1));
200 let xsum = self.0.iter().sum::<f64>();
201 let ysum = y.iter().sum::<f64>();
202 Ok(xysum - (xsum * ysum / n))
203 }
204
205 pub fn pearson_correlation_coeff(&self, y: &[f64]) -> CDHResult<f64> {
208 let denom = (self.sample_variation_x2()? * self.sample_variation_y2(y)?).sqrt();
209 if denom == 0.0 {
210 return Ok(0.0); }
212 Ok(self.sample_variation_xy(y)? / denom)
213 }
214
215 pub fn into_set(&self) -> CDHResult<Vec<f64>> {
217 let mut set: Vec<f64> = Vec::with_capacity(self.0.len());
218 for &a in self.0.iter() {
219 if !self.has(a, Some(&set))? {
220 set.push(a);
221 }
222 }
223 Ok(set)
224 }
225
226 pub fn population_variance(&self) -> CDHResult<f64> {
228 let n = self.0.len() as f64;
229 if n == 0.0 { return Err("Empty dataset context.".to_string()); }
230 let mean = self.mean()?;
231 Ok(self.0.iter().fold(0.0, |acc, &x| acc + (x - mean).powi(2)) / n)
232 }
233
234 pub fn population_std_deviation(&self) -> CDHResult<f64> {
236 Ok(self.population_variance()?.sqrt())
237 }
238
239 pub fn max(&self) -> CDHResult<f64> {
241 if self.0.is_empty() { return Err("Dataset is empty.".to_string()); }
242 let mut max = self.0[0];
243 self.0.iter().for_each(|&i| {
244 if i > max { max = i; }
245 });
246 Ok(max)
247 }
248
249 pub fn min(&self) -> CDHResult<f64> {
251 if self.0.is_empty() { return Err("Dataset is empty.".to_string()); }
252 let mut min = self.0[0];
253 self.0.iter().for_each(|&i| {
254 if i < min { min = i; }
255 });
256 Ok(min)
257 }
258
259 pub fn info(&self) -> CDHResult<()> {
261 println!("DataSet === {:?}", self.0);
262 println!("Mean === {:#?}", self.mean()?);
263 println!("Median === {:#?}", self.median()?);
264 println!("Mode === {:#?}", self.mode()?);
265 println!("Range === {:#?}", self.range()?);
266 println!("Variance === {:#?}", self.sample_variance()?);
267 println!("Skewness === {:#?}", self.skewness()?);
268 println!("Kurtosis === {:#?}", self.kurtosis()?);
269 println!("self has 3f64 == {:?}", self.has(3.0, None)?);
270 println!("Set === {:?}", self.into_set()?);
271 println!("Maximum === {:?}", self.max()?);
272 println!("Minimum === {:?}", self.min()?);
273 Ok(())
274 }
275}