1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//! Per-column statistics using axis reductions: mean, min, max, std dev.
//!
//! Run: cargo run --example 28_column_statistics
//!
//! A common PoC pattern: treating each column of a [rows, cols] tensor as
//! a feature, computing basic stats across all rows.
use matten::Tensor;
/// Manually compute column standard deviation from column means.
/// std_dev_i = sqrt( mean( (col_i - mean_i)^2 ) )
fn column_std(data: &Tensor, col_means: &Tensor) -> Tensor {
// Broadcast means over all rows, compute squared deviations
let deviations = data - col_means; // [rows, cols] - [cols] → [rows, cols]
let sq = &deviations * &deviations;
sq.mean_axis(0) // → [cols] mean of squared deviations
.as_slice()
.iter()
.map(|v| v.sqrt())
.collect::<Vec<f64>>()
.into()
}
fn main() {
// 4 rows, 3 columns (features)
let data = Tensor::new(
vec![
1.0, 10.0, 100.0, 2.0, 20.0, 200.0, 3.0, 30.0, 300.0, 4.0, 40.0, 400.0,
],
&[4, 3],
);
let means = data.mean_axis(0);
let mins = data.min_axis(0);
let maxs = data.max_axis(0);
let stds = column_std(&data, &means);
println!("columns : 0 1 2");
println!("mean : {:?}", means.as_slice());
println!("min : {:?}", mins.as_slice());
println!("max : {:?}", maxs.as_slice());
println!("std dev : {:?}", stds.as_slice());
assert_eq!(means.as_slice(), &[2.5, 25.0, 250.0]);
assert_eq!(mins.as_slice(), &[1.0, 10.0, 100.0]);
assert_eq!(maxs.as_slice(), &[4.0, 40.0, 400.0]);
// Std dev: sqrt of mean squared deviation from mean
let expected_std0 = {
// Column 0 values: 1,2,3,4. Mean=2.5. Deviations: -1.5,-0.5,0.5,1.5
let sq_devs = [
1.5f64.powi(2),
0.5f64.powi(2),
0.5f64.powi(2),
1.5f64.powi(2),
];
(sq_devs.iter().sum::<f64>() / 4.0).sqrt()
};
assert!((stds.as_slice()[0] - expected_std0).abs() < 1e-10);
println!("done.");
}