Example: Iris Dataset¶
The Iris dataset is the classic "Hello World" of machine learning - perfect for getting started with Pilz.
Dataset¶
- Source: UCI Machine Learning Repository
- 150 samples (50 per class)
- 4 features: sepal/petal length and width
- 3 classes: Setosa, Versicolor, Virginica
Quick Start¶
# Download data
curl -o iris.csv "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
# Add headers
echo "sepal_length,sepal_width,petal_length,petal_width,species" > iris_header.csv
cat iris.csv >> iris_header.csv
mv iris_header.csv iris.csv
# Create DataCard (the checked-in examples/iris/dc_iris.yaml was generated this way)
pilz create-dc --src iris.csv --out dc_iris.yaml
# Train
pilz train --datacard dc_iris.yaml --trainsettings train_settings.yaml
# Evaluate
pilz eval --datacard dc_iris.yaml --evalsettings eval_settings.yaml
DataCard¶
features:
- name: sepal_length
statistical: numerical
type: float
- name: sepal_width
statistical: numerical
type: float
- name: petal_length
statistical: numerical
type: float
- name: petal_width
statistical: numerical
type: float
- name: species
statistical: categorial
type: str
target:
feature_name: species
values:
- Iris-setosa
- Iris-versicolor
- Iris-virginica
infos:
src: https://archive.ics.uci.edu/ml/datasets/iris
licence: CC0
date: 2026-05-10
Settings¶
n: 5
out_folder: iris_model
max_depth: 10
n_dims: 2
n_cat: 3
n_rep: 5
train_files:
- /path/to/iris.csv
The checked-in examples/iris/train_settings.yaml is identical apart from
train_files, which contains a machine-specific absolute path.
EvalSettings¶
Actual Results¶
ROC Curves (Excellent Separation)¶
The Iris dataset is well-separated - the three species are easily distinguished:
- Setosa is linearly separable from the others
- Versicolor and Virginica overlap slightly but are still distinguishable
Learned Rules Example¶
The checked-in iris_model/Iris-setosa/0.json holds 4 spores with numeric
depths, log-odds scores and stored leaf counts. Two of them:
{
"cond_table": [
{"kind": "cmp", "op": "<=", "col": "petal_length", "value": 1.5},
...
],
"spore": [
{
"cond": [0],
"score": 4.3175,
"depth": "0",
"n_target": 37,
"n_non_target": 0
},
{
"cond": [1, 2],
"score": -4.9488,
"depth": "1.0",
"n_target": 0,
"n_non_target": 70
}
],
"target": "Iris-setosa"
}
The first spore — petal_length ≤ 1.5 — holds 37 Setosa rows and no others,
scoring +4.32 log-odds (ln(37.5 / 0.5) with the default leaf_alpha
of 0.5). Shared conditions like the petal_length split above live once in
cond_table and are referenced by id, which keeps even large fan-out trees
small on disk.
Output Files¶
iris_model/
├── Iris-setosa/0.json
├── Iris-setosa/1.json
├── Iris-setosa/2.json
├── Iris-setosa/3.json
├── Iris-setosa/4.json
├── Iris-versicolor/0.json
├── ... (trees 1-4 per class)
├── Iris-virginica/4.json
└── label_stats.json
eval/
├── Iris-setosa_roc.html
├── Iris-versicolor_roc.html
├── Iris-virginica_roc.html
├── all_roc.html
├── multi_class_result.html
└── scored.csv
Training also writes label_stats.json for the multi-class target (label
counts and majority class, used as the fallback prediction when
different_target_pilz_comb_method is youden and no threshold margin is
positive). Decision thresholds themselves are derived on the fly from the
stored leaf counts — no threshold files are written or read.
Why Iris Works So Well¶
- Clear clusters: Each species forms a distinct group
- Simple rules work:
petal_lengthalone separates most Setosa from the rest - Shallow interactions suffice: The checked-in
n_dims: 2model needs onlypetal_lengthandsepal_width
Expected Results¶
| Metric | Value |
|---|---|
| AUC | ~1.0 (excellent) |
| Accuracy | >95% |
| Training time | < 1 second |
Next Steps¶
Try these variations to learn more:
- n_dims=1 - See if single features are enough
- n_dims=3 - Try feature combinations (though not needed)
- n_cat=5 - More granular bins
- n=10 - Larger ensemble per class