Costruisci un grafico della conoscenza biomedica con la PNL

Nodo di origine: 1401511

Ho già dimostrato come farlo creare un grafico della conoscenza da una pagina di Wikipedia. Tuttavia, poiché il post ha ricevuto molta attenzione, ho deciso di esplorare altri domini in cui ha senso utilizzare le tecniche di NLP per costruire un grafo della conoscenza. A mio avviso, il campo biomedico è un ottimo esempio in cui rappresentare i dati come un grafico ha senso poiché spesso si analizzano interazioni e relazioni tra geni, malattie, farmaci, proteine ​​e altro ancora.

Sottografico di esempio che mostra le relazioni dell'acido ascorbico con altri concetti biomedici. Immagine dell'autore.

Nella visualizzazione di cui sopra, abbiamo l'acido ascorbico, noto anche come vitamina C, e alcune delle sue relazioni con altri concetti. Ad esempio, mostra che la vitamina C potrebbe essere usata per curare la gastrite cronica.

Ora, potresti avere un team di esperti del settore che mappa per te tutte quelle connessioni tra farmaci, malattie e altri concetti biomedici. Ma, sfortunatamente, non molti di noi possono permettersi di assumere un team di medici che faccia il lavoro per noi. In tal caso, possiamo ricorrere all'utilizzo di tecniche di NLP per estrarre automaticamente tali relazioni. La parte buona è che possiamo usare una pipeline di PNL per leggere tutti i documenti di ricerca là fuori, e la parte negativa è che non tutti i risultati ottenuti saranno perfetti. Tuttavia, dato che non ho un team di scienziati pronto al mio fianco per estrarre relazioni manualmente, ricorrerò all'utilizzo di tecniche di PNL per costruire un mio grafico della conoscenza biomedica.

Userò un singolo documento di ricerca in questo post del blog per guidarti attraverso tutti i passaggi necessari per costruire un grafico della conoscenza biomedica – Ingegneria tissutale della rigenerazione cutanea e della crescita dei capelli.

Il documento è stato scritto da Mohammadreza Ahmadi. La versione PDF dell'articolo è disponibile con la licenza CC0 1.0. Per costruire un grafico della conoscenza, analizzeremo i seguenti passaggi:

  • Lettura di un documento PDF con OCR
  • Preelaborazione del testo
  • Riconoscimento e collegamento di concetti biomedici
  • Estrazione della relazione
  • Arricchimento database esterno

Entro la fine di questo post, costruirai un grafico con il seguente schema.

Schema grafico biomedico. Immagine dell'autore.

Utilizzeremo Neo4j, un database di grafici che presenta il modello di grafico delle proprietà etichettato, per memorizzare il nostro grafico. Ogni articolo può avere uno o più autori. Divideremo il contenuto dell'articolo in frasi e useremo la PNL per estrarre sia le entità mediche che le loro relazioni. Potrebbe essere un po' controintuitivo memorizzare le relazioni tra le entità come nodi intermedi anziché come relazioni. Il fattore critico alla base di questa decisione è che vogliamo avere un audit trail del testo sorgente da cui è stata estratta la relazione. Con il modello grafico delle proprietà con etichetta, non puoi avere una relazione che punta a un'altra relazione. Per questo motivo, riformuliamo la connessione tra concetti medici in un nodo intermedio. Ciò consentirà anche a un esperto di dominio di valutare se una relazione è stata estratta correttamente o meno.

Lungo la strada, dimostrerò anche le applicazioni dell'utilizzo del grafico costruito per cercare e analizzare le informazioni memorizzate.

Facciamoci un tuffo!

Se questo contenuto educativo approfondito è utile per te, iscriviti alla nostra mailing list di ricerca sull'IA per essere avvisato quando rilasciamo nuovo materiale.

Lettura di un documento PDF con OCR

Come accennato, la versione PDF del documento di ricerca è accessibile al pubblico con la licenza CC0 1.0, il che significa che possiamo scaricarlo facilmente con Python. Useremo il pitesseratto libreria per estrarre il testo dal PDF. Per quanto ne so, la libreria pytesseract è una delle librerie più popolari per l'OCR. Se vuoi seguire insieme ad esempi di codice, ho preparato a Quaderno Google Colab, quindi non devi copiare e incollare il codice da solo.

