Add statistics functions: sum, variance, mean.
This commit is contained in:
parent
570611a59b
commit
cc2a70664d
163
src/base/statistics.rs
Normal file
163
src/base/statistics.rs
Normal file
@ -0,0 +1,163 @@
|
||||
use ::{Real, Dim, Matrix, VectorN, RowVectorN, DefaultAllocator, U1, VectorSliceN};
|
||||
use storage::Storage;
|
||||
use allocator::Allocator;
|
||||
|
||||
impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||
#[inline]
|
||||
pub fn compress_rows(&self, f: impl Fn(VectorSliceN<N, R, S::RStride, S::CStride>) -> N) -> RowVectorN<N, C>
|
||||
where DefaultAllocator: Allocator<N, U1, C> {
|
||||
|
||||
let ncols = self.data.shape().1;
|
||||
let mut res = unsafe { RowVectorN::new_uninitialized_generic(U1, ncols) };
|
||||
|
||||
for i in 0..ncols.value() {
|
||||
// FIXME: avoid bound checking of column.
|
||||
unsafe { *res.get_unchecked_mut(0, i) = f(self.column(i)); }
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn compress_rows_tr(&self, f: impl Fn(VectorSliceN<N, R, S::RStride, S::CStride>) -> N) -> VectorN<N, C>
|
||||
where DefaultAllocator: Allocator<N, C> {
|
||||
|
||||
let ncols = self.data.shape().1;
|
||||
let mut res = unsafe { VectorN::new_uninitialized_generic(ncols, U1) };
|
||||
|
||||
for i in 0..ncols.value() {
|
||||
// FIXME: avoid bound checking of column.
|
||||
unsafe { *res.vget_unchecked_mut(i) = f(self.column(i)); }
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn compress_columns(&self, init: VectorN<N, R>, f: impl Fn(&mut VectorN<N, R>, VectorSliceN<N, R, S::RStride, S::CStride>)) -> VectorN<N, R>
|
||||
where DefaultAllocator: Allocator<N, R> {
|
||||
let mut res = init;
|
||||
|
||||
for i in 0..self.ncols() {
|
||||
f(&mut res, self.column(i))
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||
/*
|
||||
*
|
||||
* Sum computation.
|
||||
*
|
||||
*/
|
||||
#[inline]
|
||||
pub fn sum(&self) -> N {
|
||||
self.iter().cloned().fold(N::zero(), |a, b| a + b)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn row_sum(&self) -> RowVectorN<N, C>
|
||||
where DefaultAllocator: Allocator<N, U1, C> {
|
||||
self.compress_rows(|col| col.sum())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn row_sum_tr(&self) -> VectorN<N, C>
|
||||
where DefaultAllocator: Allocator<N, C> {
|
||||
self.compress_rows_tr(|col| col.sum())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn column_sum(&self) -> VectorN<N, R>
|
||||
where DefaultAllocator: Allocator<N, R> {
|
||||
let nrows = self.data.shape().0;
|
||||
self.compress_columns(VectorN::zeros_generic(nrows, U1), |out, col| {
|
||||
out.axpy(N::one(), &col, N::one())
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Variance computation.
|
||||
*
|
||||
*/
|
||||
#[inline]
|
||||
pub fn variance(&self) -> N {
|
||||
if self.len() == 0 {
|
||||
N::zero()
|
||||
} else {
|
||||
let val = self.iter().cloned().fold((N::zero(), N::zero()), |a, b| (a.0 + b * b, a.1 + b));
|
||||
let denom = N::one() / ::convert::<_, N>(self.len() as f64);
|
||||
val.0 * denom - (val.1 * denom) * (val.1 * denom)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn row_variance(&self) -> RowVectorN<N, C>
|
||||
where DefaultAllocator: Allocator<N, U1, C> {
|
||||
self.compress_rows(|col| col.variance())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn row_variance_tr(&self) -> VectorN<N, C>
|
||||
where DefaultAllocator: Allocator<N, C> {
|
||||
self.compress_rows_tr(|col| col.variance())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn column_variance(&self) -> VectorN<N, R>
|
||||
where DefaultAllocator: Allocator<N, R> {
|
||||
let (nrows, ncols) = self.data.shape();
|
||||
|
||||
let mut mean = self.column_mean();
|
||||
mean.apply(|e| -(e * e));
|
||||
|
||||
let denom = N::one() / ::convert::<_, N>(ncols.value() as f64);
|
||||
self.compress_columns(mean, |out, col| {
|
||||
for i in 0..nrows.value() {
|
||||
unsafe {
|
||||
let val = col.vget_unchecked(i);
|
||||
*out.vget_unchecked_mut(i) += denom * *val * *val
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Mean computation.
|
||||
*
|
||||
*/
|
||||
#[inline]
|
||||
pub fn mean(&self) -> N {
|
||||
if self.len() == 0 {
|
||||
N::zero()
|
||||
} else {
|
||||
self.sum() / ::convert(self.len() as f64)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn row_mean(&self) -> RowVectorN<N, C>
|
||||
where DefaultAllocator: Allocator<N, U1, C> {
|
||||
self.compress_rows(|col| col.mean())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn row_mean_tr(&self) -> VectorN<N, C>
|
||||
where DefaultAllocator: Allocator<N, C> {
|
||||
self.compress_rows_tr(|col| col.mean())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn column_mean(&self) -> VectorN<N, R>
|
||||
where DefaultAllocator: Allocator<N, R> {
|
||||
let (nrows, ncols) = self.data.shape();
|
||||
let denom = N::one() / ::convert::<_, N>(ncols.value() as f64);
|
||||
self.compress_columns(VectorN::zeros_generic(nrows, U1), |out, col| {
|
||||
out.axpy(denom, &col, N::one())
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user