nutramilo-nis 1.1.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,47 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 Nutramilo Ltd. (EIK 207793581, Sofia, Bulgaria)
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
18
+
19
+ ────────────────────────────────────────────────────────────────────────────
20
+ ATTRIBUTION REQUIREMENT (Apache License §4(c) — required preservation of
21
+ NOTICE file):
22
+
23
+ When using this package in research, clinical software, mobile apps, or any
24
+ derivative work, you MUST cite:
25
+
26
+ Inkov, I. et al. (2026). "Nutramilo Insulin Score (NIS): An Open,
27
+ Macronutrient-Derived Algorithm for Predicting Postprandial
28
+ Insulinaemic Response — Development and Validation Against the Holt
29
+ Food Insulin Index." International Journal of Medical Reviews and
30
+ Case Reports, Vol. X(Y), pp. ZZ-ZZ. DOI: 10.XXXX/ijmrcr.2026.NIS
31
+
32
+ ────────────────────────────────────────────────────────────────────────────
33
+ TRADEMARK NOTICE:
34
+
35
+ "NIS™", "Nutramilo Insulin Score™", and "Nutramilo™" are trademarks of
36
+ Nutramilo Ltd. The trademark rights are NOT granted under this Apache 2.0
37
+ license. Use of these marks in commercial products, marketing, or branding
38
+ requires written permission from Nutramilo Ltd. (legal@nutramilo.com).
39
+
40
+ You ARE permitted to use the marks in:
41
+ - Academic citations and references to this algorithm
42
+ - Bug reports and forks (with clear disclaimer)
43
+ - Educational material describing the algorithm
44
+
45
+ You are NOT permitted to use the marks to:
46
+ - Brand a competing or derivative product as "NIS-powered" without licence
47
+ - Imply endorsement by Nutramilo Ltd.
@@ -0,0 +1,27 @@
1
+ Nutramilo Insulin Score (NIS) — Python Reference Implementation
2
+ Copyright 2026 Nutramilo Ltd. (Sofia, Bulgaria, EIK 207793581)
3
+
4
+ This product includes software developed at Nutramilo Ltd.
5
+ Licensed under the Apache License, Version 2.0.
6
+
7
+ Required citation when used in research or derivative work:
8
+
9
+ Inkov, I. et al. (2026). "Nutramilo Insulin Score (NIS): An Open,
10
+ Macronutrient-Derived Algorithm for Predicting Postprandial
11
+ Insulinaemic Response — Development and Validation Against the
12
+ Holt Food Insulin Index." Int J Med Rev Case Rep.
13
+ DOI: 10.XXXX/ijmrcr.2026.NIS
14
+
15
+ Methodological lineage:
16
+ - Holt SHA, Brand-Miller JC, Petocz P (1997). An insulin index of foods:
17
+ the insulin demand generated by 1000-kJ portions of common foods.
18
+ Am J Clin Nutr 66:1264-76. PMID 9356547.
19
+ - Bell KJ (2014). Algorithms to improve the prediction of postprandial
20
+ insulinaemia in response to common foods (PhD thesis, U. Sydney).
21
+ - Bao J et al. (2009). Prediction of postprandial glycemia and
22
+ insulinemia in lean, young, healthy adults: glycemic load compared
23
+ with carbohydrate content alone. Am J Clin Nutr 90:986-92. PMID 19710196.
24
+
25
+ Trademark: "NIS™", "Nutramilo Insulin Score™" and "Nutramilo™" are
26
+ trademarks of Nutramilo Ltd., applied for at EUIPO. Use of marks restricted
27
+ under separate licence (see LICENSE).
@@ -0,0 +1,275 @@
1
+ Metadata-Version: 2.4
2
+ Name: nutramilo-nis
3
+ Version: 1.1.5
4
+ Summary: Nutramilo Insulin Score (NIS) — open algorithm for predicting postprandial insulin response from macronutrient composition.
5
+ Author-email: Ivan Inkov <inkov@nutramilo.com>, Nutramilo Research <research@nutramilo.com>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://nutramilo.com/science
8
+ Project-URL: Repository, https://github.com/nutramilo/nutramilo-nis
9
+ Project-URL: Documentation, https://nutramilo.com/science/nis
10
+ Project-URL: Paper, https://doi.org/10.XXXX/ijmrcr.2026.NIS
11
+ Project-URL: Issues, https://github.com/nutramilo/nutramilo-nis/issues
12
+ Keywords: insulin,postprandial,glycemic,nutrition,metabolism,food insulin index,NIS,diabetes,nutrigenomics,biomedical
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Healthcare Industry
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: Apache Software License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
24
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ License-File: NOTICE
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7; extra == "dev"
31
+ Requires-Dist: pytest-cov>=4; extra == "dev"
32
+ Requires-Dist: ruff>=0.4; extra == "dev"
33
+ Provides-Extra: validation
34
+ Requires-Dist: numpy>=1.24; extra == "validation"
35
+ Requires-Dist: pandas>=2.0; extra == "validation"
36
+ Requires-Dist: scipy>=1.10; extra == "validation"
37
+ Dynamic: license-file
38
+
39
+ # nutramilo-nis
40
+
41
+ [![PyPI version](https://img.shields.io/pypi/v/nutramilo-nis.svg)](https://pypi.org/project/nutramilo-nis/)
42
+ [![Python ≥ 3.9](https://img.shields.io/badge/python-≥3.9-green.svg)](https://python.org)
43
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
44
+ [![DOI](https://img.shields.io/badge/DOI-10.XXXX%2Fijmrcr.2026.NIS-orange.svg)](https://doi.org/10.XXXX/ijmrcr.2026.NIS)
45
+ [![PyPI downloads](https://img.shields.io/pypi/dm/nutramilo-nis.svg)](https://pypi.org/project/nutramilo-nis/)
46
+ [![Status: exploratory-methodology](https://img.shields.io/badge/status-exploratory--methodology-yellow.svg)](#)
47
+ [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-purple.svg)](https://github.com/astral-sh/ruff)
48
+
49
+ > **Reference implementation of the Nutramilo Insulin Score (NIS™)** —
50
+ > an open, **exploratory** macronutrient-derived insulinogenic surrogate
51
+ > computable from any meal composition. Trained on the Holt–Bell–Bao
52
+ > Food Insulin Index cohort (n = 147) and evaluated on a strictly
53
+ > out-of-sample subset (n = 25).
54
+ >
55
+ > ⚠️ **Positioning.** NIS v1.1.5 is an **exploratory methodology study**,
56
+ > not an externally validated predictive model. A prospective CGM trial
57
+ > is the planned confirmatory step (see manuscript §4.2 + Part II).
58
+
59
+ ---
60
+
61
+ ## ✨ Why NIS?
62
+
63
+ | Property | Holt Food Insulin Index (FII) | **NIS v1.1.5** |
64
+ |---|---|---|
65
+ | In-vivo insulin AUC measurement required | ✅ Yes | ❌ No — **composition only** |
66
+ | Suitable for mobile apps & CGM-less use | ❌ No | ✅ Yes |
67
+ | Frozen, versioned coefficients | ❌ No | ✅ Yes (Apache 2.0, since v1.0) |
68
+ | Mandatory citation in derivatives | ❌ No | ✅ Yes (NOTICE clause) |
69
+ | Open dataset (SHA-256-verified) | ❌ No | ✅ Yes (Zenodo on release) |
70
+ | Out-of-sample evaluation reported | Partial | ✅ Yes (n = 25 hold-out) |
71
+ | Externally validated on fresh CGM cohort | n/a | ❌ **Not yet** — see Part II |
72
+
73
+ **Headline metrics (v1.1.5 on n = 25 strictly out-of-sample subset):**
74
+
75
+ | Pipeline | OOS MAE | 95 % bootstrap CI | Pearson r |
76
+ |---|---|---|---|
77
+ | v1.0.0 baseline | 17.49 | [14.22, 21.12] | 0.778 |
78
+ | **v1.1.5 full** | **10.20** | **[7.06, 13.70]** | **0.826** |
79
+
80
+ Paired Wilcoxon (n = 25 OOS): **W = 55.5, z = −2.879, p = 0.00399**.
81
+ Bootstrap 95 % CIs do not overlap. Bland–Altman LoA on the OOS subset
82
+ is **±37.6 %-points** — wide enough that NIS is **best used for
83
+ relative meal comparison within the same subject**, not for absolute
84
+ insulin AUC prediction.
85
+
86
+ ## 📦 Install
87
+
88
+ ```bash
89
+ pip install nutramilo-nis
90
+ ```
91
+
92
+ Optional extras:
93
+
94
+ ```bash
95
+ pip install "nutramilo-nis[validation]" # numpy / pandas / scipy for re-running the regression notebook
96
+ pip install "nutramilo-nis[dev]" # pytest, ruff, coverage
97
+ ```
98
+
99
+ ## 🚀 Quick start — 30 seconds
100
+
101
+ ```python
102
+ from nutramilo_nis import compute_nis
103
+
104
+ # A balanced lunch: salmon + quinoa + broccoli
105
+ result = compute_nis(
106
+ carbs_g=35,
107
+ protein_g=30,
108
+ fat_g=15,
109
+ fiber_g=8,
110
+ )
111
+
112
+ print(result.nis_percent) # → 65.0
113
+ print(result.tier) # → "Medium"
114
+ print(result.tier_color) # → "#F59E0B"
115
+ print(result.contributions) # → {"carbs": 9.65, "protein": 3.36, ...}
116
+ print(result.citation) # → "Inkov I, et al. (2026). NIS … IJMRCR …"
117
+ ```
118
+
119
+ JSON-serialisable for APIs:
120
+
121
+ ```python
122
+ import json
123
+ print(json.dumps(result.to_dict(), indent=2))
124
+ ```
125
+
126
+ ## 🧪 Worked examples (from the paper)
127
+
128
+ > Computed with default `mixed` source-type and calibration **on**
129
+ > (slope = 0.7275, intercept = 8.111). See `tests/test_nis_v1_1_*.py`
130
+ > for the full pinned numerical regression suite.
131
+
132
+ | Plate | C / P / F / Fb (g) | NIS % | Tier |
133
+ |---|---|---|---|
134
+ | White bread, lean cheese, butter | 50 / 12 / 8 / 1 | **77** | High |
135
+ | Salmon + quinoa + broccoli | 35 / 30 / 15 / 8 | **65** | Medium |
136
+ | Plain Greek yogurt + walnuts | 8 / 18 / 14 / 2 | **40** | Moderate |
137
+ | Black bean & spinach bowl | 30 / 14 / 6 / 13 | **48** | Moderate |
138
+ | Avocado-omelette + side salad | 6 / 18 / 22 / 5 | **27** | Low |
139
+
140
+ ## 📐 Algorithm (5-step pipeline, v1.1.5)
141
+
142
+ 1. **Per-1000-kJ normalisation** using Atwater factors (17·C + 17·P + 37·F kJ/g).
143
+ 2. **Linear regression layer** — independent OLS on the frozen
144
+ `HoltBellBao_v1_frozen_2026.csv` cohort (n = 147 foods).
145
+ Coefficients exposed as `NIS_COEFFICIENTS`:
146
+ `carbs = +1.61 · protein = +0.66 · fat = +1.20 · fiber = −1.14` (per 1000 kJ).
147
+ Protein and fat scaled by **source-type multipliers** (plant/mixed/animal:
148
+ protein 0.55/1.00/1.30, fat 0.45/1.00/1.25).
149
+ 3. **Pure-fat extrapolation guard** — when `(net-carb + protein) / 1000 kJ < 5 g`
150
+ the regression output is scaled by `0.15×` (energy-normalised, serving-
151
+ invariant since v1.1.1).
152
+ 4. **Cross-cohort linear calibration** — `obs ≈ 0.7275 × pct + 8.111`
153
+ (fit on the n = 63 cross-cohort validation set; opt-out via
154
+ `apply_calibration=False`).
155
+ 5. **Optional Holt cross-track + clinical-tier floor**, then
156
+ **`Final NIS = max(regression_cal, holt, floor)`**, clamped [0, 100].
157
+
158
+ > **Note on validation framing.** The n = 147 training cohort and the
159
+ > n = 63 cross-cohort calibration set share Holt 1997 foods (derivational
160
+ > overlap, see manuscript §4.3 L1). All inferential claims in v1.1.5 are
161
+ > therefore restricted to the **n = 25 strictly out-of-sample subset**
162
+ > (Bao 2011, Nilsson 2004, Boirie 1997, Trichopoulou 2003, Sahyoun 2008).
163
+
164
+ ## 📘 API reference
165
+
166
+ ### `compute_nis(carbs_g, protein_g, fat_g, fiber_g=0.0, *, insulin_impact_tier="low", il_total_g=None) → NisResult`
167
+
168
+ | Argument | Type | Default | Description |
169
+ |---|---|---|---|
170
+ | `carbs_g` | `float` | — | Net carbohydrate grams |
171
+ | `protein_g` | `float` | — | Protein grams |
172
+ | `fat_g` | `float` | — | Total fat grams |
173
+ | `fiber_g` | `float` | `0.0` | Dietary fibre grams (blunts response) |
174
+ | `insulin_impact_tier` | `Literal["low","medium","high"]` | `"low"` | Clinical floor band |
175
+ | `il_total_g` | `Optional[float]` | `None` | Pre-computed Insulin Load (overrides Holt track) |
176
+
177
+ ### `NisResult` (frozen `dataclass`)
178
+
179
+ | Field | Type | Description |
180
+ |---|---|---|
181
+ | `nis_percent` | `float` | Final NIS, 0–100 |
182
+ | `tier` | `str` | `"Low"` / `"Moderate"` / `"Medium"` / `"High"` / `"Very high"` |
183
+ | `tier_color` | `str` | Hex colour for UI (Tailwind-compatible) |
184
+ | `piru` | `float` | Predicted Insulin Response Unit (regression layer raw) |
185
+ | `regression_pct` | `float` | Pure regression output (0–100) |
186
+ | `holt_pct` | `float` | Holt cross-track output (0–100) |
187
+ | `tier_floor_pct` | `float` | Clinical-tier floor applied |
188
+ | `contributions` | `dict[str, float]` | Per-macro absolute contribution to PIRU |
189
+ | `nis_version` | `str` | Frozen version (e.g. `"1.0.0"`) |
190
+ | `coefficients_date` | `str` | Date coefficients were regressed (ISO) |
191
+ | `citation` | `str` | Required academic citation |
192
+
193
+ Use `.to_dict()` → JSON-serialisable.
194
+
195
+ ## 🔬 Reproducibility
196
+
197
+ | Artifact | Location |
198
+ |---|---|
199
+ | Frozen training dataset | Zenodo DOI [10.5281/zenodo.XXXXXX](https://zenodo.org/) |
200
+ | Regression notebook | [`notebooks/independent_regression_v2.ipynb`](https://github.com/nutramilo/nutramilo-nis) |
201
+ | SHA-256 of v1.0 dataset | `b41eb157661b2d8ad0…` (paper § 2.2) |
202
+ | Unit tests | `pytest -q` — 13 tests, all should pass |
203
+ | Figures (PNG + TIFF 300dpi) | Paper supplement, Figs 1–6 |
204
+
205
+ ## 📖 Paper
206
+
207
+ > **Inkov, I., et al.** (2026). "Nutramilo Insulin Score (NIS): An Open,
208
+ > Macronutrient-Derived Algorithm for Predicting Postprandial Insulinaemic
209
+ > Response — Development and Validation Against the Holt Food Insulin Index."
210
+ > *International Journal of Medical Reviews and Case Reports*, in press.
211
+ > DOI: [10.XXXX/ijmrcr.2026.NIS](https://doi.org/10.XXXX/ijmrcr.2026.NIS)
212
+
213
+ **Pre-print:** [medRxiv 2026.02.XXXXXX](https://medrxiv.org/)
214
+
215
+ If you use NIS in research, **please cite the paper** (Apache 2.0 + NOTICE).
216
+
217
+ ## ™ Trademark notice
218
+
219
+ `NIS™`, `Nutramilo Insulin Score™`, and `Nutramilo™` are trademarks of
220
+ **International Sci Ink Press Ltd EOOD** (EIK 205414288, Sofia, Bulgaria),
221
+ filed at the EUIPO.
222
+
223
+ The Apache 2.0 licence covers the **code** — *not* the trademarks. For
224
+ commercial use of the marks in branding/marketing, contact
225
+ [legal@nutramilo.com](mailto:legal@nutramilo.com).
226
+
227
+ ## ⚖️ Disclaimer & regulatory framing
228
+
229
+ NIS is intended for **educational and research** purposes.
230
+ It is **not** a medical device, does **not** diagnose any disease, and should
231
+ **not** replace professional clinical judgement.
232
+
233
+ | Framework | Classification |
234
+ |---|---|
235
+ | EU MDR 2017/745 | **Not a medical device** |
236
+ | EU AI Act 2024/1689 | **Limited risk** (Art. 50 — transparency only) |
237
+
238
+ ## 🏗️ Roadmap (semver-frozen)
239
+
240
+ - **v1.x** — patch fixes only; coefficients **never** change.
241
+ - **v2.0.x** — prospective CGM trial re-regression (manuscript Part II,
242
+ pre-registered at OSF before data collection).
243
+
244
+
245
+ | GDPR | No personal data processed by the library itself |
246
+
247
+ ## 🤝 NIS vs DIL — different questions, different units
248
+
249
+ NIS and DIL are **complementary, not interchangeable**:
250
+
251
+ | | **NIS** (per-meal) | **DIL** (per-meal & daily) |
252
+ |---|---|---|
253
+ | Question | *"How insulinogenic is THIS meal compared to pure glucose?"* | *"How many grams of carb-equivalent insulin load did I eat today?"* |
254
+ | Output | 0–100 % (intensity score) | grams of carb-equivalent (load) |
255
+ | Use-case | Compare two meals; rank foods on a phone; coach single-meal swaps | Daily budget tracking; weekly trend monitoring; clinical dosing-adjacent reasoning |
256
+ | Formula | 5-step pipeline with source-aware multipliers, pure-fat guard, cross-cohort calibration | `0.69 × protein + max(carbs − fiber, 0)` per food, summed across the day |
257
+ | Validation | n = 25 OOS Pearson r = 0.83, MAE = 10.2 | OLS-stable across Ridge/LASSO; food-level coefficient frozen at 0.69 since 2026-02-10 |
258
+ | In this SDK | `compute_nis(...)` | not bundled — see `nutramilo-health` package or `services/dil_formula.py` in the Nutramilo platform |
259
+
260
+ If you need both layers (per-meal NIS for ranking + daily DIL for budget),
261
+ combine `compute_nis` here with the open `compute_dil` formula:
262
+ `DIL_g = max(0, 0.69·protein + max(0, carbs − fiber))`.
263
+
264
+ ## 📜 Licence
265
+
266
+ [Apache 2.0](LICENSE) — see [`NOTICE`](NOTICE) for the mandatory citation clause.
267
+
268
+ ## 💬 Contact
269
+
270
+ | For | Email |
271
+ |---|---|
272
+ | Research collaboration | research@nutramilo.com |
273
+ | Trademark / commercial licensing | legal@nutramilo.com |
274
+ | Bug reports & feature requests | [github.com/nutramilo/nutramilo-nis/issues](https://github.com/nutramilo/nutramilo-nis/issues) |
275
+ | General product info | https://nutramilo.com/science |
@@ -0,0 +1,237 @@
1
+ # nutramilo-nis
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/nutramilo-nis.svg)](https://pypi.org/project/nutramilo-nis/)
4
+ [![Python ≥ 3.9](https://img.shields.io/badge/python-≥3.9-green.svg)](https://python.org)
5
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
6
+ [![DOI](https://img.shields.io/badge/DOI-10.XXXX%2Fijmrcr.2026.NIS-orange.svg)](https://doi.org/10.XXXX/ijmrcr.2026.NIS)
7
+ [![PyPI downloads](https://img.shields.io/pypi/dm/nutramilo-nis.svg)](https://pypi.org/project/nutramilo-nis/)
8
+ [![Status: exploratory-methodology](https://img.shields.io/badge/status-exploratory--methodology-yellow.svg)](#)
9
+ [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-purple.svg)](https://github.com/astral-sh/ruff)
10
+
11
+ > **Reference implementation of the Nutramilo Insulin Score (NIS™)** —
12
+ > an open, **exploratory** macronutrient-derived insulinogenic surrogate
13
+ > computable from any meal composition. Trained on the Holt–Bell–Bao
14
+ > Food Insulin Index cohort (n = 147) and evaluated on a strictly
15
+ > out-of-sample subset (n = 25).
16
+ >
17
+ > ⚠️ **Positioning.** NIS v1.1.5 is an **exploratory methodology study**,
18
+ > not an externally validated predictive model. A prospective CGM trial
19
+ > is the planned confirmatory step (see manuscript §4.2 + Part II).
20
+
21
+ ---
22
+
23
+ ## ✨ Why NIS?
24
+
25
+ | Property | Holt Food Insulin Index (FII) | **NIS v1.1.5** |
26
+ |---|---|---|
27
+ | In-vivo insulin AUC measurement required | ✅ Yes | ❌ No — **composition only** |
28
+ | Suitable for mobile apps & CGM-less use | ❌ No | ✅ Yes |
29
+ | Frozen, versioned coefficients | ❌ No | ✅ Yes (Apache 2.0, since v1.0) |
30
+ | Mandatory citation in derivatives | ❌ No | ✅ Yes (NOTICE clause) |
31
+ | Open dataset (SHA-256-verified) | ❌ No | ✅ Yes (Zenodo on release) |
32
+ | Out-of-sample evaluation reported | Partial | ✅ Yes (n = 25 hold-out) |
33
+ | Externally validated on fresh CGM cohort | n/a | ❌ **Not yet** — see Part II |
34
+
35
+ **Headline metrics (v1.1.5 on n = 25 strictly out-of-sample subset):**
36
+
37
+ | Pipeline | OOS MAE | 95 % bootstrap CI | Pearson r |
38
+ |---|---|---|---|
39
+ | v1.0.0 baseline | 17.49 | [14.22, 21.12] | 0.778 |
40
+ | **v1.1.5 full** | **10.20** | **[7.06, 13.70]** | **0.826** |
41
+
42
+ Paired Wilcoxon (n = 25 OOS): **W = 55.5, z = −2.879, p = 0.00399**.
43
+ Bootstrap 95 % CIs do not overlap. Bland–Altman LoA on the OOS subset
44
+ is **±37.6 %-points** — wide enough that NIS is **best used for
45
+ relative meal comparison within the same subject**, not for absolute
46
+ insulin AUC prediction.
47
+
48
+ ## 📦 Install
49
+
50
+ ```bash
51
+ pip install nutramilo-nis
52
+ ```
53
+
54
+ Optional extras:
55
+
56
+ ```bash
57
+ pip install "nutramilo-nis[validation]" # numpy / pandas / scipy for re-running the regression notebook
58
+ pip install "nutramilo-nis[dev]" # pytest, ruff, coverage
59
+ ```
60
+
61
+ ## 🚀 Quick start — 30 seconds
62
+
63
+ ```python
64
+ from nutramilo_nis import compute_nis
65
+
66
+ # A balanced lunch: salmon + quinoa + broccoli
67
+ result = compute_nis(
68
+ carbs_g=35,
69
+ protein_g=30,
70
+ fat_g=15,
71
+ fiber_g=8,
72
+ )
73
+
74
+ print(result.nis_percent) # → 65.0
75
+ print(result.tier) # → "Medium"
76
+ print(result.tier_color) # → "#F59E0B"
77
+ print(result.contributions) # → {"carbs": 9.65, "protein": 3.36, ...}
78
+ print(result.citation) # → "Inkov I, et al. (2026). NIS … IJMRCR …"
79
+ ```
80
+
81
+ JSON-serialisable for APIs:
82
+
83
+ ```python
84
+ import json
85
+ print(json.dumps(result.to_dict(), indent=2))
86
+ ```
87
+
88
+ ## 🧪 Worked examples (from the paper)
89
+
90
+ > Computed with default `mixed` source-type and calibration **on**
91
+ > (slope = 0.7275, intercept = 8.111). See `tests/test_nis_v1_1_*.py`
92
+ > for the full pinned numerical regression suite.
93
+
94
+ | Plate | C / P / F / Fb (g) | NIS % | Tier |
95
+ |---|---|---|---|
96
+ | White bread, lean cheese, butter | 50 / 12 / 8 / 1 | **77** | High |
97
+ | Salmon + quinoa + broccoli | 35 / 30 / 15 / 8 | **65** | Medium |
98
+ | Plain Greek yogurt + walnuts | 8 / 18 / 14 / 2 | **40** | Moderate |
99
+ | Black bean & spinach bowl | 30 / 14 / 6 / 13 | **48** | Moderate |
100
+ | Avocado-omelette + side salad | 6 / 18 / 22 / 5 | **27** | Low |
101
+
102
+ ## 📐 Algorithm (5-step pipeline, v1.1.5)
103
+
104
+ 1. **Per-1000-kJ normalisation** using Atwater factors (17·C + 17·P + 37·F kJ/g).
105
+ 2. **Linear regression layer** — independent OLS on the frozen
106
+ `HoltBellBao_v1_frozen_2026.csv` cohort (n = 147 foods).
107
+ Coefficients exposed as `NIS_COEFFICIENTS`:
108
+ `carbs = +1.61 · protein = +0.66 · fat = +1.20 · fiber = −1.14` (per 1000 kJ).
109
+ Protein and fat scaled by **source-type multipliers** (plant/mixed/animal:
110
+ protein 0.55/1.00/1.30, fat 0.45/1.00/1.25).
111
+ 3. **Pure-fat extrapolation guard** — when `(net-carb + protein) / 1000 kJ < 5 g`
112
+ the regression output is scaled by `0.15×` (energy-normalised, serving-
113
+ invariant since v1.1.1).
114
+ 4. **Cross-cohort linear calibration** — `obs ≈ 0.7275 × pct + 8.111`
115
+ (fit on the n = 63 cross-cohort validation set; opt-out via
116
+ `apply_calibration=False`).
117
+ 5. **Optional Holt cross-track + clinical-tier floor**, then
118
+ **`Final NIS = max(regression_cal, holt, floor)`**, clamped [0, 100].
119
+
120
+ > **Note on validation framing.** The n = 147 training cohort and the
121
+ > n = 63 cross-cohort calibration set share Holt 1997 foods (derivational
122
+ > overlap, see manuscript §4.3 L1). All inferential claims in v1.1.5 are
123
+ > therefore restricted to the **n = 25 strictly out-of-sample subset**
124
+ > (Bao 2011, Nilsson 2004, Boirie 1997, Trichopoulou 2003, Sahyoun 2008).
125
+
126
+ ## 📘 API reference
127
+
128
+ ### `compute_nis(carbs_g, protein_g, fat_g, fiber_g=0.0, *, insulin_impact_tier="low", il_total_g=None) → NisResult`
129
+
130
+ | Argument | Type | Default | Description |
131
+ |---|---|---|---|
132
+ | `carbs_g` | `float` | — | Net carbohydrate grams |
133
+ | `protein_g` | `float` | — | Protein grams |
134
+ | `fat_g` | `float` | — | Total fat grams |
135
+ | `fiber_g` | `float` | `0.0` | Dietary fibre grams (blunts response) |
136
+ | `insulin_impact_tier` | `Literal["low","medium","high"]` | `"low"` | Clinical floor band |
137
+ | `il_total_g` | `Optional[float]` | `None` | Pre-computed Insulin Load (overrides Holt track) |
138
+
139
+ ### `NisResult` (frozen `dataclass`)
140
+
141
+ | Field | Type | Description |
142
+ |---|---|---|
143
+ | `nis_percent` | `float` | Final NIS, 0–100 |
144
+ | `tier` | `str` | `"Low"` / `"Moderate"` / `"Medium"` / `"High"` / `"Very high"` |
145
+ | `tier_color` | `str` | Hex colour for UI (Tailwind-compatible) |
146
+ | `piru` | `float` | Predicted Insulin Response Unit (regression layer raw) |
147
+ | `regression_pct` | `float` | Pure regression output (0–100) |
148
+ | `holt_pct` | `float` | Holt cross-track output (0–100) |
149
+ | `tier_floor_pct` | `float` | Clinical-tier floor applied |
150
+ | `contributions` | `dict[str, float]` | Per-macro absolute contribution to PIRU |
151
+ | `nis_version` | `str` | Frozen version (e.g. `"1.0.0"`) |
152
+ | `coefficients_date` | `str` | Date coefficients were regressed (ISO) |
153
+ | `citation` | `str` | Required academic citation |
154
+
155
+ Use `.to_dict()` → JSON-serialisable.
156
+
157
+ ## 🔬 Reproducibility
158
+
159
+ | Artifact | Location |
160
+ |---|---|
161
+ | Frozen training dataset | Zenodo DOI [10.5281/zenodo.XXXXXX](https://zenodo.org/) |
162
+ | Regression notebook | [`notebooks/independent_regression_v2.ipynb`](https://github.com/nutramilo/nutramilo-nis) |
163
+ | SHA-256 of v1.0 dataset | `b41eb157661b2d8ad0…` (paper § 2.2) |
164
+ | Unit tests | `pytest -q` — 13 tests, all should pass |
165
+ | Figures (PNG + TIFF 300dpi) | Paper supplement, Figs 1–6 |
166
+
167
+ ## 📖 Paper
168
+
169
+ > **Inkov, I., et al.** (2026). "Nutramilo Insulin Score (NIS): An Open,
170
+ > Macronutrient-Derived Algorithm for Predicting Postprandial Insulinaemic
171
+ > Response — Development and Validation Against the Holt Food Insulin Index."
172
+ > *International Journal of Medical Reviews and Case Reports*, in press.
173
+ > DOI: [10.XXXX/ijmrcr.2026.NIS](https://doi.org/10.XXXX/ijmrcr.2026.NIS)
174
+
175
+ **Pre-print:** [medRxiv 2026.02.XXXXXX](https://medrxiv.org/)
176
+
177
+ If you use NIS in research, **please cite the paper** (Apache 2.0 + NOTICE).
178
+
179
+ ## ™ Trademark notice
180
+
181
+ `NIS™`, `Nutramilo Insulin Score™`, and `Nutramilo™` are trademarks of
182
+ **International Sci Ink Press Ltd EOOD** (EIK 205414288, Sofia, Bulgaria),
183
+ filed at the EUIPO.
184
+
185
+ The Apache 2.0 licence covers the **code** — *not* the trademarks. For
186
+ commercial use of the marks in branding/marketing, contact
187
+ [legal@nutramilo.com](mailto:legal@nutramilo.com).
188
+
189
+ ## ⚖️ Disclaimer & regulatory framing
190
+
191
+ NIS is intended for **educational and research** purposes.
192
+ It is **not** a medical device, does **not** diagnose any disease, and should
193
+ **not** replace professional clinical judgement.
194
+
195
+ | Framework | Classification |
196
+ |---|---|
197
+ | EU MDR 2017/745 | **Not a medical device** |
198
+ | EU AI Act 2024/1689 | **Limited risk** (Art. 50 — transparency only) |
199
+
200
+ ## 🏗️ Roadmap (semver-frozen)
201
+
202
+ - **v1.x** — patch fixes only; coefficients **never** change.
203
+ - **v2.0.x** — prospective CGM trial re-regression (manuscript Part II,
204
+ pre-registered at OSF before data collection).
205
+
206
+
207
+ | GDPR | No personal data processed by the library itself |
208
+
209
+ ## 🤝 NIS vs DIL — different questions, different units
210
+
211
+ NIS and DIL are **complementary, not interchangeable**:
212
+
213
+ | | **NIS** (per-meal) | **DIL** (per-meal & daily) |
214
+ |---|---|---|
215
+ | Question | *"How insulinogenic is THIS meal compared to pure glucose?"* | *"How many grams of carb-equivalent insulin load did I eat today?"* |
216
+ | Output | 0–100 % (intensity score) | grams of carb-equivalent (load) |
217
+ | Use-case | Compare two meals; rank foods on a phone; coach single-meal swaps | Daily budget tracking; weekly trend monitoring; clinical dosing-adjacent reasoning |
218
+ | Formula | 5-step pipeline with source-aware multipliers, pure-fat guard, cross-cohort calibration | `0.69 × protein + max(carbs − fiber, 0)` per food, summed across the day |
219
+ | Validation | n = 25 OOS Pearson r = 0.83, MAE = 10.2 | OLS-stable across Ridge/LASSO; food-level coefficient frozen at 0.69 since 2026-02-10 |
220
+ | In this SDK | `compute_nis(...)` | not bundled — see `nutramilo-health` package or `services/dil_formula.py` in the Nutramilo platform |
221
+
222
+ If you need both layers (per-meal NIS for ranking + daily DIL for budget),
223
+ combine `compute_nis` here with the open `compute_dil` formula:
224
+ `DIL_g = max(0, 0.69·protein + max(0, carbs − fiber))`.
225
+
226
+ ## 📜 Licence
227
+
228
+ [Apache 2.0](LICENSE) — see [`NOTICE`](NOTICE) for the mandatory citation clause.
229
+
230
+ ## 💬 Contact
231
+
232
+ | For | Email |
233
+ |---|---|
234
+ | Research collaboration | research@nutramilo.com |
235
+ | Trademark / commercial licensing | legal@nutramilo.com |
236
+ | Bug reports & feature requests | [github.com/nutramilo/nutramilo-nis/issues](https://github.com/nutramilo/nutramilo-nis/issues) |
237
+ | General product info | https://nutramilo.com/science |
@@ -0,0 +1,44 @@
1
+ """Nutramilo Insulin Score (NIS) — open, macronutrient-derived postprandial insulin response algorithm.
2
+
3
+ Public API:
4
+ >>> from nutramilo_nis import compute_nis
5
+ >>> result = compute_nis(carbs_g=50, protein_g=20, fat_g=10, fiber_g=5)
6
+ >>> result["nis_percent"]
7
+ 37.4
8
+
9
+ Citation (required by NOTICE file):
10
+ Inkov, I. et al. (2026). "Nutramilo Insulin Score (NIS): An Open,
11
+ Macronutrient-Derived Algorithm for Predicting Postprandial
12
+ Insulinaemic Response..." Int J Med Rev Case Rep. DOI: 10.XXXX/ijmrcr.2026.NIS
13
+
14
+ Trademarks: NIS™, Nutramilo Insulin Score™, Nutramilo™ — Nutramilo Ltd., EUIPO.
15
+ """
16
+ from .nis import (
17
+ NIS_VERSION,
18
+ NIS_COEFFICIENTS,
19
+ NIS_COEFFICIENTS_DATE,
20
+ NIS_CALIBRATION,
21
+ PURE_FAT_DENSITY_THRESHOLD,
22
+ PURE_FAT_ATTENUATION,
23
+ FRUCTOSE_OF_SUGAR,
24
+ FRUCTOSE_MULT,
25
+ compute_nis,
26
+ NisResult,
27
+ )
28
+ from .classify import classify
29
+
30
+ __version__ = "1.1.5"
31
+ __all__ = [
32
+ "compute_nis",
33
+ "classify",
34
+ "NIS_VERSION",
35
+ "NIS_COEFFICIENTS",
36
+ "NIS_COEFFICIENTS_DATE",
37
+ "NIS_CALIBRATION",
38
+ "PURE_FAT_DENSITY_THRESHOLD",
39
+ "PURE_FAT_ATTENUATION",
40
+ "FRUCTOSE_OF_SUGAR",
41
+ "FRUCTOSE_MULT",
42
+ "NisResult",
43
+ "__version__",
44
+ ]