Skip to main content

dtrees_rs/
globals.rs

1//! Item encoding and small numeric helpers.
2//!
3//! An item is a feature together with a branch: item `2 * f` is the branch
4//! where feature `f` is 0 (left), and item `2 * f + 1` the branch where it is
5//! 1 (right).
6
7use crate::tree::Tree;
8use float_cmp::{ApproxEq, F64Margin};
9
10/// The feature of an item.
11pub fn attribute(item: usize) -> usize {
12    item / 2
13}
14
15/// The branch of an item: 0 for left, 1 for right.
16pub fn item_type(item: usize) -> usize {
17    item % 2
18}
19
20/// The item of a feature and a branch.
21pub fn item(attribute: usize, item_type: usize) -> usize {
22    attribute * 2 + item_type
23}
24
25/// Whether a value is zero, up to two units in the last place.
26pub fn float_is_null(value: f64) -> bool {
27    value.approx_eq(
28        0.0,
29        F64Margin {
30            ulps: 2,
31            epsilon: 0.0,
32        },
33    )
34}
35
36/// Shannon entropy (base 2) of a class distribution.
37pub fn compute_entropy(classes_support: &[usize]) -> f64 {
38    let support = classes_support.iter().sum::<usize>();
39    let mut entropy = 0f64;
40    for class_support in classes_support {
41        let p = match support {
42            0 => 0f64,
43            _ => *class_support as f64 / support as f64,
44        };
45
46        let mut log_val = 0f64;
47        if p > 0. {
48            log_val = p.log2();
49        }
50        entropy += -p * log_val;
51    }
52    entropy
53}
54
55/// The metric stored at the root of `tree`, 0 if none.
56pub fn get_tree_root_gain(tree: &Tree) -> f64 {
57    tree.get_node(tree.get_root_index())
58        .map_or(0.0, |node| node.value.metric.unwrap_or(0.0))
59}
60
61/// The error of the root of `tree`, infinite if the tree is empty.
62pub fn get_tree_root_error(tree: &Tree) -> f64 {
63    tree.get_node(tree.get_root_index())
64        .map_or(<f64>::INFINITY, |node| node.value.error)
65}