• Non ci sono risultati.

3.3 Reti neurali con OhioT1DM dataset

4.1.2 Data Preparation

L’obiettivo della fase di preparazione dei dati per paziente `e quello di creare una griglia, o Data-Frame, di tante serie temporali quante sono le feature del dataset e sincronizzarle secondo un unico filo conduttore temporale, in modo che sia possibile osservare come si comportano tutte le feature selezionate allo stesso timestamp, cio`e allo stesso momento. A tal fine, sono state seguite 5 fasi:

1. Selezione delle feature

2. Ingegnerizzazione e Sincronizzazione dei dati

3. Analisi dei missing value, cio`e dei valori mancanti nei buchi temporali

4. Analisi, confronto e scelta di tecniche tra interpolazione e imputation, che sar`a tradotta con imputazione, anche se il significato `e totalmente differente dal consueto significato in italiano

5. Controllo qualit`a finale

E’ importante chiarire come le analisi non siano conseguenziali, ma di supporto per la fase pi`u importante di ingegnerizzazione e sincronizzazione dei dati. Tutte le fasi saranno adesso analizzate nelle successive sottosezioni.

FASE 1 - Selezione delle feature

Questa fase `e caratterizzata dalla cernita iniziale effettuata sulle feature candidate a far parte della fase successiva di ingegnerizzazione e sincronizzazione dei dati. Da ogni file XML(ne esistono due per paziente, uno di training e uno di testing), sono state inizialmente scartate tutte quelle feature che mediamente apportavano poco

”peso”, in quanto non presenti in tutti i pazienti e se presenti, si presentavano molto raramente.

Ecco le feature che sono state concettualmente scartate: eventi ipoglicemici, eventi febbrili, eventi stressanti, orari di lavoro e di esercizio fisico, finger stick.

In seguito vengono riportate invece, tutte le feature, intese ancora come campi dei file XML, che sono state ”ammesse” alla fase successiva perch´e potenzialmente ritenute importanti per sviluppi futuri: letture CGM di glucosio, basal, temp basal, boli, frequenza cardiaca, GSR (risposta galvanica della pelle), temperatura della pelle e temperatura dell’aria, conteggio dei passi, conteggio dei carboidrati nei pasti e qualit`a/durata del sonno.

FASE 2 - Ingegnerizzazione e sincronizzazione dei dati Questa `e sicuramente la fase pi`u corposa delle 5 elencate.

La figura 4.5 mostra una panoramica che porta dal semplice file XML alla griglia con tutte le feature sincronizzate in un DataFrame Pandas, una struttura di dati bidimensionale, dove i dati sono allineati in modo tabellare in righe e colonne.

L’uso della libreria Pandas `e quasi obbligatorio per tutti coloro che si cimentano nella costruzione di dataset, poich´e offre una serie di vantaggi e librerie molto comode se si parla di manipolazione e generazione di dati/serie temporali/data-frame in linguaggio Python.