import requests
import pdf2image
import pytesseract pdf = requests.get('https://arxiv.org/pdf/2110.03526.pdf')
doc = pdf2image.convert_from_bytes(pdf.content) # Get the article text
article = []
for page_number, page_data in enumerate(doc): txt = pytesseract.image_to_string(page_data).encode("utf-8") # Sixth page are only references if page_number < 6: article.append(txt.decode("utf-8"))
article_txt = " ".join(article)

Preelaborazione del testo

Ora che abbiamo il contenuto dell'articolo disponibile, andremo avanti e rimuoveremo i titoli delle sezioni e le descrizioni delle figure dal testo. Successivamente, divideremo il testo in frasi.

import nltk
nltk.download('punkt') def clean_text(text): """Remove section titles and figure descriptions from text""" clean = "n".join([row for row in text.split("n") if (len(row.split(" "))) > 3 and not (row.startswith("(a)")) and not row.startswith("Figure")]) return clean text = article_txt.split("INTRODUCTION")[1]
ctext = clean_text(text)
sentences = nltk.tokenize.sent_tokenize(ctext)

Collegamento di entità nominative biomediche

Ora arriva la parte eccitante. Per coloro che non conoscono la PNL e il riconoscimento e il collegamento di entità denominate, iniziamo con alcune nozioni di base. Le tecniche di riconoscimento di entità nominative vengono utilizzate per rilevare entità o concetti rilevanti nel testo. Ad esempio, nel campo biomedico, vogliamo identificare vari geni, farmaci, malattie e altri concetti nel testo.

Estrazione di concetti biomedici. Immagine dell'autore.

In questo esempio, il modello NLP ha identificato nel testo geni, malattie, farmaci, specie, mutazioni e percorsi. Come accennato, questo processo è chiamato riconoscimento di entità denominata. Un aggiornamento al riconoscimento dell'entità denominata è il cosiddetto collegamento di entità denominata. La tecnica di collegamento dell'entità denominata rileva i concetti rilevanti nel testo e cerca di mapparli alla base di conoscenza di destinazione. Nel dominio biomedico, alcune delle basi di conoscenza target sono:

Perché vorremmo collegare le entità mediche a una base di conoscenza di destinazione? Il motivo principale è che ci aiuta a gestire la disambiguazione dell'entità. Ad esempio, non vogliamo entità separate nel grafico che rappresentino l'acido ascorbico e la vitamina C poiché gli esperti di dominio possono dirti che sono la stessa cosa. Il motivo secondario è che mappando i concetti su una base di conoscenza di destinazione, possiamo arricchire il nostro modello grafico recuperando informazioni sui concetti mappati dalla base di conoscenza di destinazione. Se utilizziamo nuovamente l'esempio dell'acido ascorbico, potremmo facilmente recuperare ulteriori informazioni dal database CHEBI se ne conosciamo già CHEBI id.

Dati di arricchimento disponibili sull'acido ascorbico sul sito web CHEBI. Tutti i contenuti del sito sono disponibili sotto Licenza CC BY 4.0. Immagine dell'autore.

Ho cercato per un po 'di tempo un collegamento di entità biomedico pre-addestrato open source decente. Molti modelli di PNL si concentrano sull'estrazione solo di un sottoinsieme specifico di concetti medici come geni o malattie. È ancora più raro trovare un modello che rilevi la maggior parte dei concetti medici e li colleghi a una base di conoscenza di destinazione. Per fortuna mi sono imbattuto BERNA[1], uno strumento di riconoscimento di entità biomediche neurali e normalizzazione multi-tipo. Se ho capito bene, è un modello BioBert messo a punto con vari modelli di collegamento di entità denominate integrati per mappare concetti su basi di conoscenza di destinazione biomedica. Non solo, ma forniscono anche un endpoint REST gratuito, quindi non dobbiamo affrontare il mal di testa di far funzionare le dipendenze e il modello. La visualizzazione biomedica del riconoscimento di entità denominate che ho usato sopra è stata creata utilizzando il modello BERN, quindi sappiamo che rileva geni, malattie, farmaci, specie, mutazioni e percorsi nel testo.

