Skip to content

Documentation

fyt โ€” From Yaml Training

A configuration-driven machine learning library for tabular data โ€” classification and regression. Define, train, evaluate, save, and reuse end-to-end ML pipelines from YAML files or from Python.

Features

  • ๐Ÿ”ง Configuration-Driven: Define entire ML pipelines through YAML files
  • ๐Ÿ Programmatic API: The same pipelines are available from Python (import fyt)
  • ๐ŸŽฏ Classification & Regression: One task: switch drives models, metrics, target processing, and split strategy
  • ๐Ÿงฉ Modular Architecture: Registry-based components; add your own models, imputers, transformers, and metrics without touching library code
  • ๐Ÿ’พ Persistence & Inference: Save fitted pipelines to disk, reload them, and batch-score new data (fyt predict)
  • ๐Ÿ” Leakage-Safe Tuning: Optuna hyperparameter search re-fits preprocessing and feature selection inside every CV fold (on by default)
  • ๐Ÿ“Š Optional Experiment Tracking: MLflow integration when configured; runs happily without it
  • โœจ Feature Engineering: Imputation (incl. MissForest and QRILC), scaling, encoding, correlation filtering, Boruta/RFE/KBest selection, feature importance (native/SHAP/permutation)
  • ๐Ÿงช Robust Validation: Stratified or plain K-Fold, multiple random seeds with per-seed fault isolation, aggregated statistics across seeds

Quick Start

Install

# as a dependency of your project
pip install .            # from a checkout; wheels build via hatchling

# or for development
make install-uv          # once, if you don't have uv
make dev                 # creates .venv with all dev dependencies + pre-commit hooks

Run the bundled example (no MLflow needed)

uv run fyt run_pipeline --config examples/quickstart/config.yaml

That config trains a random forest on a small bundled dataset, prints metrics, and exits. Point data_manager.data_path at your own CSV or Parquet file to train on real data.

Use it from Python

import fyt

config = fyt.RunPipelineCommandConfig.from_yaml("examples/quickstart/config.yaml")
pipeline = fyt.create_training_pipeline(config)
metrics = pipeline.run(test_size=0.2, random_state=42)

# keep the fitted pipeline
artifact = pipeline.to_inference_pipeline().save("models/my_model")

# ... later, in another process
loaded = fyt.load_pipeline("models/my_model.joblib")
predictions = loaded.predict(new_dataframe)          # polars Series of labels/values
probabilities = loaded.predict_proba(new_dataframe)  # classification only

Batch prediction from the CLI

# predict.yaml
model_path: models/my_model.joblib
data_path: data/new_samples.csv
output_path: predictions.csv
id_column: sample_id     # optional passthrough
include_proba: true      # optional probability columns
uv run fyt predict --config predict.yaml

Configuration Example

task: classification        # or: regression

seeds: [42, 123, 456]       # each seed is a full run; failures are isolated
test_size: 0.2
model_output_dir: models/   # optional: saves pipeline_seed_<seed>.joblib per seed

data_manager:
  data_path: data/my_dataset.csv    # .csv or .parquet
  target_column: target             # required
  id_column: sample_id              # optional

pre_processor:
  numerical_imputations:
    - strategy: mean                # mean, median, knn, miss_forest, qrilc, ...
      impute_zeros: false
  numerical_transformations:
    - strategy: standard            # standard, min_max, robust, log, combat, ...
  categorical_transformations:
    - strategy: ordinal             # ordinal, onehot

feature_selector:
  feature_selection:
    strategy: select_k_best         # boruta, rfe, select_from_model, variance_threshold, passthrough
    scoring_function: f_classif
    params:
      k: 10
  correlation_filter:
    enabled: true
    method: pearson
    threshold: 0.95
    removal_strategy: highest_mean

trainer:
  model_type: random_forest
  model_params:
    n_estimators: 200
  metrics: [accuracy, precision, recall, f1, roc_auc]   # omit for task defaults
  metric_averaging: auto            # auto | binary | macro | micro | weighted

  cross_validation_config:
    enabled: true
    n_splits: 5

  optuna_config:
    enabled: true
    n_trials: 30
    optimization_metric: f1         # tuned objective == reported metric
    direction: maximize
    leakage_safe_cv: true           # preprocessing re-fit inside each fold (default)
    param_space:
      - name: n_estimators
        param_type: int
        low: 100
        high: 400

# Optional โ€” omit this block entirely to run without MLflow
experiment_logger:
  tracking_uri: "http://localhost:5001"
  experiment_name: my_experiment

Unknown or misspelled configuration keys are rejected at load time with a validation error.

Configuration kinds