Si mostreranno adesso nel dettaglio i passi pi`u importanti di tale processo per ogni singolo paziente:

• Estrazione dai file XML.

A partire dal file XML, si sfruttano funzioni tali da essere in grado di: leggere il file XML, scegliere il campo desiderato (mettendolo come input alla funzione), estrarre i dati temporali e i corrispettivi valori correnti e dare in output la serie temporale di Pandas della feature di interesse. Le feature ottenute sono di due tipologie: continue o semi-continue.

1 i m p o r t xml . e t r e e . E l e m e n t T r e e as ET

2

3 def l o a d _ o h i o _ s e r i e s ( x m l _ p a t h , v a r i a t e _ n a m e , a t t r i b u t e , t i m e _ a t t r i b u e =" ts ") :

4 t r e e = ET . p a r s e ( x m l _ p a t h )

5 r o o t = t r e e . g e t r o o t ()

6 for c h i l d in r o o t :

7 if c h i l d . tag == v a r i a t e _ n a m e :

8 d a t e s = []

9 v a l u e s = []

10 for e v e n t in c h i l d :

11 if(not t y p e( t i m e _ a t t r i b u e ) ==t y p e((1 ,) ) ) :

12 t i m e _ a t t r i b u e =( t i m e _ a t t r i b u e ,)

13

14 for ( i , t ) in e n u m e r a t e( t i m e _ a t t r i b u e ) :

15 ts = e v e n t . a t t r i b [ t ]

16 d a t e = pd . t o _ d a t e t i m e ( ts , f o r m a t=’ % d -% m -% Y

% H :% M :% S ’)

17 d a t e = d a t e . r e p l a c e ( s e c o n d =0)

18 v a l u e = f l o a t( e v e n t . a t t r i b [ a t t r i b u t e ])

19 if( i ==len( t i m e _ a t t r i b u e ) -1 and len(

t i m e _ a t t r i b u e ) >1) :

20 # v a l u e = f l o a t ( ’ nan ’)

21 v a l u e = 0

22 if(len( d a t e s ) >0 and d a t e s [ -1] >= d a t e ) :

23 del d a t e s [ -1]

24 del v a l u e s [ -1]

25 d a t e s . a p p e n d ( d a t e )

26 v a l u e s . a p p e n d ( v a l u e )

27 i n d e x = pd . D a t e t i m e I n d e x ( d a t e s )

28 s e r i e s = pd . S e r i e s ( values , i n d e x = i n d e x )

29 r e t u r n s e r i e s

Listing 4.1: Funzione che estrae le informazioni dal file XML e le converte in Series di Pandas

Le feature denominate come continue sono le feature che hanno un rilevamento costante, a meno di gap temporali, da parte di dispositivi associati o al dispo-sitivo CMG o alla fitness band con una propria frequenza di campionamento, mentre le feature semi continue, sono caratterizzate da eventi limitati ad un circoscritto periodo di tempo (vedi la feature sleep, cio`e il sonno) o da eventi che si manifestano un numero limitato di volte durante l’arco della giornata (vedi Meal, Bolus, Steps cio`e Cibo, Boli e Passi). Un’altra caratteristica delle variabili non continue `e quella di avere degli zeri quando la variabile non si manifesta e il valore vero quando si manifesta. Quindi per esempio Meal(o Pasti) avr`a nell’arco della giornata tutti zeri, tranne i valori corrispondenti ai carboidrati all’ora di inizio pasto autosegnalata dal paziente.

• Passaggio nell’ambiente di lavoro del Pandas DataFrame.

Per lavorare con i DataFrame si associa ad ogni serie la classe DataFrame, ottenendo la possibilit`a di sfruttare un’ampia gamma di funzioni utili per la preparazione dei dati.

1 i m p o r t p a n d a s as pd

2

3 g l u c o s e _ s e r i e s _ D F = pd . D a t a F r a m e ( g l u c o s e _ s e r i e s )

Listing 4.2: Conversione in DataFrame pandas delle serie temporale del glucosio

In particolare resample, `e immediatamente utilizzata per ricampionare tutte le serie temporali ad intervalli di 5 minuti, in modo da semplificare il lavoro successivo di interpolazione.

• Interpolazione delle variabili continue e filling del variabili non con-tinue.

I segnali delle caselle in verde dell’immagine 4.5, cio`e i segnali delle variabili continue, sono stati ricampionati ad intervalli di 5 minuti tramite la funzione resample con metodo pchip (discusso nella FASE 4 di questo capitolo), utiliz-zata in serie dopo ffill con limite = 1, una funzione che agisce secondo il filling forward, cio`e se il valore manca in un punto ad un particolare timestamp, verr`a interpolato con il valore pi`u vicino prima di tale punto. Oltre a tale regola, lo stesso valore pu`o essere utilizzato al massimo una sola volta nel processo(da qui il parametro del limite = 1), mentre i valori seguenti saranno etichettati semplicemente come mancanti e saranno soggetti all’interpolazione.

1 r e s a m p l e d _ G S = g l u c o s e _ s e r i e s _ D F . r e s a m p l e (’ 300 S ’, c o n v e n t i o n = s t a r t ’) . f f i l l ( l i m i t =1) . i n t e r p o l a t e (" p c h i p ")

Listing 4.3: Ricampionamento e interpolazione della serie di glucosio Diverso `e il caso delle variabili non continue.

In esse, la stragrande maggioranza di dati mancanti sono i dati virtualmente nulli, cio`e i dati in cui non esiste la misurazione, ma che, per poterla inserire nella stessa griglia temporale delle variabili continue, `e stata posta uguale a 0.

1 r e s a m p l e d _ b o l u s = b o l u s _ s e r i e s _ D F . r e s a m p l e (’ 300 s ’, c o n v e n t i o n =’

s t a r t ’) . a s f r e q () . f i l l n a (0)

Listing 4.4: Esempio di ricampionamento del bolo

E’ un approccio naive, che sar`a ulteriormente approfondito nella sezione 4.1.4 riguardanti gli sparse data .

• Ciclo for effettuato per ogni giorno corrispondente a 288 timesteps In tale ciclo avviene l’effettiva costruzione del dataset con le feature selezionate.

E’ un lungo processo dove si ripetono i seguenti punti:

1. Selezione dei valori da ogni serie per il giorno selezionato

1 i m p o r t p a n d a s as pd

2

3 x _ t e m p = r e s a m p l e d _ G S [ pd . T i m e s t a m p ( t i m e s t a m p _ d a y ) : pd . T i m e s t a m p ( t i m e s t a m p _ d a y _ a f t e r ) ]

Listing 4.5: Esempio di selezione della giornata del livello di glucosio

2. Aggiornamento delle feature basal e temp basal in una singola feature

1 def m a k e _ v a l u e s _ n u l l ( basal , t e m p _ b a s a l , t i m e ) :

2 """ " b a s a l g i v e s c o n t i n u u s v a l u e of b a s a l i n s u l i n e r o g a t e d ,

3 w h i l e t e m p _ b a s a l g i v e s w h e n the e r o g a t i o n of b a s a l i n s u l i n is off in a c e r t a i n day t i m e : f . e . ’2022 -01 -17 ’

4 T h i s f u n c t i o n r e p l a c e w i t h 0 the v a l u e s w h e n e r o g a t i o n is off in b a s a l i n s u l i n s e r i e s

5

6 I N P U T : b a s a l = b a s a l s e r i e s

7 t e m p _ b a s a l = t e m p _ b a s a l s e r i e s

8 t i m e in s t r i n g f o r m a t ’ yyyy - mm - dd ’ ( year - month - day )

9 A u t h o r : S a l v a t o r e P u z z o

10 """

11

12

13 b a s a l = b a s a l [ pd . T i m e s t a m p ( t i m e ) : pd . T i m e s t a m p ( t i m e ) + pd . T i m e d e l t a (’ 1 day ’) ]

14 t e m p _ b a s a l = t e m p _ b a s a l [ pd . T i m e s t a m p ( t i m e ) : pd . T i m e s t a m p ( t i m e ) + pd . T i m e d e l t a (’ 1 day ’) ]

15 a c t u a l _ t i m e _ s t a m p = b a s a l . a s t y p e (str)

16 day = a c t u a l _ t i m e _ s t a m p . i n d e x [0]

17 d a y _ c o n v e r t e d = day . s t r f t i m e (’ % Y -% m -% d ’)

18

19 l e n _ t e m p _ b a s a l = len ( t e m p _ b a s a l )

20

21 # se in q u e l g i o r n o non ci s o n o t e m p _ b a s a l , r i t o r n a la s e r i e b a s a l

22 if l e n _ t e m p _ b a s a l == 0:

23 b a s a l = b a s a l

24

25 # C A S O A = se p r e s e n t e una s o l a m i s u r a z i o n e in

t e m p _ b a s a l m e t t i 0 dal m o m e n t o in cui i n i z i a f i n o a l l a f i n e d e l l a g i o r n a t a di b a s a l

26 if l e n _ t e m p _ b a s a l == 1:

27 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 0 ] : b a s a l . l a s t _ v a l i d _ i n d e x () ] = 0

