Construya un gráfico de conocimiento biomédico con PNL

Nodo de origen: 1401511

Ya he demostrado cómo crear un gráfico de conocimiento a partir de una página de Wikipedia. Sin embargo, dado que la publicación atrajo mucha atención, decidí explorar otros dominios donde el uso de técnicas de PNL para construir un gráfico de conocimiento tiene sentido. En mi opinión, el campo biomédico es un excelente ejemplo en el que representar los datos como un gráfico tiene sentido, ya que a menudo se analizan interacciones y relaciones entre genes, enfermedades, medicamentos, proteínas y más.

Subgráfico de ejemplo que muestra las relaciones del ácido ascórbico con otros conceptos biomédicos. Imagen del autor.

En la visualización anterior, tenemos ácido ascórbico, también conocido como vitamina C, y algunas de sus relaciones con otros conceptos. Por ejemplo, muestra que la vitamina C podría usarse para tratar la gastritis crónica.

Ahora, podría hacer que un equipo de expertos en el dominio mapee todas esas conexiones entre medicamentos, enfermedades y otros conceptos biomédicos para usted. Pero, desafortunadamente, no muchos de nosotros podemos permitirnos contratar a un equipo de médicos para que hagan el trabajo por nosotros. En ese caso, podemos recurrir al uso de técnicas de PNL para extraer esas relaciones de forma automática. Lo bueno es que podemos usar un canal de PNL para leer todos los trabajos de investigación que existen, y lo malo es que no todos los resultados obtenidos serán perfectos. Sin embargo, dado que no tengo un equipo de científicos listo a mi lado para extraer relaciones manualmente, recurriré al uso de técnicas de PNL para construir mi propio gráfico de conocimiento biomédico.

Usaré un solo trabajo de investigación en esta publicación de blog para guiarlo a través de todos los pasos necesarios para construir un gráfico de conocimiento biomédico: Ingeniería de tejidos de regeneración de la piel y crecimiento del cabello.

El papel fue escrito por Mohammadreza Ahmadi. La versión PDF del artículo está disponible bajo la licencia CC0 1.0. Seguiremos los siguientes pasos para construir un gráfico de conocimiento:

  • Lectura de un documento PDF con OCR
  • Preprocesamiento de texto
  • Reconocimiento y vinculación de conceptos biomédicos
  • Extracción de relaciones
  • Enriquecimiento de bases de datos externas

Al final de esta publicación, construirá un gráfico con el siguiente esquema.

Esquema gráfico biomédico. Imagen del autor.

Usaremos Neo4j, una base de datos de gráficos que presenta el modelo de gráfico de propiedades etiquetado, para almacenar nuestro gráfico. Cada artículo puede tener uno o más autores. Dividiremos el contenido del artículo en oraciones y usaremos NLP para extraer tanto las entidades médicas como sus relaciones. Puede ser un poco contrario a la intuición que almacenemos las relaciones entre entidades como nodos intermedios en lugar de relaciones. El factor crítico detrás de esta decisión es que queremos tener una pista de auditoría del texto fuente del que se extrajo la relación. Con el modelo de gráfico de propiedades etiquetado, no puede tener una relación que apunte a otra relación. Por esta razón, refactorizamos la conexión entre conceptos médicos en un nodo intermedio. Esto también permitirá que un experto en el dominio evalúe si una relación se extrajo correctamente o no.

En el camino, también demostraré las aplicaciones del uso del gráfico construido para buscar y analizar información almacenada.

¡Vamos a sumergirnos en esto!

Si este contenido educativo en profundidad es útil para usted, suscríbete a nuestra lista de correo de investigación de IA ser alertado cuando lancemos nuevo material.

Lectura de un documento PDF con OCR

Como se mencionó, la versión en PDF del trabajo de investigación está disponible para el público bajo la licencia CC0 1.0, lo que significa que podemos descargarla fácilmente con Python. estaremos usando el pytesseract biblioteca para extraer texto del PDF. Hasta donde yo sé, la biblioteca pytesseract es una de las bibliotecas más populares para OCR. Si desea seguir los ejemplos de código, he preparado un Bloc de notas de Google Colab, para que no tenga que copiar y pegar el código usted mismo.

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)

Preprocesamiento de texto

Ahora que tenemos el contenido del artículo disponible, continuaremos y eliminaremos los títulos de las secciones y las descripciones de las figuras del texto. A continuación, dividiremos el texto en oraciones.

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)

Vinculación de entidad nombrada biomédica

