millwright 2.2.1

A unified ML framework for Rust — proven Rust crates, assembled into one machine.
Documentation
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Millwright · Python</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="site.css">
</head><body><header class="top">
  <div class="wrap">
    <div class="brand"><a href="../index.html"><span class="mark">⚙</span>millwright</a><span class="ver">docs</span></div>
    <nav>
      <a href="index.html">home</a>
      <a href="data.html">data &amp; EDA</a>
      <a href="pipelines.html">pipelines</a>
      <a href="insight.html">insight</a>
      <a href="deploy.html">deploy</a>
      <a href="python.html" class="active">python</a>
      <a href="../index.html">design brief</a>
      <a class="repo" href="https://github.com/mi7plus/millwright">GitHub ↗</a>
    </nav>
  </div>
</header>

<main>
  <div class="wrap">
    <div class="hero">
      <div class="eyebrow">05 · python</div>
      <h1>The same engine,<br>a Pythonic API.</h1>
      <p class="lede"><code class="inl">pip install millwright</code> — a Pythonic pipeline over the same Rust engine, shipped on <a href="https://pypi.org/project/millwright/">PyPI</a> as an abi3 wheel built with maturin. Run it at Rust speed from a notebook.</p>
    </div>
  </div>

  <section id="python">
    <div class="wrap">
      <div class="head col">
        <div class="eyebrow">Install &amp; use</div>
        <h2>A pipeline, from Python.</h2>
      </div>
<pre>pip install millwright</pre>
<pre><span class="k">import</span> millwright <span class="k">as</span> mw

train = mw.Frame.from_pandas(df)             <span class="c"># or from_numpy / from_rows</span>

pipe = (mw.<span class="f">Pipeline</span>()
    .step(<span class="s">"impute"</span>, mw.SimpleImputer.median())
    .step(<span class="s">"scale"</span>,  mw.StandardScaler())
    .estimator(<span class="s">"rf"</span>, mw.RandomForest(n_trees=<span class="k">200</span>, max_depth=<span class="k">8</span>)))

pipe.fit(train, y_train)
preds   = pipe.predict(test)
metrics = pipe.evaluate(test, y_test)        <span class="c"># -&gt; {"accuracy": …, "f1": …}</span></pre>
      <p>The transformer / estimator objects (<code class="inl">StandardScaler</code>, <code class="inl">MinMaxScaler</code>, <code class="inl">SimpleImputer</code>, <code class="inl">OneHotEncoder</code>, <code class="inl">RandomForest</code>, <code class="inl">LinearRegression</code>, <code class="inl">Knn</code>, <code class="inl">Svc</code>, <code class="inl">NaiveBayes</code>) are the same engines as Rust. The older builder form — <code class="inl">pipe.standard_scaler()</code>, <code class="inl">pipe.random_forest()</code> — still works.</p>
    </div>
  </section>

  <section id="ingest">
    <div class="wrap">
      <div class="head col">
        <div class="eyebrow">Ingest &amp; EDA</div>
        <h2>numpy, pandas, or a typed table.</h2>
      </div>
<pre><span class="c"># a Frame reads arrays and DataFrames directly</span>
train = mw.Frame.from_numpy(X)               <span class="c"># or from_pandas(df) / from_rows(rows)</span>

<span class="c"># or the dtype-aware Table (strings, dates, nulls) + automated EDA</span>
data = mw.Table.from_csv(<span class="s">"churn.csv"</span>)
mw.Profile.of_with_target(data, <span class="s">"churned"</span>).to_html(<span class="s">"eda.html"</span>)
train = data.to_frame()</pre>
    </div>
  </section>

  <section id="tune">
    <div class="wrap">
      <div class="head col">
        <div class="eyebrow">Tune, explain, export</div>
        <h2>The whole lifecycle.</h2>
      </div>
<pre><span class="c"># grid search + stratified CV over the pipeline</span>
best = (mw.GridSearch(pipe, {<span class="s">"rf__max_depth"</span>: [<span class="k">4</span>, <span class="k">8</span>, <span class="k">16</span>]})
    .cv(mw.StratifiedKFold(<span class="k">5</span>)).scoring(<span class="s">"f1"</span>)
    .fit(train, y_train))
best.best_score; best.best_params()

<span class="c"># SHAP importance, and one portable ONNX artifact</span>
pipe.fit(train, y_train)
pipe.explain(test)                           <span class="c"># [(feature, mean|shap|), …]</span>
pipe.export_onnx(<span class="s">"churn.onnx"</span>)

<span class="c"># consume an external sklearn / PyTorch model (exported to ONNX) as a step</span>
ext = mw.<span class="f">Pipeline</span>().estimator(<span class="s">"onnx"</span>, mw.OnnxModel(<span class="s">"model.onnx"</span>))</pre>
      <div class="callout"><b>Note.</b> 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.</div>
      <p class="tiny"><code class="inl">python</code> is deliberately not part of <code class="inl">full</code>: pyo3's <code class="inl">extension-module</code> defers libpython symbols, so a plain <code class="inl">cargo test</code> can't link it. It is built and tested the way it ships — as a wheel. To build from source, from a virtualenv: <code class="inl">maturin develop --features python</code>. The wheel bundles the EDA (polars), model-selection, explain, and ONNX engines.</p>
    </div>
  </section>

  <div class="wrap">
    <div class="pager">
      <a href="deploy.html"><span class="dir">← prev</span><b>Deploy</b></a>
      <a class="next" href="index.html"><span class="dir">back to →</span><b>Docs home</b></a>
    </div>
  </div>
</main>

<footer>
  <div class="wrap">
    <span class="mono">⚙ millwright docs</span>
    <span class="mono"><a href="../index.html">design brief</a> · <a href="https://crates.io/crates/millwright">crates.io</a> · <a href="https://pypi.org/project/millwright/">PyPI</a> · <a href="https://docs.rs/millwright">docs.rs</a> · <a href="https://github.com/mi7plus/millwright">GitHub</a></span>
  </div>
</footer>
</body></html>