← Terug naar blog
Herman Holterman · 27 januari 2026

Machine learning in de revalidatiezorg: van patiëntdata naar behandelprognose

Google Cloudmachine learninghealthcareCloud RunBigQuery

ML Platform architectuur op Google Cloud

Een revalidatiekliniek behandelt patiënten met chronische pijn via een interdisciplinair programma. De behandeling is intensief: weken lang, meerdere disciplines tegelijk, grote investering van patiënt en kliniek. De vraag die al jaren op tafel lag: kunnen we vooraf inschatten welke patiënten het meeste baat hebben bij deze behandeling? En voor wie is een ander traject wellicht effectiever?

Dat is geen academische vraag. Het is een operationele vraag met directe gevolgen voor behandelplanning, capaciteit, en uiteindelijk patiëntuitkomsten.

De opdracht

De kliniek had samen met een data science specialist een machine learning model ontwikkeld voor prognostische patiëntprofielen. Het model was gebouwd in scikit-learn en getraind op historische patiëntdata: behandeluitkomsten gekoppeld aan 51 kenmerken die bij intake worden vastgelegd.

Die 51 parameters komen uit gevalideerde vragenlijsten - meetinstrumenten voor pijn, angst, depressie, functionele beperkingen, en psychologische factoren. Elk van die vragenlijsten is wetenschappelijk gevalideerd en wordt standaard afgenomen bij intake. Het model gebruikt de scores om een prognose te genereren: hoe waarschijnlijk is het dat deze patiënt klinisch relevante verbetering laat zien na behandeling?

Het probleem was niet het model. Het model werkte. Het probleem was dat het draaide als Python-script op een laptop. De data science specialist moest handmatig data exporteren, het script draaien, en de resultaten terugkoppelen. Dat is niet schaalbaar, niet reproduceerbaar, en niet acceptabel als je het als standaardonderdeel van de intake wilt inzetten.

De opdracht aan ons: maak hier een productieplatform van.

De architectuur

We bouwden het platform op Google Cloud, aansluitend op de data-infrastructuur die we eerder voor deze kliniek hadden ingericht. De architectuur volgt een helder patroon:

Patiëntdata naar BigQuery. De kliniek registreert patiëntgegevens in een EPD-systeem. Via onze EPD Connector - een Cloud Run-service die dagelijks draait - wordt de relevante data geëxtraheerd en naar BigQuery geschreven. Dit is de ruwe laag: onbewerkte antwoorden op vragenlijsten, demografische gegevens, en behandelhistorie.

dbt als transformatielaag. De ruwe EPD-data is niet direct bruikbaar voor het model. Scores moeten berekend worden uit individuele antwoorden. Subschalen moeten geaggregeerd. Ontbrekende items moeten volgens de scoringsprotocollen van de vragenlijsten worden afgehandeld. dbt transformeert de ruwe data naar exact de 51 parameters die het model verwacht - gedocumenteerd, getest, en versiebeheerd.

Cloud Run Jobs voor modelinference. Het scikit-learn model draait als container op Cloud Run Jobs. De job haalt de getransformeerde parameters op uit BigQuery, laadt het getrainde model, genereert prognoses, en schrijft de resultaten terug naar BigQuery. Geen VM die 24/7 draait - alleen rekenwerk wanneer het nodig is.

GCP Workflows als orchestrator. Een Workflow koppelt de stappen aan elkaar: dbt-transformatie triggeren, wachten tot die klaar is, de Cloud Run Job starten, en bij fouten alerteren. Dit vervangt de handmatige stappen die de data scientist eerder moest uitvoeren.

Resultaten naar Power BI. De kliniek werkt met Microsoft 365. De prognoses uit BigQuery zijn beschikbaar in Power BI-dashboards waar behandelteams bij kunnen. Geen exports, geen losse bestanden - actuele resultaten, direct beschikbaar.

De NaN-uitdaging

De interessantste technische uitdaging zat niet in de infrastructuur, maar in de data. Scikit-learn - de library waarop het model is gebouwd - heeft een verraderlijke eigenschap: het faalt niet op ontbrekende waarden. Het produceert gewoon incorrecte output.

Dat klinkt als een klein probleem. Het is een groot probleem.

