Skip to main content

PerRI — Personalized Reference Intervals

Code accompanying the paper: Personalized clinical reference intervals for routine precision medical care

Built on University of Washington Medicine (UWM) data. All default hyperparameters, units, and reference ranges are calibrated to UWM laboratory standards.

Note on units and reference ranges: Default hyperparameters assume UWM laboratory units and reference ranges (UW Lab Test Guide). If your institution uses different units or reference ranges, update bayesian_hyperparameters.csv and marker_intra_patient_std.csv to reflect own lab's reference ranges.


What does it do?

Standard clinical reference intervals are derived from a healthy reference population and applied uniformly to all patients. PerRI takes a different approach: for any laboratory marker that follows homeostatic dynamics, it fits a Bayesian model to an individual's longitudinal lab measurements to estimate that patient's personal physiological setpoint as a normal distribution N(μ, σ).

The model starts from a population-level prior derived from the standard reference range for the marker, then refines its estimate with each new observation. At any time point, the personalized reference interval is the 95% credible interval: μ ± 1.96σ. The result is a reference interval specific to the individual — narrower for patients with stable physiology, and appropriately wider for those with greater intra-individual variability.


Inputs

The model takes an ordered sequence of measurement values and timestamps for a single patient and marker. Five hyperparameters control the search space and temporal weighting:

Parameter Description
log_lambda_ Log of the temporal decay rate. Higher values give more weight to recent measurements over older ones. Optimized per marker, procedure mentioned in the paper
min_mu, max_mu Search grid bounds for the setpoint μ. Bundled defaults are calibrated to UWM. perri.bounds.resolve_grid_bounds calculates site-specific bounds using each marker's policy in perri/marker_config.py: clinical RI by default, empirical 0.5th/99.5th percentiles for A1C, and an empirical upper side for HDL.
min_sigma, max_sigma Search grid bounds for within-person SD σ.

Pre-optimized values for all 43 supported markers are in perri/data/bayesian_hyperparameters.csv, stratified by sex (ALL, M, F). Supported markers:

['A1C', 'ALB', 'ALK', 'ALT', 'AST', 'BIL', 'BILD', 'BUN', 'CA', 'CHOL', 'CL', 'CO2', 'CRE', 'FER', 'GLU', 'HB', 'HCT', 'HDL', 'HSCRP', 'IGAP', 'K', 'LD', 'LDL', 'LYMPH', 'MCH', 'MCHC', 'MCV', 'MG', 'MONOC', 'NA', 'NONHDL', 'P', 'PLT', 'PROINR', 'PROPAT', 'RBC', 'RDWCV', 'TNEUT', 'TP', 'TRIG', 'TSH', 'VITDT', 'WBC']

Some markers were found to have better performance after log transformation:

['FER', 'GLU', 'HSCRP', 'TRIG', 'TSH']

For these markers, min_mu/max_mu in bayesian_hyperparameters.csv are bundled in log-space, and fit_patient()/fit_batch() log-transform measurements before fitting and back-transform mu/sigma to raw units after by default.

Measurement Selection

By default, measurements within 90 days of any neighbour are filtered out before fitting to avoid clusters of repeat draws (e.g. serial phlebotomy, acute illness) biasing the setpoint estimate. This can be disabled by passing filter_isolated_measurements=False to fit_patient() or fit_batch(), and the gap threshold can be adjusted via min_gap_days.

Scoring

We report RMSE, KS statistic, and KS quintile range. To enable comparison across markers with different scales, RMSE is also reported as RMSE_Scaled, which is RMSE normalized by the median intra-patient standard deviation. The theoretical lower bound for RMSE Scaled is 1. These are pre-calculated from the UW cohort and stored in perri/data/marker_intra_patient_std.csv.


Requirements

Python 3.9+.

To install the package in editable mode with all dependencies from pyproject.toml:

python3 -m venv .venv
source .venv/bin/activate
pip install -e .

Running the Examples

Sample data (synthetic, 3 patients × 43 markers × 12 visits) is bundled at perri/data/sample_data.csv.

Single-patient fit:

python perri/example_single.py --test_code HB --patient_id 3

Outputs the estimated setpoint, within-person SD, personalized 95% reference interval, and saves a plot to the perri/ directory.

Batch fit + cohort evaluation:

python perri/example_batch.py --test_code HB

Outputs RMSE, KS statistic, and KS quintile range across all patients for the specified marker.

Optional flags for both scripts:

Flag Default Description
--test_code HB Lab marker (see supported list above)
--patient_id 3 Patient ID — single-patient script only
--sex ALL ALL, M, or F

Custom Hyperparameters

To override the optimized defaults, pass a params dict to fit_patient() or fit_batch():

import perri as pri

# Start from the defaults and tweak one value
params = pri.get_default_params("HB")
params["log_lambda_"] = 0.5  # stronger recency weighting

result = pri.fit_patient(
    values=patient_df["result_value"].values,
    timestamps=patient_df["result_date"].values,
    params=params,
)

Or specify all five parameters from scratch:

result = pri.fit_patient(
    values=patient_df["result_value"].values,
    timestamps=patient_df["result_date"].values,
    params={
        "log_lambda_": 0.5,
        "min_mu": 5.0,
        "max_mu": 20.0,
        "min_sigma": 0.01,
        "max_sigma": 2.0,
    },
)

When params is provided, test_code is not required for parameter loading (but can still be passed for display purposes).


Interactive Streamlit App

Requires pip install streamlit plotly.

pip install -e ".[app]"
streamlit run perri/app.py

Metadata

Release files for perri 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for perri 0.5.0
File Size Uploaded Provenance
perri-0.5.0.tar.gz 48.2 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for perri 0.5.0
File Interpreter ABI Platform
perri-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 95.7 kB

Release files / perri-0.5.0.tar.gz

Download URL perri-0.5.0.tar.gz
Size 48.2 kB
Tags Source
SHA-256 checksum
How to use checksums
6c12bcaa4f24a36d248510339ddbd72b91c788d860c20198a246f43e76d55102
BLAKE2b-256 checksum
How to use checksums
64f00ab8467e4731f3cb951d100c6a4e1b2bddfbba5cf4c16d5b51d2d5eb3a3d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / perri-0.5.0-py3-none-any.whl

Download URL perri-0.5.0-py3-none-any.whl
Size 47.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0ce933dad1218b6af8144c7debd55e64e2163c9dcb0a1723a5906ed40842f392
BLAKE2b-256 checksum
How to use checksums
67825e9f99d8165a7433722523f310eda1a807091edb7013eeebd7cfebdba283
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Security for perri 0.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page