05 · python

The same engine,
a Pythonic API.

pip install millwright — a Pythonic pipeline over the same Rust engine, shipped on PyPI as an abi3 wheel built with maturin. Run it at Rust speed from a notebook.

Install & use

A pipeline, from Python.

pip install millwright
import millwright as mw

train = mw.Frame.from_pandas(df)             # or from_numpy / from_rows

pipe = (mw.Pipeline()
    .step("impute", mw.SimpleImputer.median())
    .step("scale",  mw.StandardScaler())
    .estimator("rf", mw.RandomForest(n_trees=200, max_depth=8)))

pipe.fit(train, y_train)
preds   = pipe.predict(test)
metrics = pipe.evaluate(test, y_test)        # -> {"accuracy": …, "f1": …}

The transformer / estimator objects (StandardScaler, MinMaxScaler, SimpleImputer, OneHotEncoder, RandomForest, LinearRegression, Knn, Svc, NaiveBayes) are the same engines as Rust. The older builder form — pipe.standard_scaler(), pipe.random_forest() — still works.

Ingest & EDA

numpy, pandas, or a typed table.

# a Frame reads arrays and DataFrames directly
train = mw.Frame.from_numpy(X)               # or from_pandas(df) / from_rows(rows)

# or the dtype-aware Table (strings, dates, nulls) + automated EDA
data = mw.Table.from_csv("churn.csv")
mw.Profile.of_with_target(data, "churned").to_html("eda.html")
train = data.to_frame()
Tune, explain, export

The whole lifecycle.

# grid search + stratified CV over the pipeline
best = (mw.GridSearch(pipe, {"rf__max_depth": [4, 8, 16]})
    .cv(mw.StratifiedKFold(5)).scoring("f1")
    .fit(train, y_train))
best.best_score; best.best_params()

# SHAP importance, and one portable ONNX artifact
pipe.fit(train, y_train)
pipe.explain(test)                           # [(feature, mean|shap|), …]
pipe.export_onnx("churn.onnx")

# consume an external sklearn / PyTorch model (exported to ONNX) as a step
ext = mw.Pipeline().estimator("onnx", mw.OnnxModel("model.onnx"))
Note. ONNX export folds affine preprocessing (scalers) into the graph; a non-affine step (impute, one-hot) raises, naming the step. Fit / predict / evaluate / explain work with any steps.

python is deliberately not part of full: pyo3's extension-module defers libpython symbols, so a plain cargo test can't link it. It is built and tested the way it ships — as a wheel. To build from source, from a virtualenv: maturin develop --features python. The wheel bundles the EDA (polars), model-selection, explain, and ONNX engines.