Applicazioni pratiche di machine learning/Diagnosi di malattie

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