In de praktijk ontbreken er regelmatig waarden. Een patiënt vult niet alle vragen in. Een vragenlijst wordt in een latere versie aangepast waardoor scores anders berekend worden. Een intake wordt in twee sessies afgenomen en de tweede sessie is nog niet geregistreerd. Het resultaat: NaN-waarden in de feature matrix.

Op de laptop van de data scientist was dit beheersbaar - die kende de data, zag de gaten, en handelde ze af. In een geautomatiseerde pipeline is er niemand die meekijkt. Als het model stilletjes een prognose genereert op basis van onvolledige data, krijg je resultaten die er valide uitzien maar het niet zijn. Dat is erger dan een error, want niemand merkt het.

Onze oplossing was drieledig:

  1. Validatie vóór inference. Voordat de data het model ingaat, valideert de pipeline elke rij op completheid. Ontbrekende waarden worden expliciet gedetecteerd en gelogd. Rijen met ontbrekende verplichte parameters worden uitgesloten van de modelrun en apart gerapporteerd.

  2. dbt-tests op de 51 parameters. In de transformatielaag testen we niet alleen of de berekeningen kloppen, maar ook of de output compleet is. Een not_null-test op elke verplichte kolom is het minimale. Daarbovenop zitten range-checks: valt een score buiten het theoretisch mogelijke bereik, dan klopt er iets niet in de berekening.

  3. Vergelijking lokaal versus cloud. Bij de initiële validatie hebben we het model op beide omgevingen gedraaid - de laptop van de specialist en het cloudplatform - op identieke datasets. De uitkomsten moesten exact overeenkomen. Elke afwijking was een signaal dat er iets misging in de datatransformatie of de modelconfiguratie.

Die laatste stap klinkt eenvoudig, maar was onmisbaar. Het is de enige manier om te garanderen dat de migratie van laptop naar cloud geen verschuivingen introduceert. In de gezondheidszorg is “ongeveer goed” niet goed genoeg.

Containerisatie voor reproduceerbaarheid

Het model moest exact dezelfde resultaten geven, ongeacht waar het draaide. Dat betekent: dezelfde Python-versie, dezelfde library-versies, dezelfde volgorde van operaties.

We verpakten het model en de inference-code als Docker-container. De container bevat een vastgezette requirements.txt met exacte versienummers. Het getrainde model wordt als artifact meegeleverd, niet opnieuw getraind bij elke run. De container draait identiek op een lokale machine en op Cloud Run Jobs.

Dit maakt het platform ook overdraagbaar. Wanneer een ander revalidatiecentrum met hetzelfde behandelprogramma het model wil inzetten, hoeven ze alleen hun data in het juiste formaat aan te leveren. De container, het model, en de pipeline zijn herbruikbaar.

Wat dit laat zien

Dit project demonstreert een patroon dat we vaker tegenkomen in de zorg: de domeinkennis is er, het model is er, maar het platform ontbreekt. Een data scientist bouwt iets dat werkt op een laptop. Vervolgens moet het schaalbaar, betrouwbaar, en reproduceerbaar worden - en dan begint het echte werk.

De waarde die wij toevoegen is niet het model. Het model was al gebouwd door iemand met diepe domeinkennis en statistische expertise. De waarde zit in het platform eromheen:

  • Betrouwbaarheid: de pipeline draait dagelijks, zonder handmatige interventie, met monitoring op elke stap.
  • Reproduceerbaarheid: containerisatie garandeert identieke resultaten, ongeacht de omgeving.
  • Datakwaliteit: validatie vangt de stille fouten op die scikit-learn niet vangt.
  • Schaalbaarheid: dezelfde architectuur kan uitgerold worden naar andere klinieken en andere behandelprogramma’s.

De kliniek heeft nu een operationeel systeem dat bij elke intake een behandelprognose kan genereren. De behandelaar krijgt een extra datapunt - niet ter vervanging van klinisch oordeel, maar ter ondersteuning ervan.

Van laptop naar productie. Dat is de stap waar veel ML-projecten stranden. De modelbouw is het spectaculaire deel. Het platform is het deel dat bepaalt of het ook daadwerkelijk gebruikt wordt.

Laten we praten

Plan een eerste consult voor uw data-uitdagingen.