28 b a s a l = b a s a l

29 # C A S O B = se ci s o n o due m i s u r a z i o n i m e t t i 0 dal m o m e n t o in cui i n i z i a f i n o a l l a s e c o n d a m i s u r a z i o n e

30 if l e n _ t e m p _ b a s a l == 2:

31 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 0 ] : t e m p _ b a s a l . i n d e x [ 1 ] ]

= 0

32 b a s a l = b a s a l

33 # C A S O C = se ci s o n o tre m i s u r a z i o n i : C A S O B + C A S O A

34 if l e n _ t e m p _ b a s a l == 3:

35 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 0 ] : t e m p _ b a s a l . i n d e x [ 1 ] ]

= 0

36 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 2 ] : b a s a l . l a s t _ v a l i d _ i n d e x () ] = 0

37 b a s a l = b a s a l

38 # C A S O D = con 4 m i s u r a z i o n i : C A S O B + C A S O B

39 if l e n _ t e m p _ b a s a l == 4:

40 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 0 ] : t e m p _ b a s a l . i n d e x [ 1 ] ]

= 0

41 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 2 ] : t e m p _ b a s a l . i n d e x [ 3 ] ]

= 0

42 b a s a l = b a s a l

43

44 # C A S O E = con 5 m i s u r a z i o n i : C A S O B + C A S O B + C A S O A

