Applicazioni pratiche di machine learning/Diagnosi di malattie

Wikibooks, manuali e libri di testo liberi.
Indice del libro

Diagnosi di malattie tramite descrizione testuale[modifica]

Tramite il modello BERT di classificazione del testo è possibile diagnosticare malattie, descrivendo liberamente la propria sintomatologia. Su HuggingFace al seguente indirizzo : https://huggingface.co/Zabihin/Symptom_to_Diagnosis è possibile digitare in inglese in modo discorsivo i propri sintomi nell'apposita casella di testo, ottenendo varie diagnosi con una certa accuracy in percentuale.

Diagnosi di malattie tramite sintomi[modifica]

Utilizzando l'algoritmo di machine learning Random Forest è possibile diagnosticare le malattie tramite i loro sintomi con un'Accuracy del 99% . Su HuggingFace al seguente indirizzo : https://huggingface.co/gianlab/random-forest-model-disease-symptom-prediction è possibile scaricare il modello sul proprio PC o su Google Colab, in modo da fare diagnosi mediche attraverso sintomi. Il codice per effettuare tale analisi si trova su Github, come indicato nel suddetto link.

Diagnosi di malattie cardiache[modifica]

Caricamento librerie[modifica]

 library(dplyr)
 library(ggplot2)
 library(caret)

Parte 1: Dati[modifica]

