Previsione dell’esito della sperimentazione clinica

Previsione del risultato della sperimentazione clinica

Parte 2: Prevedere gli esiti degli studi clinici utilizzando XGBoost

Nella prima parte di questa serie mi sono concentrato sull’incorporazione di dati del mondo reale multimodali derivati da ClinicalTrials.gov. In questo articolo implementerò un modello base XGBoost, lo addestrerò sulle incorporazioni che abbiamo creato nella Parte 1 e ne confrontarò le prestazioni con quelle del modello HINT (una rete neurale gerarchica a grafo) che ha ispirato questo progetto.

Schema del flusso di lavoro (immagine dell'autore)

Questi sono i passi che seguirò in questo articolo:

  • Caricare i set di dati di addestramento, validazione e test
  • Incorporare la molecola/i del farmaco, i criteri di inclusione/esclusione, le indicazioni della malattia, il promotore dello studio e il numero di partecipanti
  • Definire le metriche di valutazione
  • Addestrare il modello XGBoost e confrontarlo brevemente con le prestazioni del modello HINT
Focus per la parte 2 di questa serie: Prevedere gli esiti degli studi clinici basandosi sulle incorporazioni delle caratteristiche create nella <a href=Parte 1 (immagine dell’autore)” src=”https://ai.miximages.com/miro.medium.com/v2/resize:fit:640/format:webp/1*dLuTeQ_2qMrDUzamlbp1GQ.png”/>

Puoi seguire tutti i passaggi in questo notebook Jupyter: Tutorial sull’incorporazione degli studi clinici.

Carica i set di dati di addestramento, validazione e test

import osimport pandas as pdimport numpy as npimport pickle# Importa il set di dati di gioco (toy dataset)toy_df = pd.read_pickle('data/toy_df_full.pkl')train_df = toy_df[toy_df['split'] == 'train']val_df = toy_df[toy_df['split'] == 'valid']test_df = toy_df[toy_df['split'] == 'test']y_train = train_df['label']y_val = val_df['label']y_test = test_df['label']print(train_df.shape, val_df.shape, test_df.shape)print(y_train.shape, y_val.shape, y_test.shape)### Output:# (1028, 14) (146, 14) (295, 14)# (1028,) (146,) (295,)

Incorpora la molecola del farmaco, il protocollo, l’indicazione e il promotore dello studio

In questa sezione carichiamo i dizionari che abbiamo creato nella Parte 1 di questa serie e li utilizziamo per mappare i valori nei set di dati di addestramento, validazione e test nelle rispettive incorporazioni.

def incorpora_tutto(df):    print('forma di input: ', df.shape)    ### INCORPORA LE MOLECOLE DEL FARMACO ###    print('incorpora le molecole del farmaco..')    nctid2molecule_embedding_dict = load_nctid2molecule_embedding_dict()    h_m = np.stack(df['nctid'].map(nctid2molecule_embedding_dict))     print(f"molecole del farmaco incorporate con successo in {h_m.shape} dimensioni")    ### INCORPORA I PROTOCOLLI ###    print('incorpora i protocolli..')    nctid2protocol_embedding_dict = load_nctid2protocol_embedding_dict()    h_p = np.stack(df['nctid'].map(nctid2protocol_embedding_dict))    print(f"protocolli incorporati con successo in {h_p.shape} dimensioni")    ### INCORPORA LE INDICAZIONI DELLA MALATTIA ###    print('incorpora le indicazioni della malattia..')    nctid2disease_embedding_dict = load_nctid2disease_embedding_dict()    h_d = np.stack(df['nctid'].map(nctid2disease_embedding_dict))    print(f"indicazioni della malattia incorporate con successo in {h_d.shape} dimensioni")    ### INCORPORA I PROMOTORI DELLO STUDIO ###    print('incorpora i promotori dello studio..')    sponsor2embedding_dict = load_sponsor2embedding_dict()    h_s = np.stack(df['lead_sponsor'].map(sponsor2embedding_dict))    print(f"promotori dello studio incorporati con successo in {h_s.shape} dimensioni")    ### INCORPORA L'ISCRIZIONE ###    print('normalizza i numeri di iscrizione..')    iscrizione = pd.to_numeric(df['enrollment'] , errors='coerce')    if iscrizione.isna().sum() != 0:        print(f"riempimento di {iscrizione.isna().sum()} dati mancanti con il valore mediano")        iscrizione.fillna(int(iscrizione.median()), inplace=True)        print(f"riempimento dei dati mancanti con valore mediano: {iscrizione.isna().sum()} dati mancanti rimasti")    iscrizione = iscrizione.astype(int)    h_e = np.array((iscrizione - iscrizione.mean())/iscrizione.std()).reshape(len(df),-1)    print(f"iscrizione incorporata con successo in {h_e.shape} dimensioni")    ### COMBINA TUTTE LE INCORPORAZIONI ###    embedded_df = pd.DataFrame(data=np.column_stack((h_m, h_p, h_d, h_s, h_e)))    print('forma di output: ', embedded_df.shape)    return embedded_df# Incorpora i datiX_train = incorpora_tutto(train_df)X_val = incorpora_tutto(val_df)X_test = incorpora_tutto(test_df)

Definire le metriche di valutazione

Utilizzeremo le stesse metriche di valutazione proposte nell’articolo HINT: ROC AUC, F1, PR-AUC, Precisione, Richiamo e Accuratezza.

Allenare il modello XGBoost e prevedere le etichette di allenamento, validazione e test

import xgboost as xgb# Creare un classificatore XGBoost con gli iperparametri specificatixgb_classifier = xgb.XGBClassifier(    learning_rate=0.1,    max_depth=3,    n_estimators=200,    objective='binary:logistic',  # per la classificazione binaria    random_state=42)# Allenare il modello XGBoostxgb_classifier.fit(X_train, y_train)# Fare le previsioniy_train_pred = xgb_classifier.predict(X_train)y_val_pred = xgb_classifier.predict(X_val)y_test_pred = xgb_classifier.predict(X_test)print('-----------Risultati sui dati di allenamento:-----------')print_results(y_train_pred, y_train)print('-----------Risultati sui dati di validazione:-----------')print_results(y_val_pred, y_val)print('-----------Risultati sui dati di test:-----------')print_results(y_test_pred, y_test)### Output:#-----------Risultati sui dati di allenamento:-----------# ROC AUC: 1.0# F1: 1.0# PR-AUC: 1.0# Precisione: 1.0# Richiamo: 1.0# Accuratezza: 1.0# Rapporto previsione 1: 0.661# Rapporto etichetta 1: 0.661# -----------Risultati sui dati di validazione:-----------# ROC AUC: 0.765# F1: 0.817# PR-AUC: 0.799# Precisione: 0.840# Richiamo: 0.795# Accuratezza: 0.773# Rapporto previsione 1: 0.602# Rapporto etichetta 1: 0.636# -----------Risultati sui dati di test:-----------# ROC AUC: 0.742# F1: 0.805# PR-AUC: 0.757# Precisione: 0.790# Richiamo: 0.821# Accuratezza: 0.759# Rapporto previsione 1: 0.630# Rapporto etichetta 1: 0.606

Confrontare le prestazioni con il modello HINT

Questo semplice modello XGBoost è stato allenato su caratteristiche di incorporamento per molecola/i di farmaco, criteri di inclusione/esclusione, indicazione/i di malattia, sponsor dello studio e numero di partecipanti, mentre gli autori di HINT non hanno utilizzato le ultime due caratteristiche: sponsor dello studio e numero di partecipanti. Abbiamo utilizzato diversi strumenti di incorporamento di modelli di linguaggio di grandi dimensioni come BioBERT e SBERT, e abbiamo utilizzato la codifica di Morgan per le rappresentazioni dei farmaci, mentre gli autori di HINT hanno utilizzato una varietà di reti neurali per tutti i loro incorporamenti.

Dalla figura sottostante possiamo vedere che i nostri incorporamenti delle caratteristiche, allenati da un semplice modello XGBoost, si comportano piuttosto bene rispetto al modello più sofisticato HINT. Il nostro progetto ha una precisione e un’accuratezza migliori su questo dataset, ma un richiamo peggiore.

Confronto delle prestazioni di questo progetto con quelle del progetto HINT (immagine dell'autore)

Conclusione

I prossimi passi potrebbero includere un’analisi per capire fino a che punto l’aggiunta delle caratteristiche sponsor dello studio e numero di partecipanti stia contribuendo al miglioramento delle prestazioni (su alcune metriche) rispetto ad altri fattori come la scelta del modello e le tecniche di incorporamento. Intuitivamente, sembra che queste caratteristiche possano migliorare le prestazioni predittive, poiché alcuni sponsor hanno storicamente ottenuto risultati migliori di altri, e ci si potrebbe aspettare una relazione anche tra la dimensione dello studio e l’esito.

Ora potreste chiedervi: “Qual è l’utilità di un modello predittivo del genere? Non possiamo fare affidamento su un simile modello e rinunciare all’esecuzione dello studio?” E avete ragione (anche se alcune aziende stanno creando copie virtuali di pazienti con l’obiettivo di condurre studi in modo virtuale). Un modello come quello presentato in questa serie potrebbe, ad esempio, essere utilizzato per migliorare l’analisi della potenza di un trial clinico, una pratica statistica correlata. Un’analisi di potenza viene utilizzata per determinare il numero ottimale di partecipanti da arruolare in uno specifico studio, e bisogna fare un’ipotesi forte sull’effetto del trattamento per eseguire tale analisi. Un modello predittivo che utilizza informazioni sul trial come la struttura della molecola del farmaco, l’indicazione della malattia e i criteri di idoneità al trial, come il modello che abbiamo implementato qui, può aiutare potenzialmente a creare un’analisi di potenza più accurata.

Riferimenti

  • Fu, Tianfan, et al. “Hint: Rete interattiva gerarchica per previsioni dei risultati degli studi clinici.” Patterns 3.4 (2022).