45 if l e n _ t e m p _ b a s a l == 5:

46 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 0 ] : t e m p _ b a s a l . i n d e x [ 1 ] ]

= 0

47 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 2 ] : t e m p _ b a s a l . i n d e x [ 3 ] ]

= 0

48 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 4 ] : b a s a l . l a s t _ v a l i d _ i n d e x () ] = 0

49 b a s a l = b a s a l

50 # C A S O F = con 6 m i s u r a z i o n i : C A S O B + C A S O B + C A S O B

51 if l e n _ t e m p _ b a s a l == 6:

52 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 0 ] : t e m p _ b a s a l . i n d e x [ 1 ] ]

= 0

53 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 2 ] : t e m p _ b a s a l . i n d e x [ 3 ] ]

= 0

54 b a s a l . loc [ t e m p _ b a s a l . i n d e x [ 4 ] : t e m p _ b a s a l . i n d e x [ 5 ] ]

= 0

55 b a s a l = b a s a l

56 r e t u r n b a s a l

57

Listing 4.6: Funzione che aggiorna l’insulina basale

3. Aggiornamento della feature bolus, aggiungendo informazioni anche sul bolo di tipo normal e double wave. La quantit`a di bolo, rifacendosi a [56]

`

e stato convertito in unit`a di bolo al minuto, dividendo il bolo di tipo

“normale” per 5 minuti (periodo di campionamento) e dividendo il bolo di tipo double wave (a lento rilascio) per la sua intera durata.

4. Conversione della temperature della pelle e dell’aria in gradi Celsius

1 def f a h r _ t o _ c e l s i u s ( t e m p _ f a h r ) :

2 """ C o n v e r t F a h r e n h e i t to C e l s i u s

3

4 R e t u r n C e l s i u s c o n v e r s i o n of i n p u t """

5 t e m p _ c e l s i u s = ( t e m p _ f a h r - 32) * 5 / 9

6 r e t u r n t e m p _ c e l s i u s

7

Listing 4.7: Funzione che converte i gradi Fahrenheit in Celsius

5. Reindicizzazione di ogni feature ad una serie di riferimento con indici da mezzanotte a mezzanotte, con frequenza di campionamento di 5 minuti.

1 x _ t e m p = x _ t e m p . r e i n d e x ( l i s t a _ t e m p )

Listing 4.8: Esempio di reindexing del glucosio alla serie nulla di riferimento 6. Nuovo riempimento con zeri delle variabili non continue

1 h _ t e m p = h _ t e m p . f i l l n a (0)

Listing 4.9: Esempio di fillna della variabile rappresentante i carboidrati. In questo caso fillna trova e sostituisce i valori NaN semplicemente con 0

7. Riallineamento di ogni feature in un unico DataFrame di Pandas. Tramite il parametro how = ’outer’ della funzione join `e possibile allineare le colonne considerando gli indici esterni gi`a presenti con un effetto a catena che permette la costruzione del dataset feature dopo feature.

1

2 p r o v a _ j o i n _ t e m p = x _ t e m p . j o i n ( y_temp , how =’ o u t e r ’) . j o i n ( z_temp , how =’ o u t e r ’) . j o i n ( h_temp , how =’ o u t e r ’) . j o i n ( m_temp , how =’ o u t e r ’) . j o i n ( n_temp , how =’ o u t e r ’) . j o i n ( o_temp , how =’ o u t e r ’) . j o i n ( pq_temp , how =’ o u t e r ’) . j o i n ( s_temp , how =’ o u t e r ’) . j o i n ( t_temp , how =’ o u t e r ’)

Listing 4.10: Allineamento delle feature tramite la funzione join che permette di creare il dataset finale grezzo

8. Sostituzione della feature Air Temp, cio`e temperatura dell’aria, con Delta Temp, caratterizzata dalla differenza tra temperatura della pelle e tem-peratura dell’aria. Il motivo di tale sostituzione risiede nel fatto che `e

Figura 4.3: Andamento delle feature con-tinue in una giornata tipo del dataset completo

Figura 4.4: Andamento delle feature non continue in una giornata tipo dal dataset completo

dannoso per l’allenamento di una rete neurale somministrare dati molto simili tra loro, di conseguenza per non perdere anche le informazioni de-rivanti dalla conoscenza della temperatura dell’aria esterna, si `e preferito creare una feature fittizia che abbia:

