# Use the Standard Model on your data

How to leverage the Standard Model on your own EHR data — reshape and tokenize medical events, build a labels table, and train four types of classifiers on the Standard Model's embeddings.

Complete the [quickstart](https://standardmodel.bio/install.html) setup first. Commands below assume `quickstart/` as the working directory and use `uv run`.

Three steps:

1. **Format & tokenize** — reshape your data into MEDS events + labels tables, serialize with `smb_utils`
2. **Represent** — ingest tokens into the Standard Model to get high-dimensional patient embeddings
3. **Predict** — train task heads on embeddings + labels (readmission, phenotype, survival)

This tutorial focuses on EHR text data. The Standard Model operates on multiple modalities; a multimodal tutorial is forthcoming.

## Format & tokenize data

You need an **events** table in [MEDS (Medical Event Data Standard)](https://github.com/Medical-Event-Data-Standard/meds) format, one row per clinical event. ETLs from common formats — OMOP, MIMIC-IV, MEDS Unsorted — are available in [meds_etl](https://github.com/Medical-Event-Data-Standard/meds_etl). The [end-to-end example](https://standardmodel.bio/example.html) describes the input format in more detail.

Events data — example rows:

| subject_id | time | code | table | value |
|---|---|---|---|---|
| 10000032 | 2022-01-15 08:00:00 | `ICD10:I10` | condition | — |
| 10000032 | 2022-01-15 09:30:00 | `LOINC:2093-3` | lab | 145.2 |
| 10001217 | 2022-02-01 14:00:00 | `RxNorm:861004` | medication | — |

You also need a **labels** table, one row per subject, in the same order as your events table:

| subject_id | prediction_time | readmission | phenotype | survival_mo | observed |
|---|---|---|---|---|---|
| 10000032 | 2022-04-12 12:00:00 | 0 | 0 | 68.1 | 1 |
| 10001217 | 2022-06-15 08:00:00 | 0 | 2 | 45.8 | 1 |
| 10002428 | 2022-02-14 13:30:00 | 1 | 1 | 35.5 | 1 |

The tokenizer uses `prediction_time` as the **cutoff** for which events build the embedding — the "as-of" time for the prediction.

`smb_utils.process_ehr_info` converts a MEDS events table into a tokenizable XML-like stream. Time is measured in days; events sharing a timestamp are grouped by category with XML-style tags, in chronological order.

### Context length

`smb-v1-1.7b` supports a max token length of **4096**, and many patient histories exceed it. [smb-utils](https://github.com/standardmodelbio/smb-utils) offers strategies as a temporary solution:

- Filter events by modality (the `code` or `table` columns)
- Organize events into time bins with the most recent events from an anchor date
- Define custom event categories

Longer context length is on the roadmap.

## ETL example — serialize one patient

```
import pandas as pd
from smb_utils import process_ehr_info

# Load events (MEDS format: subject_id, time, code, table, value)
df = pd.read_parquet("internal_cohort_meds.parquet")
assert {"subject_id", "time", "code", "table", "value"}.issubset(df.columns)

# Serialize a single patient history
# 'end_time' enforces causal masking (the model cannot see future data)
input_text = process_ehr_info(
    df,
    subject_id="patient_5521",
    end_time=pd.Timestamp("2024-01-01")
)
```

Labels must be aligned to the same patient order as your embedding matrix, so the correct `end_time` resolves per patient.

## Represent data as embeddings

`get_embeddings` loads the model, serializes MEDS data into text, tokenizes the stream, and runs inference across a dataframe of patients. **Last-token pooling** extracts the final hidden state, representing the patient's entire causal trajectory up to and including `end_time`.

```
import pandas as pd
import torch
from smb_utils import process_ehr_info
from transformers import AutoModelForCausalLM, AutoTokenizer
from tqdm import tqdm

MODEL_ID = "standardmodelbio/smb-v1-1.7b"

tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
model = AutoModelForCausalLM.from_pretrained(
    MODEL_ID, trust_remote_code=True, device_map="auto"
)
model.eval()

def get_embeddings(df, pids, end_time):
    embeddings = []
    for pid in tqdm(pids):
        if isinstance(end_time, (pd.Series, dict)):
            patient_end_time = pd.Timestamp(end_time[pid])
        else:
            patient_end_time = end_time

        text = process_ehr_info(df, subject_id=pid, end_time=patient_end_time)
        inputs = tokenizer(
            text, return_tensors="pt", truncation=True, max_length=4096
        ).to(model.device)

        with torch.no_grad():
            outputs = model(inputs.input_ids, output_hidden_states=True)
            vec = outputs.hidden_states[-1][:, -1, :].cpu()
            embeddings.append(vec)

    return torch.cat(embeddings, dim=0).numpy()
```

## Train clinical predictors

With `X` and your labels table, train four task heads:

| Task | Type | Model | Metric |
|---|---|---|---|
| Readmission risk | Binary | Logistic regression | ROC-AUC |
| Phenotype stage | Multiclass | Logistic regression | Accuracy |
| Overall survival | Regression | Ridge | MAE |
| Cox proportional hazards | Survival | CoxPHFitter (lifelines) | C-index |

```
import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression, Ridge
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA
from sklearn.metrics import roc_auc_score, accuracy_score, mean_absolute_error
from lifelines import CoxPHFitter

# X, pids from the embedding step above. Align labels to X row order:
labels_df = pd.read_parquet("your_labels.parquet")
labels = labels_df.set_index("subject_id").loc[pids].reset_index()

X_train, X_test, labels_train, labels_test = train_test_split(
    X, labels, test_size=0.2, random_state=42
)

# Task A: Binary (readmission risk)
clf_bin = LogisticRegression(max_iter=1000)
clf_bin.fit(X_train, labels_train["readmission_risk"])
y_prob = clf_bin.predict_proba(X_test)[:, 1]
auc = roc_auc_score(labels_test["readmission_risk"], y_prob)
```

## Next steps

- [Install & quickstart](https://standardmodel.bio/install.html)
- [End-to-end example](https://standardmodel.bio/example.html)
- [Model hub](https://standardmodel.bio/model-hub.html)
- Integration questions: info@standardmodel.bio

© 2026 Standard Model Biomedicine · San Francisco, CA
