Docs · Machine learning

tree: decision tree classifier.

A histogram-based decision tree classifier with Gini impurity, the equivalent of Spark MLlib's DecisionTreeClassifier. One min/max pass fixes uniform bins per feature, then one paged pass per level accumulates class counts per node, feature and bin.

Module
ml_tree
Header
clio_ml/decision_tree.h
Rows
features, then class label
Limits
max_depth at most 8

What it does

The host picks each frontier node's best split by maximum Gini gain, breaking ties by lowest feature and then lowest bin. Counts are integers, so the tree is exact and identical across paging, block counts and nodes. The same header also defines the random forest, which reuses DecisionTreeOptions with seed and features_per_node set.

Rows

n_features feature columns followed by the class label in 0..num_classes-1. clio_ml.COLUMNS["tree"] is 1.

Python

python
import numpy as np, clio_ml as cm
rng = np.random.default_rng(1)
X = rng.normal(size=(4096, 7)).astype(np.float32)
y = ((X[:, 0] > 0) + (X[:, 1] > 0.25)).astype(np.float32)   # 3 classes
data = np.column_stack([X, y]).astype(np.float32)

r = cm.fit_tree(data, num_classes=3, max_depth=4, num_bins=32)
print(r.model.depth, r.model.status[:7])      # 0 absent, 2 leaf, 3 split
print(cm.predict("tree", r, data[0, :7]))     # predicted class
  • fit_tree(X, **options).
  • Options (DecisionTreeOptions): num_classes (2), max_depth (4, at most 8), num_bins (32), threads (256), seed (0; non-zero turns on the Poisson(1) bootstrap used by random forests), features_per_node (0 = all features; otherwise a hashed subset per node), row_base (0).
  • Result DecisionTreeResult: model and stats (summed over passes). model (DecisionTreeModel) is a heap-ordered tree with 2^(max_depth+1)-1 slots: nf, C, B (bins), depth, mn and inv (binning, nf each), status (0 absent, 2 leaf, 3 split), feat, split, cls (majority class per node), counts (class counts per node).
  • predict("tree", r, x) returns the class index.

C++

cpp
struct DecisionTreeOptions {
  u32 num_classes = 2;
  u32 max_depth = 4;          // <= 8
  u32 num_bins = 32;
  u32 threads = 256;
  u32 seed = 0;               // != 0: Poisson(1) bootstrap rows
  u32 features_per_node = 0;  // 0 = all
  u64 row_base = 0;
  ClusterExchange cluster;
};
struct DecisionTreeModel {
  u32 nf = 0, C = 0, B = 0, depth = 0;
  std::vector<float> mn, inv;
  std::vector<int> status, feat, split;
  std::vector<u32> cls;
  std::vector<float> counts;
  std::vector<float> Flatten() const;
};
struct DecisionTreeResult { DecisionTreeModel model; VecStats stats; };
DecisionTreeResult FitDecisionTree(Dataset &ds, const DecisionTreeOptions &opt);
DecisionTreeResult FitDecisionTreePlain(const float *data, u64 n_rows, u32 nf,
                                        u64 elems_per_page, u32 nblocks,
                                        const DecisionTreeOptions &opt);
DecisionTreeResult FitDecisionTreeReference(/* same arguments */);
u32 DecisionTreePredict(const DecisionTreeModel &m, const float *x);

The ChiMod is module ml_tree.

Related: random forest, gradient-boosted trees, gradient-boosted classifier.