use crate::error::MattenMlprepError;
use crate::util::matrix_dims;
use matten::Tensor;
#[inline]
fn at(data: &[f64], i: usize, j: usize, cols: usize) -> f64 {
data[i * cols + j]
}
pub fn standardize_columns(x: &Tensor) -> Result<Tensor, MattenMlprepError> {
let (rows, cols) = matrix_dims(x)?;
let data = x.as_slice();
let means = x.mean_axis(0);
let means = means.as_slice();
let mut out = vec![0.0f64; rows * cols];
for j in 0..cols {
let mean = means[j];
let var = (0..rows)
.map(|i| {
let d = at(data, i, j, cols) - mean;
d * d
})
.sum::<f64>()
/ rows as f64;
let std = var.sqrt();
if std == 0.0 {
return Err(MattenMlprepError::ZeroVariance { column: j });
}
for i in 0..rows {
out[i * cols + j] = (at(data, i, j, cols) - mean) / std;
}
}
Tensor::try_new(out, &[rows, cols]).map_err(MattenMlprepError::Matten)
}
pub fn minmax_scale_columns(x: &Tensor) -> Result<Tensor, MattenMlprepError> {
let (rows, cols) = matrix_dims(x)?;
let data = x.as_slice();
let mins = x.min_axis(0);
let maxs = x.max_axis(0);
let mins = mins.as_slice();
let maxs = maxs.as_slice();
let mut out = vec![0.0f64; rows * cols];
for j in 0..cols {
let range = maxs[j] - mins[j];
if range == 0.0 {
return Err(MattenMlprepError::ZeroVariance { column: j });
}
for i in 0..rows {
out[i * cols + j] = (at(data, i, j, cols) - mins[j]) / range;
}
}
Tensor::try_new(out, &[rows, cols]).map_err(MattenMlprepError::Matten)
}