Skip to content

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

in_folders:
  - iris_model
out_folder: eval
test_files:
  - /path/to/iris.csv
out_file: eval/scored.csv

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

flowchart LR subgraph "Feature Distribution" P1[petal_length: 1-6cm] P2[petal_width: 0.1-2.5cm] end subgraph "Separation" S1[Setosa: Small petals] S2[Versicolor: Medium] S3[Virginica: Large] end P1 --> S1 P1 --> S2 P1 --> S3 P2 --> S1 P2 --> S2 P2 --> S3 style S1 fill:#ccffcc style S2 fill:#ffff99 style S3 fill:#ffcccc
  1. Clear clusters: Each species forms a distinct group
  2. Simple rules work: petal_length alone separates most Setosa from the rest
  3. Shallow interactions suffice: The checked-in n_dims: 2 model needs only petal_length and sepal_width

Expected Results

Metric Value
AUC ~1.0 (excellent)
Accuracy >95%
Training time < 1 second

Next Steps

Try these variations to learn more:

  1. n_dims=1 - See if single features are enough
  2. n_dims=3 - Try feature combinations (though not needed)
  3. n_cat=5 - More granular bins
  4. n=10 - Larger ensemble per class