Sfortunatamente, il modello BERN non assegna gli ID della knowledge base di destinazione a tutti i concetti. Quindi ho preparato uno script che prima cerca se viene fornito un ID distinto per un concetto e, in caso contrario, utilizzerà il nome dell'entità come ID. Calcoleremo anche lo sha256 del testo delle frasi per identificare frasi specifiche più facilmente in seguito quando faremo l'estrazione di relazioni.

import hashlib def query_raw(text, url="https://bern.korea.ac.kr/plain"): """Biomedical entity linking API""" return requests.post(url, data={'sample_text': text}).json() entity_list = []
# The last sentence is invalid
for s in sentences[:-1]: entity_list.append(query_raw(s)) parsed_entities = []
for entities in entity_list: e = [] # If there are not entities in the text if not entities.get('denotations'): parsed_entities.append({'text':entities['text'], 'text_sha256': hashlib.sha256(entities['text'].encode('utf-8')).hexdigest()}) continue for entity in entities['denotations']: other_ids = [id for id in entity['id'] if not id.startswith("BERN")] entity_type = entity['obj'] entity_name = entities['text'][entity['span']['begin']:entity['span']['end']] try: entity_id = [id for id in entity['id'] if id.startswith("BERN")][0] except IndexError: entity_id = entity_name e.append({'entity_id': entity_id, 'other_ids': other_ids, 'entity_type': entity_type, 'entity': entity_name}) parsed_entities.append({'entities':e, 'text':entities['text'], 'text_sha256': hashlib.sha256(entities['text'].encode('utf-8')).hexdigest()})

Ho ispezionato i risultati del collegamento dell'entità denominata e, come previsto, non è perfetto. Ad esempio, non identifica le cellule staminali come concetto medico. D'altra parte, ha rilevato una singola entità denominata "cuore, cervello, nervi e reni". Tuttavia, Berna è ancora il miglior modello biomedico open source che ho trovato durante la mia indagine.

Costruisci un grafico della conoscenza

Prima di esaminare le tecniche di estrazione di relazioni, costruiremo un grafo della conoscenza biomedica utilizzando solo entità ed esamineremo le possibili applicazioni. Come accennato, ho preparato un Quaderno Google Colab che puoi usare per seguire gli esempi di codice in questo post. Per memorizzare il nostro grafico, utilizzeremo Neo4j. Non devi occuparti della preparazione di un ambiente Neo4j locale. Invece, puoi utilizzare un'istanza Sandbox Neo4j gratuita.

Sabbiera Neo4j

Avvia la Progetto vuoto nella sandbox e copia i dettagli della connessione sul notebook Colab.

Dettagli di connessione della sandbox Neo4j. Immagine dell'autore.

Ora puoi procedere e preparare la connessione Neo4j nel notebook.

from neo4j import GraphDatabase
import pandas as pd host = 'bolt://3.236.182.55:7687'
user = 'neo4j'
password = 'hydrometer-ditches-windings'
driver = GraphDatabase.driver(host,auth=(user, password)) def neo4j_query(query, params=None): with driver.session() as session: result = session.run(query, params) return pd.DataFrame([r.values() for r in result], columns=result.keys())

Inizieremo importando l'autore e l'articolo nel grafico. Il nodo dell'articolo conterrà solo il titolo.

author = article_txt.split("n")[0]
title = " ".join(article_txt.split("n")[2:4]) neo4j_query("""
MERGE (a:Author{name:$author})
MERGE (b:Article{title:$title})
MERGE (a)-[:WROTE]->(b)
""", {'title':title, 'author':author})

Se apri il browser Neo4j, dovresti vedere il grafico seguente.

Immagine dell'autore.

Puoi importare le frasi e le entità menzionate eseguendo la seguente query Cypher:

neo4j_query("""
MATCH (a:Article)
UNWIND $data as row
MERGE (s:Sentence{id:row.text_sha256})
SET s.text = row.text
MERGE (a)-[:HAS_SENTENCE]->(s)
WITH s, row.entities as entities
UNWIND entities as entity
MERGE (e:Entity{id:entity.entity_id})
ON CREATE SET e.other_ids = entity.other_ids, e.name = entity.entity, e.type = entity.entity_type
MERGE (s)-[m:MENTIONS]->(e)
ON CREATE SET m.count = 1
ON MATCH SET m.count = m.count + 1
""", {'data': parsed_entities})

