Project#
In dit hoofdstuk werk je met behulp van Python een casus uit met echte patiëntendata. Gebruik hierbij de functies en modules die je eerder in de cursus bent tegengekomen.
Maak je eigen .ipynb
-bestand en houd daarin je antwoorden bij. Voeg headers in Markdown toe om de opdrachten uit elkaar te houden.
Inleiding#
Voor patiënten met type 1 of 2 diabetes is het belangrijk dat hun bloedglucose goed gereguleerd is. Goede regulatie beperkt de kans op ontwikkeling van macro- en microvasculaire complicaties. Er zijn meerdere manieren om bloedglucose te monitoren:
HbA1c. Dit is een maat voor de hoeveelheid glucose die zich in de afgelopen drie maanden heeft opgestapeld in de rode bloedcellen. (Dit is niet hetzelfde als glucoseconcentratie in het bloed.)
Bloedglucosemonitoring (
BGM
). Diabeten die insuline gebruiken, prikken dagelijks 4 a 6 keer: bij ontbijt, lunch, diner en soms bij de twee tussendoortjes op een dag, en voor het slapen gaan. Daarnaast prikken ze ook wanneer er symptomen zijn van een hypo- of hyperglycemie. Met die prikken wordt bloedglucose gemeten.Tegenwoordig gebruiken steeds meer diabeten een continue glucosemeter (
CGM
), die, afhankelijk van het type, iedere 5 of 15 minuten een glucosemeting doet.
Met de komst van de CGM
hebben diabeten en hun behandelaren meer inzicht gekregen in de glucoseregulatie. Er zijn op basis daarvan nieuwe klinische CGM
-parameters gedefinieerd (zie Tabel 1 en Figuur 1) en de verwachting is dat we daarmee de belangrijke maar moeilijker te bepalen HbA1c
kunnen schatten.
Voor deze opdracht maken we gebruik van open-source data van een studie\(^{1}\) die onderzoekt of CGM
zonder regelmatige vingerprik net zo veilig is als het gebruik van CGM
met regelmatige vingerprik. Dit onderzoek is gedaan bij Type 1 diabetespatiënten. De CGM
die de patiënten gebruiken tijdens dit onderzoek bepaalt iedere 5 minuten een glucosewaarde.
Tabel 1 Gebruikte variabelen en hun eenheid, doel en omschrijving.
Afkorting |
Naam |
Definitie |
Doel |
Eenheid |
|
---|---|---|---|---|---|
\(g_{BGM}\) |
|
bloedglucosemonitoring |
glucoseconcentratie (op onregelmatige tijden) |
- |
mmol/L |
\(g_{CGM}\) |
|
continueglucosemonitoring |
glucoseconcentratie (gemaakt door een continue glucosemeter) |
- |
mmol/L |
\(h\) |
|
hemoglobinA1c |
hoeveelheid glucose in bloedcel |
- |
mmol/L |
\(h_{CGM}\) |
|
extimated HbA1c |
schatting van HbA1c op basis van gemiddelde CGM |
< 53 |
mmol/L |
\(a\) |
- |
- |
- |
- |
12.71 mmol/mol |
\(b\) |
- |
- |
- |
- |
4.70587 L/mol |
\(p_{TAR}\) |
|
time above range |
percentage van de tijd dat de CGM boven 10 mmol/L is |
< 30 |
% |
\(p_{TIR}\) |
|
time in range |
percentage van de tijd dat de CGM tussen 3.9 en 10 mmol/L is |
> 70 |
% |
\(p_{TBR}\) |
|
time below range |
percentage van de tijd dat de CGM onder 3.9 mmol/L is |
< 5 |
% |
Figuur 1 Voorbeeld van een gestapeld staafdiagram van CGM-waarden (mmol/L) met doelwaarden. Zo is in het ideale geval de TIR (percentage van de tijd dat 3.9 <CGM< 10) meer dan 70%. Zie ook Tabel 1.
Opdrachten#
Opdracht 9.1
De gegevens zijn opgeslagen in het bestand glucosedata.pickle
dat je hier kunt vinden. Een ‘pickle’ bestand bevat een object dat we uit kunnen pakken in Python. Gebruik onderstaande code om deze pickle uit te pakken. Het resultaat wordt opgeslagen in glucodat
.
with open('glucosedata.pickle', 'rb') as handle:
glucodat = pickle.load(handle)
Inspecteer de variabele glucodat
. Zoals je ziet is het een dictionary. Hoeveel patiënten zitten er in deze dictionary?
Iedere patiënt heeft een unieke ID. De ID van patient 2 is bijvoorbeeld ‘ID_2’. Je kunt alle IDs krijgen met de .keys()
method op de dictonary. Voor elke patiënt zijn metingen van BGM en CGM en HbA1c opgeslagen. Om de BGM waarden van bijvoorbeeld patiënt ‘ID_2’ te verkrijgen, gebruik je (zoals je in Hoofdstuk 2 hebt geleerd) dictionary indexing:
gbm_values = glucodat['ID_2']['BGM']
Voor zowel BGM als CGM zijn voor elke patiënt tijd (eerste kolom) en gemeten waarde (tweede kolom) opgeslagen in een NumPy array. De BGM
is vaak gemeten op onregelmatige tijden; de CGM
zijn de continue glucosemetingen, meestal regelmatig gemeten. Van de HbA1c
is per patiënt maar één meting uitgevoerd, maar de waarde is twee keer opgeslagen.
De tijd is in dagen, de glucosedata (BGM
, CGM
) zijn in mmol/L, en de HbA1c
is in
mmol/mol. Per patiënt zijn er 3 maanden aan data geselecteerd. Patiënten hebben verschillende hoeveelheden BGM
- en CGM
-metingen gedaan. Daardoor is de data van iedere patiënt verschillend van lengte.
Opdracht 9.2
Gebruik de numpy.random
module (zie Hoofdstuk 6) om drie willekeurige patiënten te selecteren. Maak vervolgens in één figuur drie subplots (voor elke patiënt een subplot, zie Hoofdstuk 8), en zet per patiënt in één subplot (zie Hoofdstuk 8):
de
CGM
van de patiënt als functie van tijd,de
BGM
van de patiënt als functie van tijd,de gemiddelde bloedglucoseconcentratie
g
(mmol/L) van de patiënt geschat a.d.h.v. opgestapelde glucose in bloedcellenh = HbA1c
als
met \(a\) = 12.71mmol/mol en \(b\) = 4.70587 L/mol.
Voeg zinvolle titels, labels en een legenda toe.
Opdracht 9.3
Wat valt je op aan de verschillende plots? Zijn er verschillen tussen patiënten?
HbA1c
vs klinische CGM
parameters#
Nu gaan we HbA1c
vergelijken met een paar klinische CGM
-parameters. We onderscheiden vier parameters (per patiënt):
eA1c
: In Opdracht 9.2 schatten we een gemiddelde glucoseconcentratieg
uith = HbA1c
volgens de formule \(g = \frac{h − a}{b}\). Omgekeerd kunnen we uit het gemiddelde \(g_{cgm}\) (mmol/mol) van de CGM-metingen van de patiënt deh = HbA1c
schatten volgens \(h_{CGM} = a +b\overline{g}_{cgm}\) meta
= 12.71 mmol/mol enb
= 4.70587L/mol. Deze \(h_{CGM}\) wordteA1c
genoemd (voor “estimatedHbA1c
”).TAR
: Dit is het percentage samples van CGM hoger dan 10.0 mmol/L.TIR
: Dit het percentage samples van CGM tussen de 3.9 en 10.0 mmol/L.TBR
: Dit is het percentage samples van CGM kleiner dan 3.9 mmol/L.
Opdracht 9.4
Maak een Python functie gluc_param
die voor een gegeven CGM
signaal (van een patiënt) alle vier parameters (eA1c
, TAR
, TIR
, TBR
) bepaalt en teruggeeft.
De streefwaarde van HbA1c
voor diabetespatiënten is < 53 mmol/mol. Voor de sommige patiënten is deze streefwaarde lastig te behalen. Nu willen we kijken hoe de verschillende HbA1c streefwaarden zich verhouden tot de CGM
-parameters (eA1c
, TAR
, TIR
, TBR
). We onderscheiden drie groepen:
Patiëntgroep 1: |
laag: |
Patiëntgroep 2: |
midden: 53 < |
patiëntgroep 3: |
hoog: |
Opdracht 9.5
Maak een stacked bar chart, waarbij de drie verschillende patiëntgroepen naast elkaar op de x-as staan, en, per patiëntgroep de gemiddelde TBR
, TIR
en TAR
voor de patiëntgroep op elkaar gestapeld staan, zoals in Figuur 1.
Hints:
Bepaal deze klinische parameters voor alle patiënten en plaats in één container.
Bereken de gemiddelde
TBR
,TIR
enTAR
, voor de verschillende groepen.Maak een bar-graph met de Matplotlib-functie
bar
. Hier staat een voorbeeld van een stacked bar chart in Matplotlib.
Opdracht 9.6
Wat valt op aan de resultaten? Welke groepen behalen de CGM
parameterdoelen (zoals beschreven in Figuur 1).
Moving average#
Het is je wellicht opgevallen dat de CGM
-metingen als functie van tijd enorm fluctueren. Door de metingen te middelen over tijd ontstaat er een langzaam variërende functie van tijd, en die zegt vermoedelijk meer over HbA1c
. Het langzaam variërende signaal construeren we met een “moving averaging” filter van orde \(M\). Een moving average, of voortschrijdend gemiddelde, bepaalt het gemiddelde over de afgelopen \(M\) metingen en vervangt daarmee de waarde in het signaal. Met andere woorden: het is een filter dat op basis van metingen \(x_{1},x_{1},...,x_{n}\) het signaal \(y_{1},y_{1},...,y_{n}\) bepaalt volgens de regel
Het getal \(M\) wordt de “orde” van het filter genoemd. Als M=1
kopiëren we gewoon de waarden van \(x\) naar \(y\), en verder geldt dat hoe hoger \(M\) is, hoe gladder het signaal \(y\) wordt. Op Wikipedia staat een uitgebreide uitleg en onderstaand voorbeeld met \(M=3\)
Dag |
Koers |
MA berekend over 3 dagen |
---|---|---|
1 |
10 |
|
2 |
11 |
|
3 |
15 |
12, want (10+11+15)/3=12 |
4 |
7 |
11 |
5 |
9 |
10,3 |
6 |
6 |
7,3 |
7 |
7 |
7,3 |
8 |
8 |
7 |
9 |
17 |
10,7 |
10 |
20 |
15 |
Opdracht 9.7
Maak een Python functie movingav
met syntax y = movingav(x, m)
die uit een vector x
een vector y
bepaalt zoals gedefinieerd in de vergelijking hierboven.
Opdracht 9.8
Controleer deze functie met onderstaande code, en leg uit waarom de plot klopt.
x = np.array([0, 1, 1, 1, 1, 1])
t = np.array([0, 1, 2, 3, 4, 5]);
M = 2
y = movingav(x, M)
print(y)
plt.stem(t,y) # ook wel "lollipop plot" genoemd
plt.show()
Opdracht 9.9
Selecteer drie patiënten, en, per patiënt, maak een figuur met daarin een plot van de:
ongefilterde
CGM
data,gefilterde
CGM
data (dus bepaald m.b.v. movingav)de geschatte gemiddelde bloedglucoseconcentratie
g
bepaald op basis van deHbA1c
gegevens.
Opdracht 9.10
Maak plaatjes met verschillende orde \(M\) van het moving average filter. Filter bijvoorbeeld ook eens met grote orders, bijvoorbeeld het aantal samples voor een dag, of voor een week. Je mag er vanuit gaan dat de samplefrequentie 5/min is. Wat valt je op voor verschillende filter ordes?
Referenties#
[1]: Aleppo G, Ruedy KJ, Riddlesworth TD, Kruger DF, Peters AL, Hirsch I, et al. REPLACE-BG: A Randomized Trial Comparing Continuous Glucose Monitoring With and Without Routine Blood Glucose Monitoring in Adults With Well-Controlled Type 1 Diabetes. Diabetes Care [Internet]. 2017 Apr 1 [cited 2021 Oct 4];40(4):538–45. Available from: https://care.diabetesjournals.org/content/40/4/538. Dataset beschikbaar vanaf: https://public.jaeb.org/datasets/diabetes.