ml

The ml collection fits machine-learning models to tables with scikit-learn: random forests and histogram gradient boosting, for regression or classification. It is written in Python. Each fitted model is written as a SpadeModel with an ONNX graph, which models.predict scores without Python. Before a model is written, its graph scores the training rows through ONNX Runtime and must agree with the fitted model; if it does not, the block fails rather than writing a model that would predict differently.

The blocks share the model-fitting arguments of the stats and sae model blocks: a Parquet or CSV data input, a target, a features column selector (names, globs and exclusions such as B*,-B0), id_columns, weights, categorical and na_action. Categorical predictors are one-hot encoded. seed fixes every source of randomness, so the same arguments give the same model, byte for byte.

Cross-validation. cv_folds reports cross-validated metrics (cv_rmse, cv_r_squared, or cv_accuracy, cv_log_loss); the model itself is always fitted on all rows. cv_group keeps whole groups -- every plot in a county -- in one fold, because spatially related rows split at random leak information between folds and flatter the model.

Hyperparameter search is a map, not a block: fan a fit block out over a grid with base.map_grid, then close it with ml.select_best, which keeps the best model by a cross-validated metric. Each grid point is its own invocation and caches on its own, so widening the grid refits only the new points.

- id: "@grid"
  name: base.map_grid
  inputs: []
  args:
    axes: '{"max_depth":[3,6,12],"min_samples_leaf":[1,4]}'

- id: "@fit"
  name: ml.random_forest
  inputs:
    - "@grid"
    - block: "@plots"
      output: file
      as: data
  args:
    target: biomass_tons_per_acre
    features: "elevation_m,canopy_cover_pct,stand_age,terrain,forest_type"
    max_depth: ${item.max_depth}
    min_samples_leaf: ${item.min_samples_leaf}
    cv_folds: 4
    cv_group: county

- id: "@best"
  name: ml.select_best
  inputs:
    - block: "@fit"
      output: model
      as: models
  args:
    metric: cv_rmse

examples/local/07-random-forest.yaml is the full pipeline, ending in models.predict.

The training table is held in memory; for very large tables, sample upstream. All blocks in this collection declare network: false.

Blocks🔗

BlockKindDescription
ml.random_foreststandardRandom forest regression or classification, exported as ONNX
ml.gradient_boostingstandardHistogram gradient boosting regression or classification, exported as ONNX
ml.select_bestreduceClose a hyperparameter grid: keep the best model by a fit metric

Installation🔗

spade install file:///path/to/blocks/ml