– valori con range molto limitato;

– valori effettivi molto piccoli simili a 1;

– valori che trasportano la conoscenza di una caratteristica.

Tutte queste caratteristiche sono comunemente ben accette se si parla di Machine Learning, poich`e aiutano la macchina ad estrarre conoscenza pi`u facilmente dai dati empirici.

1 d a t a s e t _ g r e z z o [’ D e l t a _ t e m p e r a t u r e ’] = d a t a s e t _ g r e z z o [ s k i n _ t e m p e r a t u r e ’] - d a t a s e t _ g r e z z o [’ a i r _ t e m p e r a t u r e ’] Listing 4.11: Generazione di una feature fittizia chiamata Delta Temp

In questo modo si otterr`a un DataFrame completo per il singolo paziente in cui i dati sono perfettamente sincronizzati (riquadro verde nell’immagine 4.5 dove `e possibile vedere le feature finali all’interno dei box corrispondenti).

Durante la fase di allenamento e testing delle reti neurali non sempre verranno utilizzate tutte le feature, ma `e comunque importante possedere un dataset comple-to e proncomple-to per qualsiasi ulteriore implementazione e/o ingegnerizzazione di nuove feature a partire da quelle appena create.

Esaminando le figure 4.3 e 4.4, si possono osservare gli andamenti delle grandezze continue (grafico a sinistra) e non continue (grafico a destra). In particolare, nella figura 4.3 sono presenti gli andamenti del: glucosio (blu), frequenza cardiaca (aran-cione), insulina basale (verde), temperatura della pelle (rosso), risposta galvanica della pelle (viola) e la differenza tra temperatura della pelle con la temperatura dell’aria (marrone). In figura 4.4, troviamo i valori di: sonno in valori binari(blu), numero di passi (arancio), quantit`a di carboidrati ingeriti (verde) e bolo di insulina (rosso).