fyt separates configuration into two kinds, each with its own base class in fyt/utils/configs.py:

  • Process settings โ€” YamlBaseSettings, layered over the environment so environment variables can override the YAML file. Best for singular, per-process settings such as the global log level.
  • Instance configs โ€” YamlBaseModel, plain data models loaded explicitly from a file. The same class can be loaded many times from different files, with no shared environment state between instances. All pipeline/command configs are of this kind.

Instance configs are loaded through from_yaml. A config class may set a DEFAULT_CONFIG_PATH, which is used whenever no path is given โ€” so the common case takes no arguments, while any case that needs a different file simply passes one.

Available Strategies

Category Options
Numerical imputation mean, median, most_frequent, constant, knn, miss_forest, qrilc (left-censored data)
Categorical imputation most_frequent, constant
Numerical transformation standard, min_max, robust, log, combat (batch correction), mean_binarizer
Categorical encoding ordinal, onehot
Feature selection select_k_best, select_percentile, rfe, select_from_model, variance_threshold, boruta, passthrough
Classification models logistic_regression, random_forest, xgboost, svm, knn, gradient_boosting, decision_tree, voting_classifier, stacking_classifier
Regression models linear_regression, ridge, lasso, elastic_net, random_forest_regressor, gradient_boosting_regressor, xgboost_regressor, svr, knn_regressor, decision_tree_regressor
Classification metrics accuracy, balanced_accuracy, precision, recall, f1, mcc, roc_auc, pr_auc, log_loss, confusion_matrix
Regression metrics mae, mse, rmse, r2
Feature importance native, shap, permutation

Every category is extensible at runtime via its registry:

from fyt.registries.model import ModelRegistry

@ModelRegistry.register("my_model")
def _my_model(**kwargs):
    return MyEstimator(**kwargs)

See docs/ARCHITECTURE.md for the full design and extension guide.

Experiment Tracking (optional)

fyt logs to MLflow when an experiment_logger block is configured. Without it, runs use a no-op logger and everything else works the same.

make mlflow-up      # start a local MLflow server (Docker, http://localhost:5001)
make mlflow-down    # stop it

Project Structure

fyt/                        # Repository root
โ”œโ”€โ”€ fyt/                    # Installable package
โ”‚   โ”œโ”€โ”€ commands/           # CLI commands (run_pipeline, predict)
โ”‚   โ”œโ”€โ”€ configs/            # Pydantic configuration models & enums
โ”‚   โ”œโ”€โ”€ core/               # Pipeline components + orchestrator
โ”‚   โ”‚   โ”œโ”€โ”€ inference_pipeline.py   # save/load/predict artifact
โ”‚   โ”‚   โ””โ”€โ”€ ...
โ”‚   โ”œโ”€โ”€ registries/         # Component registries (models, imputers, ...)
โ”‚   โ”œโ”€โ”€ wrappers/           # Third-party adapters (Boruta, ComBat, MissForest)
โ”‚   โ”œโ”€โ”€ imputations/        # Custom imputers (QRILC)
โ”‚   โ”œโ”€โ”€ utils/              # Logging, config loading, experiment logger, seeding
โ”‚   โ””โ”€โ”€ metrics.py          # Metric registry (+ sklearn scorer mapping)
โ”œโ”€โ”€ examples/quickstart/    # Runnable example (data + config)
โ”œโ”€โ”€ configs/                # Optional runtime defaults (log level, MLflow)
โ”œโ”€โ”€ tests/                  # Unit + end-to-end tests
โ””โ”€โ”€ docs/                   # Architecture documentation

Development

make dev            # install all dev dependencies + pre-commit hooks
make format         # ruff format
make format-check   # check formatting without modifying files
make lint           # ruff + ty type check
make lint-doc       # docstring style (flake8/pydoclint)
make test           # pytest (parallel, with coverage)
make build          # build sdist + wheel
make validate       # format, lint, test, and build
make doc            # build and serve the documentation locally
make help           # list all targets

Docker

The repository includes a multi-stage Dockerfile producing an image with the package and its dependencies:

make dockerize

GitHub Actions

Three workflows are included: lint+test on pushes to main/dev, docs deployment to GitHub Pages on pushes to main, and a PyPI publish flow triggered by version tags.

Technology Stack

uv ยท Make ยท ruff ยท ty ยท pytest ยท rich (stdlib logging) ยท pydantic v2 ยท polars ยท scikit-learn ยท XGBoost ยท Optuna ยท MLflow (optional)

License

MIT

Author

Cristian C. Spagnuolo (cristian.c.spagnuolo@gmail.com)

Greetings

This repository is built on a Python project template forked from Giovanni Giacometti's original work: giovannigiacometti/python-repository-template. See docs/updating-from-template.md for how template updates are pulled in.