È possibile eseguire la seguente query Cypher per esaminare il grafico costruito:

MATCH p=(a:Article)-[:HAS_SENTENCE]->()-[:MENTIONS]->(e:Entity)
RETURN p LIMIT 25

Se hai importato correttamente i dati, dovresti vedere una visualizzazione simile.

Estrazione di entità memorizzata come grafico. Immagine dell'autore.

Applicazioni dei grafici della conoscenza

Anche senza il flusso di estrazione delle relazioni, ci sono già un paio di casi d'uso per il nostro grafico.

Motore di ricerca

Potremmo usare il nostro grafico come motore di ricerca. Ad esempio, puoi utilizzare la seguente query Cypher per trovare frasi o articoli che menzionano un'entità medica specifica.

MATCH (e:Entity)<-[:MENTIONS]-(s:Sentence)
WHERE e.name = "autoimmune diseases"
RETURN s.text as result

Risultati

Immagine dell'autore.

Analisi di co-occorrenza

La seconda opzione è l'analisi della co-occorrenza. Potresti definire la co-occorrenza tra entità mediche se compaiono nella stessa frase o articolo. Ho trovato un articolo[2] che utilizza la rete di co-occorrenza medica per prevedere nuove possibili connessioni tra entità mediche.

Previsione dei collegamenti in una rete di co-occorrenza MeSH: risultati preliminari – PubMed

È possibile utilizzare la seguente query Cypher per trovare entità che spesso si trovano nella stessa frase.

MATCH (e1:Entity)<-[:MENTIONS]-()-[:MENTIONS]->(e2:Entity)
MATCH (e1:Entity)<-[:MENTIONS]-()-[:MENTIONS]->(e2:Entity)
WHERE id(e1) < id(e2)
RETURN e1.name as entity1, e2.name as entity2, count(*) as cooccurrence
ORDER BY cooccurrence
DESC LIMIT 3

Risultati

entità 1 entità 2 coincidenza
malattie della pelle ulcere diabetiche 2
ferite croniche ulcere diabetiche 2
malattie della pelle ferite croniche 2

Ovviamente, i risultati sarebbero migliori se analizzassimo migliaia o più articoli.

Ispeziona la competenza dell'autore

Puoi anche utilizzare questo grafico per trovare l'esperienza dell'autore esaminando le entità mediche di cui scrivono più frequentemente. Con queste informazioni, potresti anche suggerire future collaborazioni.

Esegui la seguente query Cypher per ispezionare quali entità mediche il nostro unico autore ha menzionato nel documento di ricerca.

MATCH (a:Author)-[:WROTE]->()-[:HAS_SENTENCE]->()-[:MENTIONS]->(e:Entity)
RETURN a.name as author, e.name as entity,
MATCH (a:Author)-[:WROTE]->()-[:HAS_SENTENCE]->()-[:MENTIONS]->(e:Entity)
RETURN a.name as author, e.name as entity, count(*) as count
ORDER BY count DESC
LIMIT 5

Risultati

autore entità contare
Mohammadreza Ahmadi collagene 9
Mohammadreza Ahmadi ustioni 4
Mohammadreza Ahmadi malattie della pelle 4
Mohammadreza Ahmadi enzimi collagenasi 2
Mohammadreza Ahmadi Epidermolisi bollosa 2

Estrazione della relazione

Ora cercheremo di estrarre relazioni tra concetti medici. Dalla mia esperienza, l'estrazione della relazione è almeno un ordine di grandezza più difficile dell'estrazione dell'entità denominata. Se non dovresti aspettarti risultati perfetti con il collegamento di entità con nome, allora puoi sicuramente aspettarti alcuni errori con la tecnica di estrazione delle relazioni.

Ho cercato modelli di estrazione di relazioni biomediche disponibili, ma non ho trovato nulla che funzioni immediatamente o che non richieda una messa a punto. Sembra che il campo dell'estrazione delle relazioni sia all'avanguardia e, si spera, vedremo più attenzione al riguardo in futuro. Sfortunatamente, non sono un esperto di PNL, quindi ho evitato di mettere a punto il mio modello. Invece, useremo l'estrattore di relazioni zero-shot basato sulla carta Esplorando il limite zero-shot di FewRel[3]. Anche se non consiglierei di mettere in produzione questo modello, è abbastanza buono per una semplice dimostrazione. Il modello è disponibile su abbracciare il viso, quindi non dobbiamo occuparci della formazione o dell'impostazione del modello.