Figura 4.5

Il riassunto grafico delle azioni per poter raggiungere la sincronizzazione. Osservare il flusso di lavoro da sinistra a destra, ruotando di un angolo retto il foglio in senso

antiorario.

FASE 3 - Analisi dei missing value

L’analisi dei valori mancanti in una serie temporale `e di vitale importanza non solo nella fase di sviluppo, ma anche in fase di debugging e messa a punto del codice.

Grazie alla libreria Pandas, `e stato possibile creare un codice che identificasse i NaN, cio`e le misurazioni mancanti, sia per singola feature sia per tutto il dataset. Viene presentato il codice in Python della funzione per l’analisi dei missing value, che prende in input l’intero DataFrame.

1 def c o u n t _ m i s s i n g _ d a t a ( df ) :

2 p r i n t(’ Nan per c o l u m n s ’)

3 p e r _ c o l u m n s = df . i s n u l l () .sum()

4 p r i n t(’ Nan p e r c e n t a g e _ p e r _ c o l u m n s ’)

5 p e r c e n t a g e _ p e r _ c o l u m n s = df . i s n u l l () .sum() / len( df ) * 100

6 p r i n t(’ Nan t o t a l ’)

7 t o t a l = df . i s n u l l () .sum() .sum()

8 p r i n t(’ Nan p e r c e n t a g e _ o n _ t o t a l ’)

9 p e r c e n t a g e _ o n _ t o t a l = t o t a l / ( df . s h a p e [ 0 ] * ( df . s h a p e [1] -1) )

10 r e t u r n p e r _ c o l u m n s , p e r c e n t a g e _ p e r _ c o l u m n s , total , p e r c e n t a g e _ o n _ t o t a l

Listing 4.12: Funzione per il conteggio dei valori mancanti

1 " " " l i s t a m i s s i n g d a t a _ p o s t _ s i n c r o : HOW - TO - R E A D .

2 l i s t a di m i s s i n g d a t a per colonna ,

3 l i s t a di m i s s i n g d a t a per c o l o n n a p e r c e n t u a l i ,

4 f l o a t 6 4 : n u m e r o di m i s s i n g d a t a totali , m i s s i n g d a t a t o t a l i in p e r c e n t u a l e

5 " " "

6 g l u c o s e 1 2 3 0

7 s l e e p 0

8 s t e p s 0

9 m e a l 0

10 HR 1

11 b o l u s 0

12 b a s a l 96

13 s k i n _ t e m p e r a t u r e 1

14 g a l v a n i c _ s k i n _ r e s p o n s e 1

15 D e l t a _ t e m p e r a t u r e 1

16 d t y p e : int64 ,

17

18 g l u c o s e 1 0 . 4 1 5 7 8 5

19 s l e e p 0 . 0 0 0 0 0 0

20 s t e p s 0 . 0 0 0 0 0 0

21 m e a l 0 . 0 0 0 0 0 0

22 HR 0 . 0 0 8 4 6 8

23 b o l u s 0 . 0 0 0 0 0 0

24 b a s a l 0 . 8 1 2 9 3 9

25 s k i n _ t e m p e r a t u r e 0 . 0 0 8 4 6 8

26 g a l v a n i c _ s k i n _ r e s p o n s e 0 . 0 0 8 4 6 8

27 D e l t a _ t e m p e r a t u r e 0 . 0 0 8 4 6 8

28 d t y p e : float64 , 1330 , 0 . 0 1 2 5 1 3 9 9 5 9 1 6 4 8 5 5 4 4 ]

Listing 4.13: esempio di output alla console per il paziente 559 post sincronizzazione

FASE 4 - Interpolazione e Imputazione

Sia l’interpolazione che l’imputazione sono tra le tecniche pi`u utilizzate per colmare i vuoti temporali delle mancate misurazioni all’interno delle serie storiche, nella fattispecie la serie storica del livello glicemico del sangue. In questa fase sono state analizzate e provate entrambe le tecniche per osservarne gli effetti che sanciranno la scelta del metodo di filling che sar`a utilizzato in tutto il dataset.

La tecnica di imputazione `e stata gi`a utilizzata da Xie et al. [56] e rappresenta il punto di partenza per la scelta della tecnica di filling value, cio`e di riempimento dei valori mancanti con dati virtuali. Si tratta di un filtro di smoothing, chiamato filtro di Kalmann, che richiede l’informazione futura per poter eseguire il filtraggio e il conseguente riempimento dei gap. E’ una tecnica quindi che non permette il trattamento dei dati in real time. La tecnica di interpolazione, antagonista della precedente, `e invece l’interpolazione p-chip, acronimo di Piecewise Cubic Hermite Interpolating Polynomial, che utilizza le funzioni di approssimazioni spline cubiche monotoniche per assegnare il valore ai nuovi punti. La scelta di questo tipo di interpolazione `e basata su 3 principi basilari:

