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}\)

BGM

bloedglucosemonitoring

glucoseconcentratie (op onregelmatige tijden)

-

mmol/L

\(g_{CGM}\)

CGM

continueglucosemonitoring

glucoseconcentratie (gemaakt door een continue glucosemeter)

-

mmol/L

\(h\)

HBA1c

hemoglobinA1c

hoeveelheid glucose in bloedcel

-

mmol/L

\(h_{CGM}\)

eA1

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}\)

TAR

time above range

percentage van de tijd dat de CGM boven 10 mmol/L is

< 30

%

\(p_{TIR}\)

TIR

time in range

percentage van de tijd dat de CGM tussen 3.9 en 10 mmol/L is

> 70

%

\(p_{TBR}\)

TBR

time below range

percentage van de tijd dat de CGM onder 3.9 mmol/L is

< 5

%

My Image
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):

  1. de CGM van de patiënt als functie van tijd,

  2. de BGM van de patiënt als functie van tijd,

  3. de gemiddelde bloedglucoseconcentratie g (mmol/L) van de patiënt geschat a.d.h.v. opgestapelde glucose in bloedcellen h = HbA1c als

\[g = \frac{h − a}{b}\]

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 glucoseconcentratie g uit h = 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 de h = HbA1c schatten volgens \(h_{CGM} = a +b\overline{g}_{cgm}\) met a = 12.71 mmol/mol en b = 4.70587L/mol. Deze \(h_{CGM}\) wordt eA1c genoemd (voor “estimated HbA1c”).

  • 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: HbA1c ≤ 53

Patiëntgroep 2:

midden: 53 < HbA1c < 63

patiëntgroep 3:

hoog: HbA1c ≥ 63

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:

  1. Bepaal deze klinische parameters voor alle patiënten en plaats in één container.

  2. Bereken de gemiddelde TBR, TIR en TAR, voor de verschillende groepen.

  3. 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

\[y_{k}=\frac{1}{M+1}(x_{k},x_{k-1},...,x_{k-M}), k=1,..,n\]

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 de HbA1c 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.