Il dataset "heart.csv" scaricabile da qui : https://archive.ics.uci.edu/ml/datasets/Heart+Disease contiene 303 osservazioni, ciascuna delle quali contiene 14 variabili relative al cuore. Tali variabili sono le seguenti :

  • age: l'età della persona in anni
  • sex: il sesso della persona (1 = maschio, 0 = femmina)
  • cp: dolore toracico sperimentato (1: angina tipica, 2: angina atipica, 3:dolore non anginale, 4: asintomatico)
  • trestbps: pressione sanguigna a riposo della persona (mm/Hg al momento del ricovero in ospedale)
  • chol: misurazione del colesterolo in mg/dl
  • fbs: glicemia a digiuno della persona (> 120 mg/dl, 1 = vero; 0 = falso)
  • restecg: elettrocardiogramma a riposo (0 = normale, 1 = con anomalia dell'onda ST-T, 2 = ipertrofia ventricolare sinistra probabile o definita secondo i criteri di Estes)
  • thalach: frequenza cardiaca massima raggiunta dalla persona
  • exang: angina indotta dall'esercizio (1 = sì; 0 = no)
  • oldpeak: depressione ST indotta dall'esercizio ('ST' si riferisce alle posizioni sul diagramma ECG)
  • slop: pendenza del segmento ST (valore 1: salita, valore 2: piano, valore 3: discesa)
  • ca: numero di vasi principali (0-3)
  • tal: disturbo del sangue chiamato talassemia (3 = normale; 6 = difetto fisso; 7 = difetto reversibile)
  • target: malattie cardiache (0 = no, 1 = sì)

Caricamento dei dati:

 heart <- read.csv("heart.csv")

Ricerca valori mancanti:

 colSums(is.na(heart))
  age      sex       cp trestbps     chol      fbs  restecg  thalach 
      0        0        0        0        0        0        0        0 
  exang  oldpeak    slope       ca     thal   target 
      0        0        0        0        0        0 

Parte 2 : Domanda di ricerca[modifica]

Si vuole predire l'eventuale presenza di una malattia cardiaca nel paziente, predicendo la variabile target in base alle 13 suddette variabili.

Parte 3: Esplorazione dei dati[modifica]

 df <- heart

 #Traduco le variabili del dataset in italiano:

 names(df)<-c("eta","sesso","tipo di dolore toracico","pressione sanguigna a riposo","colesterolo  in mg/dl","glicemia a digiuno","elettrocardiogramma a riposo","frequenza cardiaca massima raggiunta","angina indotta dall'esercizio","depressione ST indotta","pendenza del segmento ST","numero di vessels","talassemia","malattia al cuore")

 #Rendo più comprensibili i valori delle variabili:

 df$sesso[df$sesso==0]="Femmina"
 df$sesso[df$sesso==1]="Maschio"
 df$sesso=as.factor(df$sesso)

 df$`tipo di dolore toracico`[df$`tipo di dolore toracico`==0]="Angina tipica"
 df$`tipo di dolore toracico`[df$`tipo di dolore toracico`==1]="Angina atipica"
 df$`tipo di dolore toracico`[df$`tipo di dolore toracico`==2]="Dolore non anginale"
 df$`tipo di dolore toracico`[df$`tipo di dolore toracico`==3]="Asintomatico"
 df$`tipo di dolore toracico`=as.factor(df$`tipo di dolore toracico`)


 df$`glicemia a digiuno`[df$`glicemia a digiuno`==0] ="minore di 120 mg/ml"
 df$`glicemia a digiuno`[df$`glicemia a digiuno`==1] ="maggiore di 120 mg/ml"
 df$`glicemia a digiuno`=as.factor(df$`glicemia a digiuno`) 


 df$`elettrocardiogramma a riposo`[df$`elettrocardiogramma a riposo`==0]="Normale"
 df$`elettrocardiogramma a riposo`[df$`elettrocardiogramma a riposo`==1]="con anomalia dell'onda  ST-T"
 df$`elettrocardiogramma a riposo`[df$`elettrocardiogramma a riposo`==2]="Ipertrofia ventricolare sinistra"
 df$`elettrocardiogramma a riposo`= as.factor(df$`elettrocardiogramma a riposo`)

 df$`malattia al cuore`[df$`malattia al cuore`==0]="No"
 df$`malattia al cuore`[df$`malattia al cuore`==1]="Si"

Visualizzo informazioni sulle variabili numeriche come min, max, media, mediana, 1°quartile, 3° quartile ecc e per le variabili categoriche il numero di elementi di ciascun livello:

 summary(df)

Alcuni grafici relativi al campione :

 df %>%
  ggplot(aes(`pressione sanguigna a riposo`, fill=`malattia al cuore`))+
  geom_histogram(binwidth =  10, colour="gray")
 df %>%
  ggplot(aes(`colesterolo in mg/dl`, fill=`malattia al cuore`))+
  geom_histogram(binwidth =  10, colour="gray")
 df %>%
  ggplot(aes(`tipo di dolore toracico`, fill=`malattia al cuore`))+
  geom_bar()

Parte 4: Modellizzazione e previsione[modifica]

Divido il dataset heart in un training set costituito dal 70% delle osservazioni casuali, ottenendo 213 osservazioni, ed in un testing set costituito dalle rimanenti 90 osservazioni:

 train <- createDataPartition(heart$target,p=0.7,list = FALSE)
 training <- heart[train,]
 testing <- heart[-train,]

 training$target <- as.factor(training$target)
 testing$target <- as.factor(testing$target)

Utilizzando l'algoritmo Random Forest costruisco un modello previsionale sul training set che mi dà un'Accuracy quasi del 100% e sul testing set un'Accuracy dell'80% per cui il modello così ottenuto, con cui si predice se il paziente ha malattie al cuore oppure no, si può ritenere valido.

 model <-  train( target ~ .,data=training, method="rf", verbose=FALSE )

 p3 <- predict(model,newdata = training)
 print(confusionMatrix(p3,training$target)) 

 p3 <- predict(model,newdata = testing)
 print(confusionMatrix(p3,testing$target))
Confusion Matrix and Statistics
         Reference
Prediction   0   1
         0  97   0
         1   1 115
                                         
              Accuracy : 0.9953          
                95% CI : (0.9741, 0.9999)
   No Information Rate : 0.5399          
   P-Value [Acc > NIR] : <2e-16          
                                         
                 Kappa : 0.9905          
                                         
Mcnemar's Test P-Value : 1               
                                         
           Sensitivity : 0.9898          
           Specificity : 1.0000          
        Pos Pred Value : 1.0000          
        Neg Pred Value : 0.9914          
            Prevalence : 0.4601          
        Detection Rate : 0.4554          
  Detection Prevalence : 0.4554          
     Balanced Accuracy : 0.9949          
                                         
      'Positive' Class : 0               
                                         
Confusion Matrix and Statistics
         Reference
Prediction  0  1
         0 33 11
         1  7 39
                                         
              Accuracy : 0.8             
                95% CI : (0.7025, 0.8769)
   No Information Rate : 0.5556          
   P-Value [Acc > NIR] : 1.034e-06       
                                         
                 Kappa : 0.599           
                                         
Mcnemar's Test P-Value : 0.4795          
                                         
           Sensitivity : 0.8250          
           Specificity : 0.7800          
        Pos Pred Value : 0.7500          
        Neg Pred Value : 0.8478          
            Prevalence : 0.4444          
        Detection Rate : 0.3667          
  Detection Prevalence : 0.4889          
     Balanced Accuracy : 0.8025          
                                         
      'Positive' Class : 0               

Esempio di diagnosi[modifica]

Per un uomo di 37 anni con i dati di seguito indicati il modello fa una diagnosi di malattia al cuore:

 predict(model, newdata= data.frame(age=37, sex=1, cp=2, trestbps=130, chol=250, fbs=0, restecg=1, thalach=187, exang=0, oldpeak=3.5, slope=0, ca=0, thal=2))
[1] 1
Levels: 0 1