1. essendo una funzione cubica, porta con s´e un approccio non lineare, caratteri-stico dei segnali biologici

2. conserva la monotonia dei dati analizzati

3. impedisce l’overshoot, quindi la generazione di dati al di fuori dell’intervallo in cui si manifestano e di fatto non fisiologicamente corretti

A livello implementativo, l’imputazione `e stata eseguita tramite la funzione na.kalman, facente parte della libreria ImputeTS, con il metodo di input impo-stato su ”StructTS”, mentre il linguaggio utilizzato `e R, uno dei pi`u noti linguaggi utilizzati per il Machine Learning. Il codice di tale implementazione `e riportato in seguito:

1 l i b r a r y( i m p u t e T S )

2 p a t i e n t_563 < - r e a d.csv("/p a t i e n t_563_DF_t r a i n i n g_j u s t_g l u c o s e ")

3 p a t i e n t_563_i m p u t e d < - na. k a l m a n ( p a t i e n t_563 , m o d e l =" S t r u c t T S ") Listing 4.14: Kalmann imputation in linguaggio R

La funzione per implementare l’interpolazione pchip fa parte invece della sotto-classe DataFrame della libreria Pandas, ed `e definita come parametro negli input della funzione interpolate.

Esaminiamo adesso le figure 4.6, 4.7 e 4.8, in cui si vuole riportare il diverso effetto delle tecniche di interpolazione e imputazione su una stessa porzione tempo-rale. In 4.6, si osserva il segnale filtrato tramite imputazione (in rosso) rispetto al segnale originale in blu; in 4.7, si osserva il segnale interpolato con la tecnica p-chip (in verde) rispetto al segnale originale (in blu); in 4.8, si osserva il segnale interpo-lato con la tecnica p-chip (in verde) rispetto al segnale filtrato con imputazione (in rosso);

Figura 4.6: Effetto dell’imputazione tramite filtro kalmann in rosso su segnale CGM in blu

Figura 4.7: Effetto dell’interpolazione pchip in verde su segnale CGM in blu

Figura 4.8: Differenza tra imputazione in rosso e interpolazione in verde. E’ bene notare che i gap minori sono trattati allo stesso modo dalle due tecniche. Ci`o si intuisce dal fatto che la parte verde nelle zone interessate sia completamente sovrapposta alla parte rosse, eccetto nel maxi gap tra il 9 e il 10 dicembre

E’ stata scelta una porzione di serie temporale del paziente 575, caratterizzata da un gap temporale tra il 9 e il 10 dicembre, nella settimana tra il 7 e il 14 dicembre.

