Quick start
MLschema reads column dtypes, names and nullability. The quality of the schema follows the quality of those dtypes, so the first step is a DataFrame whose types say what each column means.
1. Give each column a deliberate dtype
Section titled “1. Give each column a deliberate dtype”import pandas as pd
df = pd.read_csv("applicants.csv")df = df.astype({"role": "category"})df["joined"] = pd.to_datetime(df["joined"])For this page, the same data built inline:
df = pd.DataFrame( { "name": ["Ada", "Linus", "Grace"], "score": [98.5, 86.0, 91.0], "role": pd.Categorical(["engineer", "engineer", "scientist"]), "active": [True, False, True], "joined": pd.to_datetime(["2024-01-15", "2023-06-01", None]), })2. Infer the fields
Section titled “2. Infer the fields”from mlschema import infer_schema
fields = infer_schema(df)fields is a plain list[dict], one entry per column, in column order:
[ { "label": "name", "required": true, "mappedTo": "name", "kind": "text" }, { "label": "score", "required": true, "mappedTo": "score", "kind": "number", "step": 0.1 }, { "label": "role", "required": true, "mappedTo": "role", "kind": "category", "options": ["engineer", "scientist"] }, { "label": "active", "required": true, "mappedTo": "active", "kind": "boolean" }, { "label": "joined", "required": false, "mappedTo": "joined", "kind": "date" }]What each key came from:
kindcomes from the dtype:strfalls back totext,float64is anumber,categorykeeps its declared categories asoptions,boolis aboolean, anddatetime64[us]is adate.labelandmappedToboth start as the column name.labelis display copy you can change;mappedTois the key the model expects. See Mappings.requiredistruewhen the column has no missing values.joinedhas one, so it is optional.- Unset optional attributes are omitted rather than sent as
null.
3. Refine what inference cannot know
Section titled “3. Refine what inference cannot know”Labels, bounds, units and defaults are product decisions. Patch them by column name:
fields = infer_schema( df, overrides={ "score": {"label": "Quality score", "min": 0, "max": 100, "unit": "points"}, "joined": {"label": "Joined on", "required": True}, },)Overrides are validated with the rest of the field, so "min": 200, "max": 100 fails instead of
reaching the interface. Overrides covers the rules.
4. Send it to a frontend
Section titled “4. Send it to a frontend”The result is JSON-serialisable as returned:
import json
payload = json.dumps(fields)MLForm renders these fields as an accessible form and submits
values under each mappedTo. Use with MLForm shows the handoff. Any other
consumer can branch on kind, as described in Field contract.
Next steps
Section titled “Next steps”- Field kinds: every built-in kind and how it is detected.
- Mappings: one-hot groups and models that take a positional feature vector.
- Builders and custom kinds: your own inference rules.
