Models and the tree IR¶
Every supported model is parsed into one intermediate representation
(EnsembleIR): trees of (feature, threshold, op, missing_left) nodes plus a
raw-space intercept and an output link. Backends only ever see the IR — no
backend touches a native model object.
Supported inputs¶
| Library | Native objects | Dump input | Notes |
|---|---|---|---|
| XGBoost | Booster, sklearn wrappers |
save_model("*.json") path or dict |
binary:logistic, reg:squarederror; LT convention |
| LightGBM | Booster, sklearn wrappers |
dump_model() dict or its JSON |
binary, regression; LE convention; zero_as_missing and categorical splits raise |
| CatBoost | classifier/regressor | save_model(format="json") |
oblivious trees expanded to binary trees |
| scikit-learn | RF, GB, HistGB | — | see raw-score semantics below |
Unsupported constructs (multiclass, dart/gblinear, native categorical splits)
raise UnsupportedModelError — parsers never degrade silently. Every parser is
gated by a conformance suite that compares IR evaluation against native
predictions on ≥10k probes including NaN patterns and threshold-adjacent points.
Raw-score semantics per family¶
- XGBoost / LightGBM / CatBoost / GradientBoosting / HistGradientBoosting: raw score = margin (log-odds for binary classifiers, SIGMOID link).
- RandomForestClassifier: the raw score is the averaged class-1
probability with an IDENTITY link. Use
Target.raw(range=(0.0, 0.3))— aTarget.probabilityon a forest raises, because there is no sigmoid to invert.
Float32 pitfalls handled for you¶
GBDT libraries store thresholds and inputs as float32 and their JSON dumps use shortest-round-trip decimals; treecf casts thresholds back through float32 where the library compares in float32, and handles LightGBM's zeroing of values with magnitude below 1e-35. Without this, counterfactual values equal to a threshold would route differently in the deployed model.