cts_math/
statistic.rs

1use std::{cmp::Ordering, ops::{Add, AddAssign, Div, Mul, Sub}};
2use num::{Float, NumCast};
3
4/// 计算数据的格式
5pub fn count<T>(data: &[T]) -> usize {
6    data.iter().count()
7}
8
9/// 计算数组的最小值
10pub fn min<T>(data: &[T]) -> Option<T>
11where
12    T: PartialOrd + Copy,
13{
14    if data.is_empty() {
15        return None;
16    }
17
18    let mut min_result = data[0];
19
20    for &item in data.iter().skip(1) {
21        if min_result > item {
22            min_result = item;
23        }
24    }
25
26    Some(min_result)
27}
28
29
30/// 计算数组的最大值
31pub fn max<T>(data: &[T]) -> Option<T>
32where
33    T: PartialOrd + Copy,
34{
35    if data.is_empty() {
36        return None;
37    }
38
39    let mut max_result = data[0];
40
41    for &item in data.iter().skip(1) {
42        if max_result < item {
43            max_result = item;
44        }
45    }
46
47    Some(max_result)
48}
49
50/// 计算数组的平均值
51pub fn avg<T>(data: &[T]) -> Option<f64>
52where
53    T: std::convert::Into<f64> + Copy,
54{
55    if data.is_empty() {
56        return None;
57    }
58
59    let mut result = 0.0;
60    let mut count = 0;
61
62    for &item in data {
63        let value: f64 = item.into();
64        result += value;
65        count += 1;
66    }
67
68    Some(result / count as f64)
69}
70
71/// 计算数组的中位数
72pub fn median<T>(numbers: &mut [T]) -> Option<T>
73where
74    T: PartialOrd + Copy + Add<Output = T> + Div<Output = T> + From<u8>,
75{
76
77    if numbers.is_empty() {
78        return None;
79    }
80    numbers.sort_by(|a, b| {
81        a.partial_cmp(b).unwrap_or_else(|| {
82            // 处理无法比较的情况,这里我们选择保持顺序
83            Ordering::Equal
84        })
85    });
86
87    let len = numbers.len();
88    let mid = len / 2;
89
90    if len % 2 == 0 {
91        // 偶数个元素,取中间两个数的平均值
92        Some((numbers[mid - 1] + numbers[mid]) / T::from(2u8))
93    } else {
94        // 奇数个元素,取中间的数
95        Some(numbers[mid])
96    }
97}
98
99///计算数组的标准差
100pub fn std_dev<T, U>(data: &[T]) -> U
101where
102    T: NumCast + Copy,
103    U: Float + AddAssign + NumCast,
104{
105    if data.len() < 2 {
106        return U::zero();
107    }
108
109    let n = U::from(data.len()).unwrap();
110    let n_minus_one = U::from(data.len() - 1).unwrap();
111
112    // 使用 fold 计算总和
113    let sum = data.iter()
114        .map(|&x| U::from(x).unwrap())
115        .fold(U::zero(), |acc, x| acc + x);
116
117    let mean = sum / n;
118
119    // 使用 fold 计算方差
120    let variance = data.iter()
121        .map(|&x| {
122            let val = U::from(x).unwrap();
123            let diff = val - mean;
124            diff * diff
125        })
126        .fold(U::zero(), |acc, x| acc + x) / n_minus_one;
127
128    variance.sqrt()
129}