Ahora viene la parte emocionante. Para aquellos nuevos en NLP y reconocimiento y vinculación de entidades nombradas, comencemos con algunos conceptos básicos. Las técnicas de reconocimiento de entidades nombradas se utilizan para detectar entidades o conceptos relevantes en el texto. Por ejemplo, en el dominio biomédico, queremos identificar varios genes, medicamentos, enfermedades y otros conceptos en el texto.

Extracción de conceptos biomédicos. Imagen del autor.

En este ejemplo, el modelo NLP identificó genes, enfermedades, fármacos, especies, mutaciones y vías en el texto. Como se mencionó, este proceso se llama reconocimiento de entidad nombrada. Una actualización del reconocimiento de entidades nombradas es la llamada vinculación de entidades nombradas. La técnica de vinculación de entidades nombradas detecta conceptos relevantes en el texto e intenta asignarlos a la base de conocimientos de destino. En el dominio biomédico, algunas de las bases de conocimiento objetivo son:

¿Por qué querríamos vincular entidades médicas a una base de conocimiento de destino? La razón principal es que nos ayuda a lidiar con la desambiguación de entidades. Por ejemplo, no queremos entidades separadas en el gráfico que representen el ácido ascórbico y la vitamina C, ya que los expertos en el campo pueden decirle que son lo mismo. La razón secundaria es que al asignar conceptos a una base de conocimiento de destino, podemos enriquecer nuestro modelo gráfico al obtener información sobre los conceptos asignados de la base de conocimiento de destino. Si usamos el ejemplo del ácido ascórbico nuevamente, podríamos obtener fácilmente información adicional de la base de datos CHEBI si ya conocemos su Identificación de CHEBI.

Datos de enriquecimiento disponibles sobre el ácido ascórbico en el sitio web de CHEBI. Todo el contenido del sitio web está disponible bajo Licencia CC BY 4.0. Imagen del autor.

He estado buscando un enlace de entidad biomédica nombrada preentrenada de código abierto decente durante algún tiempo. Muchos modelos de PNL se enfocan en extraer solo un subconjunto específico de conceptos médicos como genes o enfermedades. Es aún más raro encontrar un modelo que detecte la mayoría de los conceptos médicos y los vincule a una base de conocimiento de destino. por suerte me he topado BERNA[1], una herramienta de normalización multitipo y reconocimiento de entidades biomédicas neurales. Si entiendo correctamente, es un modelo BioBert ajustado con varios modelos de vinculación de entidades nombradas integrados para mapear conceptos a bases de conocimiento de objetivos biomédicos. No solo eso, sino que también proporcionan un extremo REST gratuito, por lo que no tenemos que lidiar con el dolor de cabeza de hacer que las dependencias y el modelo funcionen. La visualización biomédica de reconocimiento de entidades nombradas que he usado anteriormente se creó utilizando el modelo BERN, por lo que sabemos que detecta genes, enfermedades, fármacos, especies, mutaciones y vías en el texto.

Desafortunadamente, el modelo BERN no asigna identificadores de base de conocimientos objetivo a todos los conceptos. Entonces, preparé un script que primero busca si se proporciona una identificación distinta para un concepto, y si no es así, usará el nombre de la entidad como identificación. También calcularemos el sha256 del texto de las oraciones para identificar oraciones específicas más fácilmente más adelante cuando hagamos la extracción de relaciones.

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()})

Inspeccioné los resultados de la vinculación de la entidad nombrada y, como era de esperar, no es perfecto. Por ejemplo, no identifica las células madre como un concepto médico. Por otro lado, detectó una sola entidad denominada “corazón, cerebro, nervios y riñón”. Sin embargo, BERN sigue siendo el mejor modelo biomédico de código abierto que pude encontrar durante mi investigación.

Construir un gráfico de conocimiento

Antes de analizar las técnicas de extracción de relaciones, construiremos un gráfico de conocimiento biomédico usando solo entidades y examinaremos las posibles aplicaciones. Como se mencionó, he preparado un Bloc de notas de Google Colab que puede usar para seguir los ejemplos de código en esta publicación. Para almacenar nuestro gráfico, usaremos Neo4j. No tiene que lidiar con la preparación de un entorno Neo4j local. En su lugar, puede usar una instancia gratuita de Neo4j Sandbox.

Caja de arena Neo4j

Iniciar el Proyecto en blanco en el sandbox y copie los detalles de la conexión en el cuaderno de Colab.

Detalles de conexión de Neo4j Sandbox. Imagen del autor.

Ahora puede continuar y preparar la conexión Neo4j en la computadora portátil.

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())

Comenzaremos importando el autor y el artículo en el gráfico. El nodo del artículo contendrá solo el título.

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})