from transformers import AutoTokenizer
from zero_shot_re import RelTaggerModel, RelationExtractor model = RelTaggerModel.from_pretrained("fractalego/fewrel-zero-shot")
tokenizer = AutoTokenizer.from_pretrained("bert-large-uncased-whole-word-masking-finetuned-squad")
relations = ['associated', 'interacts']
extractor = RelationExtractor(model, tokenizer, relations)

Con l'estrattore di relazioni zero-shot, puoi definire quali relazioni desideri rilevare. In questo esempio, ho usato il associato ed interagisce relazioni. Ho anche provato tipi di relazione più specifici come dolcetti, cause e altri, ma i risultati non sono stati eccezionali.

Con questo modello, devi definire tra quali coppie di entità desideri rilevare le relazioni. Utilizzeremo i risultati del collegamento dell'entità denominata come input per il processo di estrazione della relazione. Innanzitutto, troviamo tutte le frasi in cui sono menzionate due o più entità e quindi le eseguiamo attraverso il modello di estrazione delle relazioni per estrarre eventuali connessioni. Ho anche definito un valore di soglia di 0.85, il che significa che se un modello prevede un collegamento tra entità con una probabilità inferiore a 0.85, ignoreremo la previsione.

import itertools
# Candidate sentence where there is more than a single entity present
candidates = [s for s in parsed_entities if (s.get('entities')) and (len(s['entities']) &gt; 1)]
predicted_rels = []
for c in candidates: combinations = itertools.combinations([{'name':x['entity'], 'id':x['entity_id']} for x in c['entities']], 2) for combination in list(combinations): try: ranked_rels = extractor.rank(text=c['text'].replace(",", " "), head=combination[0]['name'], tail=combination[1]['name']) # Define threshold for the most probable relation if ranked_rels[0][1] &gt; 0.85: predicted_rels.append({'head': combination[0]['id'], 'tail': combination[1]['id'], 'type':ranked_rels[0][0], 'source': c['text_sha256']}) except: pass # Store relations to Neo4j
neo4j_query("""
UNWIND $data as row
MATCH (source:Entity {id: row.head})
MATCH (target:Entity {id: row.tail})
MATCH (text:Sentence {id: row.source})
MERGE (source)-[:REL]-&gt;(r:Relation {type: row.type})-[:REL]-&gt;(target)
MERGE (text)-[:MENTIONS]-&gt;(r)
""", {'data': predicted_rels})

Memorizziamo le relazioni e il testo sorgente utilizzato per estrarre tale relazione nel grafico.

Relazioni estratte memorizzate in un grafico. Immagine dell'autore.

È possibile esaminare le relazioni estratte tra le entità e il testo di origine con la seguente query Cypher:

MATCH (s:Entity)-[:REL]->(r:Relation)-[:REL]->(t:Entity), (r)<-[:MENTIONS]-(st:Sentence)
RETURN s.name as source_entity, t.name as target_entity, r.type as type, st.text as source_text

Risultati

Immagine dell'autore.

Come accennato, il modello di PNL che ho utilizzato per estrarre le relazioni non è perfetto, e siccome non sono un medico, non so quante connessioni abbia perso. Tuttavia, quelli rilevati sembrano ragionevoli.

Arricchimento database esterno

Come accennato in precedenza, possiamo ancora utilizzare i database esterni come CHEBI o MESH per arricchire il nostro grafico. Ad esempio, il nostro grafico contiene un'entità medica Epidermolisi bollosa e sappiamo anche il suo ID MeSH.

È possibile recuperare l'ID MeSH dell'epidermolisi bollosa con la seguente query:

MATCH (e:Entity)
WHERE e.name = "Epidermolysis bullosa"
RETURN e.name as entity, e.other_ids as other_ids

Potresti andare avanti e ispezionare il MeSH per trovare le informazioni disponibili:

Dati collegati a rete

Screenshot per autore. I dati sono stati forniti dalla National Library of Medicine degli Stati Uniti.

