Статистика
Меры среднего значения
В этих примерах вычисляются показатели среднего значения для набора данных, содержащегося в Rust массиве. Для пустого набора данных не может быть среднего значения, медианы или моды, поэтому каждая функция возвращает [ Option
], который должен быть обработан вызывающей стороной.
В первом примере вычисляется среднее значение (сумма всех измерений, делённая на количество измерений в наборе) путём создания итератора ссылок по данным и использования [sum
] и [len
] для определения соответственно общего значения и количества значений.
fn main() { let data = [3, 1, 6, 1, 5, 8, 1, 8, 10, 11]; let sum = data.iter().sum::<i32>() as f32; let count = data.len(); let mean = match count { positive if positive > 0 => Some(sum / count as f32), _ => None }; println!("Mean of the data is {:?}", mean); }
Во втором примере вычисляется медиана с использованием алгоритма быстрого выбора, который позволяет избежать полного [sort
] путём сортировки только тех разделов набора данных, о которых известно, что они могут содержать медиану. При этом используются [cmp
] и [Ordering
] для краткого выбора следующего исследуемого раздела и [split_at
] для выбора произвольного центра в следующем разделе на каждом шаге.
use std::cmp::Ordering; fn partition(data: &[i32]) -> Option<(Vec<i32>, i32, Vec<i32>)> { match data.len() { 0 => None, _ => { let (pivot_slice, tail) = data.split_at(1); let pivot = pivot_slice[0]; let (left, right) = tail.iter() .fold((vec![], vec![]), |mut splits, next| { { let (ref mut left, ref mut right) = &mut splits; if next < &pivot { left.push(*next); } else { right.push(*next); } } splits }); Some((left, pivot, right)) } } } fn select(data: &[i32], k: usize) -> Option<i32> { let part = partition(data); match part { None => None, Some((left, pivot, right)) => { let pivot_idx = left.len(); match pivot_idx.cmp(&k) { Ordering::Equal => Some(pivot), Ordering::Greater => select(&left, k), Ordering::Less => select(&right, k - (pivot_idx + 1)), } }, } } fn median(data: &[i32]) -> Option<f32> { let size = data.len(); match size { even if even % 2 == 0 => { let fst_med = select(data, (even / 2) - 1); let snd_med = select(data, even / 2); match (fst_med, snd_med) { (Some(fst), Some(snd)) => Some((fst + snd) as f32 / 2.0), _ => None } }, odd => select(data, odd / 2).map(|x| x as f32) } } fn main() { let data = [3, 1, 6, 1, 5, 8, 1, 8, 10, 11]; let part = partition(&data); println!("Partition is {:?}", part); let sel = select(&data, 5); println!("Selection at ordered index {} is {:?}", 5, sel); let med = median(&data); println!("Median is {:?}", med); }
В последнем примере вычисляется мода с использованием изменяемого [HashMap
] для сбора счётчиков каждого отдельного целого числа из набора с использованием API [fold
] и [entry
]. Наиболее частое значение в [HashMap
] всплывает методом [max_by_key
].
use std::collections::HashMap; fn main() { let data = [3, 1, 6, 1, 5, 8, 1, 8, 10, 11]; let frequencies = data.iter().fold(HashMap::new(), |mut freqs, value| { *freqs.entry(value).or_insert(0) += 1; freqs }); let mode = frequencies .into_iter() .max_by_key(|&(_, count)| count) .map(|(value, _)| *value); println!("Mode of the data is {:?}", mode); } ``` ### Среднеквадратичное отклонение [![std-badge]][std] [![cat-science-badge]][cat-science] В этом примере вычисляется стандартное отклонение и z-оценка набора измерений. Стандартное отклонение определяется как квадратный корень из дисперсии (здесь рассчитывается с помощью [`sqrt`] для f32, где дисперсия представляет собой [`sum`] квадрата разности между каждым измерением и [`mean`], разделённое на количество измерений. Z-оценка - это число стандартных отклонений, на которое одно измерение отклоняется от [`mean`] набора данных. ```rust fn mean(data: &[i32]) -> Option<f32> { let sum = data.iter().sum::<i32>() as f32; let count = data.len(); match count { positive if positive > 0 => Some(sum / count as f32), _ => None, } } fn std_deviation(data: &[i32]) -> Option<f32> { match (mean(data), data.len()) { (Some(data_mean), count) if count > 0 => { let variance = data.iter().map(|value| { let diff = data_mean - (*value as f32); diff * diff }).sum::<f32>() / count as f32; Some(variance.sqrt()) }, _ => None } } fn main() { let data = [3, 1, 6, 1, 5, 8, 1, 8, 10, 11]; let data_mean = mean(&data); println!("Mean is {:?}", data_mean); let data_std_deviation = std_deviation(&data); println!("Standard deviation is {:?}", data_std_deviation); let zscore = match (data_mean, data_std_deviation) { (Some(mean), Some(std_deviation)) => { let diff = data[4] as f32 - mean; Some(diff / std_deviation) }, _ => None }; println!("Z-score of data at index 4 (with value {}) is {:?}", data[4], zscore); }