Si abre el navegador Neo4j, debería ver el siguiente gráfico.

Imagen del autor.

Puede importar las oraciones y las entidades mencionadas ejecutando la siguiente consulta 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})

Puede ejecutar la siguiente consulta Cypher para inspeccionar el gráfico construido:

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

Si ha importado correctamente los datos, debería ver una visualización similar.

Extracción de entidades almacenada como un gráfico. Imagen del autor.

Aplicaciones de gráficos de conocimiento

Incluso sin el flujo de extracción de relaciones, ya hay un par de casos de uso para nuestro gráfico.

Search Engine

Podríamos usar nuestro gráfico como motor de búsqueda. Por ejemplo, podría usar la siguiente consulta de Cypher para buscar oraciones o artículos que mencionen una entidad médica específica.

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

Resultados

Imagen del autor.

Análisis de co-ocurrencia

La segunda opción es el análisis de co-ocurrencia. Podría definir la co-ocurrencia entre entidades médicas si aparecen en la misma oración o artículo. Encontré un artículo[2] que usa la red de co-ocurrencia médica para predecir nuevas conexiones posibles entre entidades médicas.

Predicción de enlaces en una red de co-ocurrencia MeSH: resultados preliminares – PubMed

Podría usar la siguiente consulta de Cypher para encontrar entidades que a menudo coexisten en la misma oración.

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

Resultados

entidad1 entidad2 coocurrencia
Enfermedades de la piel úlceras diabéticas 2
heridas crónicas úlceras diabéticas 2
Enfermedades de la piel heridas crónicas 2

Obviamente, los resultados serían mejores si analizáramos miles o más artículos.

Inspeccionar la experiencia del autor

También puede usar este gráfico para encontrar la experiencia del autor al examinar las entidades médicas sobre las que escribe con más frecuencia. Con esta información, también podría sugerir futuras colaboraciones.

Ejecute la siguiente consulta Cypher para inspeccionar qué entidades médicas mencionó nuestro único autor en el trabajo de investigación.

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

Resultados

autor entidad contar
Mohammadreza Ahmadi Colágeno 9
Mohammadreza Ahmadi quemaduras 4
Mohammadreza Ahmadi Enfermedades de la piel 4
Mohammadreza Ahmadi enzimas colagenasa 2
Mohammadreza Ahmadi Epidermólisis ampollosa 2

Extracción de relaciones

Ahora intentaremos extraer relaciones entre conceptos médicos. Desde mi experiencia, la extracción de relaciones es al menos un orden de magnitud más difícil que la extracción de entidades nombradas. Si no debe esperar resultados perfectos con la vinculación de entidades nombradas, definitivamente puede esperar algunos errores con la técnica de extracción de relaciones.

He estado buscando modelos de extracción de relaciones biomédicas disponibles, pero no encontré nada que funcione de inmediato o que no requiera ajustes. Parece que el campo de la extracción de relaciones está a la vanguardia y, con suerte, veremos más atención al respecto en el futuro. Desafortunadamente, no soy un experto en PNL, así que evité ajustar mi propio modelo. En su lugar, utilizaremos el extractor de relación de tiro cero basado en el papel Explorando el límite de tiro cero de FewRel[3]. Si bien no recomendaría poner este modelo en producción, es lo suficientemente bueno para una demostración simple. El modelo está disponible en AbrazandoCara, por lo que no tenemos que lidiar con el entrenamiento o la configuración del modelo.

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 el extractor de relaciones de tiro cero, puede definir qué relaciones le gustaría detectar. En este ejemplo, he usado el asociado y interactúa relaciones También probé tipos de relación más específicos, como golosinas, causas y otros, pero los resultados no fueron muy buenos.

Con este modelo, debe definir entre qué pares de entidades le gustaría detectar relaciones. Usaremos los resultados de la vinculación de la entidad nombrada como entrada para el proceso de extracción de la relación. Primero, encontramos todas las oraciones donde se mencionan dos o más entidades y luego las ejecutamos a través del modelo de extracción de relaciones para extraer cualquier conexión. También he definido un valor de umbral de 0.85, lo que significa que si un modelo predice un vínculo entre entidades con una probabilidad inferior a 0.85, ignoraremos la predicción.

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})

Almacenamos las relaciones, así como el texto de origen utilizado para extraer esa relación en el gráfico.

Relaciones extraídas almacenadas en un gráfico. Imagen del autor.

Puede examinar las relaciones extraídas entre las entidades y el texto de origen con la siguiente consulta de 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

Resultados