Ecco uno screenshot delle informazioni disponibili sul sito Web MeSH per l'epidermolisi bollosa. Come accennato, non sono un medico, quindi non so esattamente quale sarebbe il modo migliore per modellare queste informazioni in un grafico. Tuttavia, ti mostrerò come recuperare queste informazioni in Neo4j usando la procedura apoc.load.json per recuperare le informazioni dall'endpoint REST MeSH. E poi, puoi chiedere a un esperto di dominio di aiutarti a modellare queste informazioni.

La query Cypher per recuperare le informazioni dall'endpoint REST MeSH è:

MATCH (e:Entity)
WHERE e.name = "Epidermolysis bullosa"
WITH e, [id in e.other_ids WHERE id contains "MESH" | split(id,":")[1]][0] as meshId
CALL apoc.load.json("https://id.nlm.nih.gov/mesh/lookup/details?descriptor=" + meshId) YIELD value
RETURN value

Grafico della conoscenza come input di dati di machine learning

Come pensiero finale, ti illustrerò rapidamente come utilizzare il grafico della conoscenza biomedica come input per un flusso di lavoro di apprendimento automatico. Negli ultimi anni, ci sono state molte ricerche e progressi nel campo dell'incorporamento dei nodi. I modelli di incorporamento dei nodi traducono la topologia di rete nello spazio di incorporamento.

Copyright © 2017 Manan Shah, Gruppo SNAP. Immagine disponibile con licenza MIT in https://github.com/snap-stanford/cs224w-notes.

Supponiamo di aver costruito un grafico della conoscenza biomedica contenente entità e concetti medici, le loro relazioni e l'arricchimento da vari database medici. È possibile utilizzare le tecniche di incorporamento dei nodi per apprendere le rappresentazioni dei nodi, che sono vettori a lunghezza fissa, e inserirle nel flusso di lavoro di machine learning. Diverse applicazioni stanno utilizzando questo approccio che vanno dal riutilizzo del farmaco alla previsione di effetti collaterali o avversi. Ho trovato un documento di ricerca che utilizza previsione del collegamento per potenziali trattamenti di nuove malattie[4].

Conclusione

Il dominio biomedico è un ottimo esempio in cui sono applicabili i grafici della conoscenza. Esistono molte applicazioni che vanno dai semplici motori di ricerca ai flussi di lavoro di machine learning più complicati. Si spera che, leggendo questo post sul blog, ti sia venuta in mente alcune idee su come utilizzare i grafici della conoscenza biomedica per supportare le tue applicazioni. Puoi iniziare a Sandbox Neo4j gratuito e inizia a esplorare oggi.

Come sempre, il codice è disponibile su GitHub.

Riferimenti

[1] D.Kim et al., "Uno strumento di riconoscimento di entità con nome neurale e normalizzazione multi-tipo per l'estrazione di testi biomedici", in Accesso IEEE, vol. 7, pagg. 73729–73740, 2019, doi: 10.1109/ACCESS.2019.2920708.

[2] Kastrin A, Rindflesch TC, Hristovski D. Previsione del collegamento in una rete di co-occorrenza MeSH: risultati preliminari. Informazioni sulla tecnologia per la salute degli stalloni. 2014;205:579–83. PMID: 25160252.

[3] Cetoli, A. (2020). Esplorando il limite zero-shot di FewRel. In Atti del 28° Convegno Internazionale di Linguistica Computazionale (pagine 1447–1451). Comitato Internazionale di Linguistica Computazionale.

[4] Zhang, R., Hristovski, D., Schutte, D., Kastrin, A., Fiszman, M. e Kilicoglu, H. (2021). Riutilizzo di farmaci per COVID-19 tramite il completamento del grafico della conoscenza. Giornale di informatica biomedica, 115, 103696.

Questo articolo è stato pubblicato in origine Verso la scienza dei dati e ripubblicato su TOPBOTS con il permesso dell'autore.

Ti piace questo articolo? Iscriviti per ulteriori aggiornamenti AI.

Ti faremo sapere quando rilasceremo più istruzione tecnica.

Il post Costruisci un grafico della conoscenza biomedica con la PNL apparve prima TOPBOT.

Timestamp:

Di più da TOPBOT