Python toolkit for CGM analysis with individually callable glycemic metrics and ML-ready feature extraction.
Project description
GlycoSignal
Python library for CGM data analysis — individually callable glycemic metrics, day/sliding-window segmentation, and ML-ready feature matrices.
pip install GlycoSignal
Quick start
import glycosignal as gs
df = gs.load_csv("cgm.csv")
df = gs.clean_cgm(df)
# Individual metrics
gs.mean_glucose(df) # 138.5
gs.time_in_range_percent(df, low=70, high=180) # 93.1
# Segment → feature matrix (the standard pipeline)
segs = gs.create_day_segments(df) # 24 h, midnight anchor
X = gs.build_feature_map(segs.windows) # 32 features × n_days
Input format
Two required columns; everything else is auto-detected (case-insensitive).
| Column | Required | Recognized aliases |
|---|---|---|
Timestamp |
Yes | time, datetime, date_time, date |
Glucose |
Yes | Glucose Value (mg/dL), gl, sgv, glucose_mg_dl, bg |
subject |
Multi-subject only | id, ptid, patient_id, subjectid |
# Override auto-detection
df = gs.load_csv("data.csv", timestamp_col="time_utc", glucose_col="bg_mg_dl")
# Multiple subjects — one file with subject column
df = gs.io.load_cgm_file("all.csv", subject_col="ptid")
# Multiple subjects — one CSV per subject in a folder
df = gs.io.load_cgm_folder("data/subjects/")
Data segmentation
Both functions return WindowResult(windows, metadata). The windows DataFrame flows directly into build_feature_map().
Daily segments
from glycosignal import windows
segs = windows.create_day_segments(df) # midnight–midnight (default)
segs = windows.create_day_segments(df, anchor_time="08:00") # 8 AM–8 AM
segs = windows.create_day_segments(df, anchor_time="08:00",
min_fraction=0.7, # drop days < 70 % coverage
group_col="subject") # multi-subject
print(segs.metadata)
# {'n_groups': 1, 'n_valid_windows': 7, 'n_discarded_partial_days': 0, ...}
Sliding windows
result = windows.create_sliding_windows(df, window_hours=6, step_hours=1)
result = windows.create_sliding_windows(df, window_hours=12, step_hours=12,
anchor_time="08:00")
result = windows.create_sliding_windows(df, window_hours=24, overlap_hours=12)
result = windows.create_sliding_windows(df, window_hours=24, step_hours=6,
group_col="subject")
Key parameters: window_hours, step_hours, anchor_time, min_fraction (default 0.0 — keep all windows), group_col, interpolate, max_gap_points.
Output
The windows DataFrame is long-format — one row per (window, time-point):
window_id |
subject |
date |
Timestamp |
Glucose |
|---|---|---|---|---|
S01_2023-01-02 |
S01 | 2023-01-02 | 2023-01-02 00:00 | 112.4 |
Non-midnight anchors append _HHMM to the window ID (e.g. S01_2023-01-02_0800).
Saving as wide-format CSV
wide = windows.pivot_windows_wide(segs.windows)
wide.to_csv("segments.csv", index=False)
# → columns: date | subject | 00:00 | 00:05 | … | 23:55
# For non-midnight anchor (e.g. "08:00"): 08:00 | … | 23:55 | 00:00 | … | 07:55
Glycemic metrics
Every metric is a standalone function. See the full metric reference for all formulas.
from glycosignal import metrics
# Core
metrics.mean_glucose(df) # 138.5
metrics.median_glucose(df)
metrics.std_glucose(df)
metrics.cv(df) # 17.7 %
metrics.time_in_range_percent(df, low=70, high=180) # 93.1 %
metrics.time_above_range(df, threshold=180)
metrics.time_below_range(df, threshold=70)
# Variability
metrics.mage(df) # 27.0
metrics.j_index(df)
metrics.conga(df)
metrics.modd(df)
metrics.grade(df)
# Risk indices
metrics.lbgi(df)
metrics.hbgi(df)
metrics.adrr(df)
metrics.gri(df) # 7.2
# Grouped helpers — return dicts
metrics.basic_stats(df) # mean, median, min, max, q1, q3
metrics.variability_metrics(df) # sd, cv, j_index, mage
metrics.risk_indices(df) # lbgi, hbgi, adrr, gri
metrics.summary_dict(df) # all of the above combined
Performance tip — call prepare() once when computing many metrics on the same data:
from glycosignal.schemas import prepare
p = prepare(df)
metrics.mean_glucose(p); metrics.cv(p); metrics.lbgi(p)
Feature matrices
from glycosignal import windows, features
segs = windows.create_day_segments(df)
X = features.build_feature_map(segs.windows) # 32 features × n_windows
# Subset
X = features.build_feature_map(segs.windows,
feature_names=["mean_glucose", "cv", "tir_70_180_pct", "mage", "lbgi"])
# Single window → dict
features.build_feature_vector(window_df, feature_names=["mean_glucose", "cv"])
# List of DataFrames (one per subject)
features.build_feature_table([df_s01, df_s02], record_ids=["S01", "S02"])
Feature registry
gs.list_features() # all 32 names
gs.list_features(category="risk") # ['adrr', 'gri', 'hbgi', 'lbgi']
gs.get_feature_metadata() # DataFrame: name | description | category
gs.get_feature("gri").description # 'Glucose Risk Index (Klonoff et al. 2023)'
# Register a custom feature
from glycosignal.registry import DEFAULT_REGISTRY
DEFAULT_REGISTRY.register(name="my_metric", func=my_fn,
description="...", category="variability")
Preprocessing
from glycosignal import preprocessing
df = preprocessing.clean_cgm(df) # drop NaN, sort, enforce positive
report = preprocessing.validate_cgm(df) # structured quality report
gaps = preprocessing.detect_gaps(df) # DataFrame of gap intervals
df = preprocessing.resample_cgm(df, freq="5min") # regular grid
df = preprocessing.interpolate_cgm(df, method="pchip",
max_gap_points=12)
df = preprocessing.convert_units(df, from_unit="mmol/L",
to_unit="mg/dL")
Event detection
Returns a DataFrame with start_time, end_time, duration_minutes, event_type.
from glycosignal import detect
detect.detect_hypoglycemia(df, threshold=70, min_duration_minutes=15)
detect.detect_hyperglycemia(df, threshold=180, min_duration_minutes=15)
detect.detect_nocturnal_events(df, start_hour=0, end_hour=6)
detect.detect_postprandial_excursions(df, rise_threshold=50)
Plotting
All functions return (fig, ax) and never call plt.show().
from glycosignal import plotting
fig, ax = plotting.plot_glucose_timeseries(df, subject="P001")
fig, ax = plotting.plot_daily_overlay(df)
fig, ax = plotting.plot_agp(df)
fig, ax = plotting.plot_histogram(df)
fig.savefig("output.png", dpi=150)
CLI
glycosignal summary data.csv
glycosignal windows data.csv --window-hours 24 --overlap-hours 0 --output windows.csv
glycosignal features windows.csv --output features.csv
glycosignal features windows.csv --features mean_glucose,cv,lbgi,gri
glycosignal list-features
glycosignal list-features --category risk
License
MIT. Copyright (c) 2024 Jiafeng Song. See LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file glycosignal-0.2.0.tar.gz.
File metadata
- Download URL: glycosignal-0.2.0.tar.gz
- Upload date:
- Size: 75.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b890fc22d1d79d191621786c53c573243775cd3691cdef594ad69ba4f447677d
|
|
| MD5 |
88f75b48cf162b0c3d15733abb3c27ce
|
|
| BLAKE2b-256 |
192c8f733a755043f04c77edebc6fef4d54ac79b7abc5e5d6f576b742a31e0fc
|
File details
Details for the file glycosignal-0.2.0-py3-none-any.whl.
File metadata
- Download URL: glycosignal-0.2.0-py3-none-any.whl
- Upload date:
- Size: 50.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
601a17d884c2f0397e14bae3a48f6cb16012333dd5d9524805eee62caf620b11
|
|
| MD5 |
844826a892684e8436c7dea3b9dca3c5
|
|
| BLAKE2b-256 |
3fd0a1431638a646b779a277e86db23676834cdeaa57ac92e223c24781fc3534
|