Se da una parte `e possibile constatare in tutte le figure che le due tecniche si comportano alla stessa maniera nei gap pi`u piccoli dell’ordine di qualche minuto, notiamo come in gap pi`u corposi dell’ordine di qualche ora, l’effetto interpolante del filtro Kalmann provochi una generazione di dati che vanno oltre il valore fisiologico (nelle figure 4.6 e 4.8 la curva rossa `e stata ”tagliata” ai limiti fisiologici, anche se in realt`a proseguiva in valori molto negativi) e di conseguenza potrebbero essere dannosi per l’allenamento e la validazione delle reti neurali.L’interpolazione, d’al-tro canto, ha un approccio intrinsecamente pi`u prudente, generando dei valori che non si discostano dal range fisiologico e quindi pi`u idonei per l’utilizzo all’interno dell’apprendimento automatico. L’interpolazione pchip per via delle caratteristiche analizzate e degli effetti sulla serie temporale mostrati `e stata scelta come metodo primario di riempimento dei gap non solo del livello glicemico, ma anche di altre feature continue.

FASE 5 - Controllo finale della qualit`a delle feature

Questa rappresenta la fase finale per il controllo dei gap residui prima della costru-zione del dataset finale. Per evitare ulteriori immissioni di dati fittizi provenienti da interpolazioni, si `e scelto di riempire i buchi temporali rimanenti con dei valori fisiologici appartenenti al paziente negli stessi momenti ma in giorni precedenti o successivi. A tal fine `e stata modificata la funzione count missing data, affinch´e possa essere utilizzata in combinazione con una nuova funzione, chiamata ultimate filling. Come `e possibile leggere dal codice sottostante, tenendo in considerazione dell’output della funzione di conteggio di NaN modificata, si sfruttano le due sem-plici funzioni di fillna e shift, in modo da riempire di buchi temporali (fillna) con valori traslati nel tempo di un particolare valore (shift). In pratica si tratta un ciclo for in grado di colmare i gap presenti con un valore 1, 2, 3 giorni dopo o -1, -2, -3 giorni prima del valore effettivo, dove 1 giorno `e uguale a 288 timesteps.

1 i m p o r t p a n d a s . D a t a F r a m e

2 def c o u n t _ m i s s i n g _ d a t a ( df ) :

3 p e r _ c o l u m n s = df . i s n u l l () .sum()

4 a = l i s t( p e r _ c o l u m n s )

5 if all( v == 0 for v in a ) == T r u e :

6 m i s s i n g = F a l s e

7 e l s e:

8 m i s s i n g = T r u e

9

10 r e t u r n p e r _ c o l u m n s , m i s s i n g

11

12 def u l t i m a t e _ f i l l i n g ( p a t i e n t _ t e s t , m i s s i n g ) :

13 f r e q s = [’ 1 d ’, ’ -1 d ’, ’ 2 d ’, ’ -2 d ’, ’ 3 d ’, ’ -3 d ’, ’ 4 d ’, ’ -4 d ’]

14 for f r e q in f r e q s :

15 if not m i s s i n g :

16 p r i n t (" No m o r e NaN in y o u r D a t a F r a m e ")

17 b r e a k

18 if m i s s i n g :

19 p a t i e n t _ t e s t = p a t i e n t _ t e s t . f i l l n a ( p a t i e n t _ t e s t . s h i f t ( f r e q = f r e q ) )

20 p e r _ c o l u m n s , m i s s i n g = c o u n t _ m i s s i n g _ d a t a ( p a t i e n t _ t e s t )

21

22 r e t u r n p a t i e n t _ t e s t , p e r _ c o l u m n s

Listing 4.15: Doppia funzione per il controllo di qualit`a finale

La funzione dar`a in output il DataFrame (patient test) con i valori mancanti sosti-tuiti con i valori target e un ulteriore report testuale (per columns) per un check finale sulla qualit`a della sostituzione avvenuta.

4.1.3 Filtraggio del segnale glicemico tramite

Documenti correlati