use crate::panel::{bool_to_f64, Panel};
use ndarray::Array2;
impl Panel {
fn top_n(&self, n: usize, largest: bool) -> Panel {
let (nrows, ncols) = self.data.dim();
let mut out = Array2::from_elem((nrows, ncols), 0.0);
for r in 0..nrows {
let mut valid: Vec<(usize, f64)> = (0..ncols)
.filter_map(|c| {
let v = self.data[[r, c]];
if v.is_nan() {
None
} else {
Some((c, v))
}
})
.collect();
if n == 0 {
continue;
}
if valid.len() <= n {
for (c, _) in valid {
out[[r, c]] = 1.0;
}
continue;
}
valid.sort_by(|a, b| {
let ord = a.1.partial_cmp(&b.1).unwrap();
if largest {
ord.reverse()
} else {
ord
}
});
for &(c, _) in valid.iter().take(n) {
out[[r, c]] = 1.0;
}
}
let data = out.mapv(|x| bool_to_f64(x == 1.0));
Panel {
dates: self.dates.clone(),
symbols: self.symbols.clone(),
data,
}
}
pub fn is_largest(&self, n: usize) -> Panel {
self.top_n(n, true)
}
pub fn is_smallest(&self, n: usize) -> Panel {
self.top_n(n, false)
}
}
#[cfg(test)]
mod tests {
use crate::panel::Panel;
#[test]
fn nan_never_selected_and_ties_pick_earlier_column() {
let p = Panel::from_rows(
vec![20240102],
vec!["A".into(), "B".into(), "C".into()],
vec![vec![5.0, 5.0, f64::NAN]],
)
.unwrap();
let r = p.is_largest(1);
assert_eq!(r.data[[0, 0]], 1.0); assert_eq!(r.data[[0, 1]], 0.0);
assert_eq!(r.data[[0, 2]], 0.0); }
}
impl Panel {
pub fn normalize_row(&self) -> Panel {
let (nrows, ncols) = self.data.dim();
let mut data = self.data.clone();
for r in 0..nrows {
let total: f64 = (0..ncols)
.map(|c| data[[r, c]])
.filter(|v| !v.is_nan())
.map(f64::abs)
.sum();
if total > 0.0 {
for c in 0..ncols {
data[[r, c]] /= total;
}
}
}
Panel {
dates: self.dates.clone(),
symbols: self.symbols.clone(),
data,
}
}
}
#[cfg(test)]
mod normalize_row_tests {
use crate::panel::Panel;
use ndarray::array;
#[test]
fn scales_rows_to_unit_gross_preserving_nan_and_zero_rows() {
let p = Panel::new(
vec![20240102, 20240103, 20240104],
vec!["A".into(), "B".into(), "C".into()],
array![
[1.0, 3.0, f64::NAN], [-1.0, 1.0, 2.0], [0.0, 0.0, f64::NAN] ],
)
.unwrap();
let n = p.normalize_row();
assert_eq!(n.data[[0, 0]], 0.25);
assert_eq!(n.data[[0, 1]], 0.75);
assert!(n.data[[0, 2]].is_nan());
assert_eq!(n.data[[1, 0]], -0.25);
assert_eq!(n.data[[1, 2]], 0.5);
assert_eq!(n.data[[2, 0]], 0.0);
assert!(n.data[[2, 2]].is_nan());
}
}