Imagen del autor.

Como mencioné, el modelo de PNL que he usado para extraer relaciones no es perfecto, y dado que no soy médico, no sé cuántas conexiones se perdieron. Sin embargo, los que detectó parecen razonables.

Enriquecimiento de bases de datos externas

Como mencioné antes, aún podemos usar las bases de datos externas como CHEBI o MESH para enriquecer nuestro gráfico. Por ejemplo, nuestro gráfico contiene una entidad médica Epidermólisis ampollosa y también conocemos su MeSH id.

Puede recuperar el MeSH id de Epidermolysis bullosa con la siguiente consulta:

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

Puede continuar e inspeccionar el MeSH para encontrar la información disponible:

Datos vinculados MeSH

Captura de pantalla del autor. Los datos son cortesía de la Biblioteca Nacional de Medicina de EE. UU.

Aquí hay una captura de pantalla de la información disponible en el sitio web MeSH para Epidermolysis bullosa. Como se mencionó, no soy médico, por lo que no sé exactamente cuál sería la mejor manera de modelar esta información en un gráfico. Sin embargo, le mostraré cómo recuperar esta información en Neo4j usando el procedimiento apoc.load.json para obtener la información del punto final MeSH REST. Y luego, puede pedirle a un experto en el dominio que lo ayude a modelar esta información.

La consulta Cypher para obtener la información del punto final MeSH REST es:

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

Gráfico de conocimiento como entrada de datos de aprendizaje automático

Como pensamiento final, lo guiaré rápidamente a través de cómo podría usar el gráfico de conocimiento biomédico como entrada para un flujo de trabajo de aprendizaje automático. En los últimos años, ha habido mucha investigación y avances en el campo de la incorporación de nodos. Los modelos de incrustación de nodos traducen la topología de la red en un espacio de incrustación.

Copyright © 2017 Manan Shah, Grupo SNAP. Imagen disponible bajo licencia MIT en https://github.com/snap-stanford/cs224w-notes.

Suponga que construye un gráfico de conocimiento biomédico que contiene entidades y conceptos médicos, sus relaciones y el enriquecimiento de varias bases de datos médicas. Puede usar técnicas de incrustación de nodos para aprender las representaciones de nodos, que son vectores de longitud fija, e ingresarlos en su flujo de trabajo de aprendizaje automático. Varias aplicaciones utilizan este enfoque, desde la reutilización de fármacos hasta predicciones de efectos secundarios o adversos. Encontré un trabajo de investigación que usa predicción de enlaces para posibles tratamientos de nuevas enfermedades[4].

Conclusión

El dominio biomédico es un excelente ejemplo donde los gráficos de conocimiento son aplicables. Hay muchas aplicaciones que van desde simples motores de búsqueda hasta flujos de trabajo de aprendizaje automático más complicados. Con suerte, al leer esta publicación de blog, se le ocurrieron algunas ideas sobre cómo podría usar gráficos de conocimiento biomédico para respaldar sus aplicaciones. Puedes iniciar un caja de arena Neo4j gratis y empieza a explorar hoy.

Como siempre, el código está disponible en GitHub.

Referencias

[1] D. Kim et al., "Una herramienta de normalización multitipo y reconocimiento de entidades neuronales para la minería de textos biomédicos", en IEEE Access, vol. 7, págs. 73729–73740, 2019, doi: 10.1109/ACCESS.2019.2920708.

[2] Kastrin A, Rindflesch TC, Hristovski D. Predicción de enlaces en una red de co-ocurrencia MeSH: resultados preliminares. Informe de tecnología de salud de Stud. 2014;205:579–83. PMID: 25160252.

[3] Cetolí, A. (2020). Explorando el límite de tiro cero de FewRel. En Actas de la 28.ª Conferencia Internacional sobre Lingüística Computacional (págs. 1447–1451). Comité Internacional de Lingüística Computacional.

[4] Zhang, R., Hristovski, D., Schutte, D., Kastrin, A., Fiszman, M. y Kilicoglu, H. (2021). Reutilización de medicamentos para COVID-19 a través de la finalización del gráfico de conocimiento. Diario de Informática Biomédica, 115, 103696.

Este artículo se publicó originalmente el Hacia la ciencia de datos y re-publicado a TOPBOTS con permiso del autor.

¿Disfrutas este artículo? Regístrese para recibir más actualizaciones de IA.

Te avisaremos cuando publiquemos más educación técnica.

El puesto Construya un gráfico de conocimiento biomédico con PNL apareció por primera vez en TOPBOTS.

Sello de tiempo:

Mas de TOPBOTS