Statistical analysis library for Sugar Sugar study results.
It implements Section 7 (Statistical Analysis Plan) of the study design (Human Prediction of Next-Hour Glucose from Prior CGM Context).
The package is split into five stages so each part can be imported as a library module, exercised in a Jupyter notebook, or run end-to-end via the CLI.
| Stage | Module | What it does |
|---|---|---|
| 1. Data gathering | sugar_data_processing.gathering |
Load prediction_statistics.csv, explode rounds, build person-level table |
| 2. Data verification | sugar_data_processing.verification |
Schema / structural checks + demographic & metric quality flags |
| 3. Statistical tests | sugar_data_processing.statistics |
H1–H5 (§7.3–7.4) on person-level MAE |
| 4. Data comparison | sugar_data_processing.comparison |
Human MAE vs GlucoBench / literature bands (§7.5) |
| 5. Output | sugar_data_processing.output |
PNG figures + one merged markdown / JSON / explorer.html |
| 6. AI scoring | sugar_data_processing.ai |
Rebuild the 3-hour game window, score models, fold into the same report |
Orchestration: sugar_data_processing.pipeline.run_analysis.
| Hypothesis | Question | Test path |
|---|---|---|
| H1 | PwD vs non-PwD MAE (category first, then generic vs own) | Shapiro → t-test / Mann–Whitney |
| H2 | CGM vs non-CGM MAE (category first, then generic vs own) | Shapiro → t-test / Mann–Whitney |
| H3 | Diabetes duration (months) vs MAE, generic and own | Pearson / Spearman + log exploratory |
| H4 | CGM experience (months) vs MAE, generic and own | Pearson / Spearman + log exploratory |
| H5 | Own vs generic MAE (paired) | Shapiro on diffs → paired t / Wilcoxon |
| H6 | Human vs baseline models | Same 3-hour windows; persistence / linear / GluMind (torch + sibling test_model) |
Person-level MAE (mean of round MAEs) is the analysis unit so repeated rounds from the same participant do not inflate degrees of freedom.
| Input | Path / source | Role |
|---|---|---|
| Real export | data/raw/prediction_statistics.csv (gitignored) |
sugar-sugar app statistics export |
| Synthetic fixture | data/fixtures/synthetic_prediction_statistics.csv |
Committed demo cohort sized for H1–H5 |
| CLI override | --csv /path/to/prediction_statistics.csv |
Explicit file, any location |
Required columns (enforced on load + re-checked in verification):
study_id, run_id, timestamp, format, is_example_data, uses_cgm,
cgm_duration_years, diabetic, diabetes_duration, rounds_played,
overall_mae_mgdl, overall_rmse_mgdl, overall_mape_pct, per_round_metrics
Optional current-app columns (kept when present):
round_context, generic_intervention, challenge_unknown,
challenge_unknown_pct, paper_mention, paper_full_name, diabetic_type,
predicted_values, real_values, prediction_times
cgm_duration_years may be a bare year (legacy) or value,unit (6,months).
Per-round is_example_data / data_source_name (in per_round_metrics or
round_context) decide generic vs own — the run-level source is only the last
dataset of that session. Email / location are dropped; personal upload filenames
are redacted to own_upload.
- Primary (H1–H4): ≥6 generic segments (format A, or odd rounds in mixed C)
- Own-data: ≥6 own segments (format B, or even rounds in mixed C)
- H5: participants meeting both thresholds
src/sugar_data_processing/
gathering/ # stage 1 — load CSV, explode rounds, participant table
verification/ # stage 2 — schema checks + quality flags
statistics/ # stage 3 — H1–H5 tests + effect sizes
comparison/ # stage 4 — GlucoBench / literature bands
output/ # stage 5 — plots + human markdown/JSON/HTML
ai/ # sequence export + model ingest + AI report
fixtures/ # synthetic CSV generator
pipeline.py # run_analysis() wires stages 1→5 (+ AI export)
cli.py # Typer entry point
notebooks/
study_analysis.ipynb # thin walkthrough over the library (same paths as CLI)
data/
raw/ # drop real prediction_statistics.csv here (gitignored)
fixtures/ # committed synthetic demo data
processed/ # parquet/csv intermediates (written by output stage)
output/
figures/ # PNGs
reports/ # analysis_report.md + explorer.html + milestone.html
tests/ # pytest (real synthetic data, no mocks)
docs/
analysis-plan.md # study design §7 → module map
uv syncFor the notebook (dev group includes Jupyter):
uv sync --group devsdp is the short CLI name (uv run sugar-data-processing is the same).
The public site does not serve the research CSV. Pull it over SSH, scrub contact
columns into data/raw/ (gitignored), then run H1–H5.
Once per machine
uv sync
cp .env.template .envEdit .env (never commit it):
SUGAR_REMOTE— the sameuser@host:/pathyou alreadysshto (the CSV, or thedata/inputdirectory that contains it)SUGAR_SSH_IDENTITY— the same key you pass tossh -i, if you use one
Each time you want fresh online numbers
uv run sdp fetch --analyzeThat is the whole online path: scp → blank email / location /
paper_full_name → write data/raw/prediction_statistics.csv → reports.
Pull only (no tests):
uv run sdp fetchRe-run H1–H5 on the last pulled CSV (no SSH):
uv run sdp analyzeThen open the files in Where the numbers are.
uv run sdp make-fixture
uv run sdp analyze --fixtureuv run sdp fetch --sibling --analyzeOr:
uv run sdp analyze --csv ../sugar-sugar/data/input/prediction_statistics.csvResolution order for analyze without --csv / --fixture:
data/raw/prediction_statistics.csvif present- else fixture (with a yellow warning)
| File | What it is |
|---|---|
output/reports/analysis_report.md |
Merged report: human H1–H5, then same-person human vs AI by task |
output/reports/explorer.html |
Tabs: Overview, Human, AI, People (actual / human / AI lines) |
output/reports/milestone.html |
Milestone page: human participants only (Overview + Human) |
output/reports/analysis_report.json |
Machine-readable human + AI payload |
data/processed/ai/prediction_points.csv |
Per-point sequences for post-factum model scoring |
output/figures/*.png |
Plots (also copied under output/reports/figures/) |
data/processed/participants.csv |
Person-level analysis table |
Export sequences only (no full report rewrite):
uv run sdp export-aiAfter a model writes predictions (join keys study_id, run_id, round_number, point_index):
uv run sdp ingest-ai --predictions path/to/model.csvevaluation_mode is post_factum today (replay saved games). in_place is reserved for scores collected during the live game.
uv sync --group dev
uv run sugar-data-processing make-fixture
uv run jupyter notebook notebooks/study_analysis.ipynbSelect the sugar-data-processing (.venv) kernel. The notebook only calls library
APIs (prepare_session, gathering, verification, statistics, comparison, output).
It writes to the same place as the CLI: output/reports/ (no notebook-specific
report directory).
from pathlib import Path
from sugar_data_processing import run_analysis
result = run_analysis(
Path("data/fixtures/synthetic_prediction_statistics.csv"),
Path("output"),
)
print(result.verification.passed, result.report_path)Or stage-by-stage:
from pathlib import Path
import polars as pl
from sugar_data_processing.gathering import load_prediction_statistics, build_participant_table
from sugar_data_processing.verification import verify_dataset
from sugar_data_processing.statistics import run_all_hypotheses
from sugar_data_processing.comparison import benchmark_context
from sugar_data_processing.output import write_report
csv = Path("data/fixtures/synthetic_prediction_statistics.csv")
runs = load_prediction_statistics(csv)
participants = build_participant_table(runs)
verification = verify_dataset(runs, participants)
suite = run_all_hypotheses(participants)
eligible = participants.filter(pl.col("eligible_primary"))
benchmarks = benchmark_context(eligible if eligible.height > 0 else participants)
write_report(
runs=runs,
participants=participants,
suite=suite,
benchmarks=benchmarks,
verification=verification,
output_dir=Path("output"),
source_csv=csv,
)| Stage | In-memory | On disk (via analyze / write_report) |
|---|---|---|
| Gathering | runs, participants Polars frames |
— |
| Verification | VerificationReport (schema + quality) |
Embedded in report JSON / markdown §6 |
| Statistics | HypothesisSuite (H1–H5) |
Report §3–4 + JSON hypotheses |
| Comparison | BenchmarkContext |
Report §5 + JSON benchmarks |
| Output | report path | output/reports/analysis_report.*, explorer.html, output/figures/*, data/processed/* + data/processed/ai/ |
- Schema: required columns, non-empty IDs, format ∈ {A,B,C}, parseable
per_round_metrics, non-negative MAE,rounds_playedvs metrics length - Quality flags: implausible age/durations, flag mismatches, MAE IQR
outliers, short sessions, duplicate
run_id, below-threshold participants
High-severity schema issues set verification.schema_ok = False. Quality
flags are reported but do not alone fail verification (they inform the report).
uv run pytest- Models only see the 3-hour game window (24 visible points, left-padded to
128).
explorer.htmlPeople tab overlays actual CGM, the human line, and each AI forecast. - See
docs/analysis-plan.mdfor the §7 → module mapping and format conventions.