Побудуйте графік біомедичних знань за допомогою НЛП

Вихідний вузол: 1401511

Я вже показав, як створити графік знань зі сторінки Вікіпедії. Однак, оскільки публікація привернула багато уваги, я вирішив дослідити інші області, де використання методів НЛП для побудови графіка знань має сенс. На мою думку, біомедична сфера є яскравим прикладом, коли представлення даних у вигляді графіка має сенс, оскільки ви часто аналізуєте взаємодії та зв’язки між генами, захворюваннями, ліками, білками тощо.

Приклад підграфа, який показує зв’язок аскорбінової кислоти з іншими біомедичними концепціями. Зображення автора.

У наведеній вище візуалізації ми маємо аскорбінову кислоту, також відому як вітамін С, і деякі її зв’язки з іншими поняттями. Наприклад, він показує, що вітамін С можна використовувати для лікування хронічного гастриту.

Тепер ви можете запропонувати команду експертів у галузі для вас відобразити всі ці зв’язки між ліками, захворюваннями та іншими біомедичними концепціями. Але, на жаль, не багато хто з нас може дозволити собі найняти команду лікарів, щоб вони виконали роботу за нас. У цьому випадку ми можемо вдатися до використання методів НЛП для автоматичного вилучення цих відносин. Хороша частина полягає в тому, що ми можемо використовувати конвеєр НЛП, щоб прочитати всі дослідницькі роботи, а погана частина полягає в тому, що не всі отримані результати будуть ідеальними. Однак, враховуючи, що я не маю команди вчених, готових витягувати відносини вручну, я вдаюся до використання методів НЛП, щоб побудувати власний графік біомедичних знань.

Я буду використовувати одну дослідницьку роботу в цьому блозі, щоб провести вас через усі кроки, необхідні для побудови графіка біомедичних знань – Тканинна інженерія регенерації шкіри та росту волосся.

Стаття була написана Мохаммадреза Ахмаді. PDF-версія статті доступна за ліцензією CC0 1.0. Ми виконаємо такі кроки, щоб побудувати графік знань:

  • Читання PDF-документа за допомогою OCR
  • Попередня обробка тексту
  • Розпізнавання та зв'язування біомедичних концепцій
  • Вилучення відношення
  • Зовнішнє збагачення бази даних

Наприкінці цієї публікації ви побудуєте графік з такою схемою.

Біомедична схема графіка. Зображення автора.

Для зберігання нашого графіка ми будемо використовувати Neo4j, базу даних графіків, яка містить модель графа властивостей із мітками. Кожна стаття може мати одного або кількох авторів. Ми розділимо зміст статті на речення та використаємо НЛП для вилучення як медичних установ, так і їхніх стосунків. Може бути трохи нерозумним, що ми будемо зберігати відносини між сутностями як проміжні вузли замість зв’язків. Критичним фактором, що стоїть за цим рішенням, є те, що ми хочемо мати контрольний слід вихідного тексту, з якого було виділено зв’язок. З позначеною моделлю графіка властивостей ви не можете мати зв’язок, що вказує на інше відношення. З цієї причини ми реорганізуємо зв’язок між медичними поняттями в проміжний вузол. Це також дозволить експерту з домену оцінити, чи було відношення правильно виділено чи ні.

Попутно я також продемонструю застосування побудованого графіка для пошуку та аналізу збереженої інформації.

Давайте зануримось прямо в це!

Якщо цей поглиблений навчальний зміст вам корисний, підпишіться на наш список розсилки досліджень ШІ щоб отримати попередження, коли ми випускаємо новий матеріал.

Читання PDF-документа за допомогою OCR

Як згадувалося, PDF-версія наукової роботи доступна для громадськості за ліцензією CC0 1.0, що означає, що ми можемо легко завантажити її за допомогою Python. Ми будемо використовувати пітессеракт бібліотека для вилучення тексту з PDF. Наскільки мені відомо, бібліотека pytesseract є однією з найпопулярніших бібліотек для OCR. Якщо ви хочете наслідувати приклади коду, я підготував a Блокнот Google Colab, тож вам не доведеться копіювати та вставляти код самостійно.

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)

Попередня обробка тексту

Тепер, коли у нас є доступний вміст статті, ми вилучимо з тексту заголовки розділів та описи малюнків. Далі ми розділимо текст на речення.

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)

Зв’язування біомедичних іменованих об’єктів

Тепер настає хвилююча частина. Для тих, хто тільки починає працювати з НЛП, а також розпізнавання і зв’язування іменованих об’єктів, почнемо з деяких основ. Методи розпізнавання іменованих сутностей використовуються для виявлення відповідних сутностей або понять у тексті. Наприклад, у біомедичній сфері ми хочемо визначити різні гени, ліки, хвороби та інші поняття в тексті.

Вилучення біомедичних концепцій. Зображення автора.

У цьому прикладі модель НЛП ідентифікувала в тексті гени, хвороби, ліки, види, мутації та шляхи. Як згадувалося, цей процес називається розпізнаванням іменованих об’єктів. Оновленням до розпізнавання іменованого об’єкта є так зване зв’язування іменованих об’єктів. Техніка зв’язування іменованих об’єктів виявляє відповідні поняття в тексті та намагається відобразити їх у цільову базу знань. У біомедичній сфері деякі цільові бази знань:

Чому ми хочемо пов’язувати медичні установи з цільовою базою знань? Основна причина полягає в тому, що це допомагає нам впоратися з неоднозначністю сутностей. Наприклад, ми не хочемо, щоб на графіку були окремі об’єкти, що представляють аскорбінову кислоту та вітамін С, оскільки експерти з області можуть сказати вам, що це одне й те саме. Друга причина полягає в тому, що, зіставляючи концепції з цільовою базою знань, ми можемо збагатити нашу модель графіка, витягуючи інформацію про відображені концепції з цільової бази знань. Якщо ми знову використаємо приклад аскорбінової кислоти, ми можемо легко отримати додаткову інформацію з бази даних CHEBI, якщо ми вже знаємо її ЧЕБІ ід.

Дані про збагачення аскорбінової кислоти доступні на веб-сайті CHEBI. Весь вміст сайту доступний за посиланням Ліцензія CC BY 4.0. Зображення автора.

Я вже деякий час шукав гідного з відкритим вихідним кодом попередньо підготовленого біомедичного зв’язку з іменем. Багато моделей НЛП зосереджені на виділенні лише певної підмножини медичних концепцій, таких як гени або хвороби. Ще рідше можна знайти модель, яка виявляє більшість медичних концепцій і пов’язує їх із цільовою базою знань. На щастя, я натрапив БЕРН[1], нейронний біомедичний інструмент розпізнавання та багатотипної нормалізації. Якщо я правильно розумію, це точно налаштована модель BioBert з різними моделями зв’язування іменованих об’єктів, інтегрованими для зіставлення концепцій із цільовими біомедичними базами знань. Мало того, вони також надають безкоштовну кінцеву точку REST, тому нам не доведеться мати справу з головним болем, пов’язаним із запуском залежностей і моделі. Біомедична візуалізація розпізнавання іменованих сутностей, яку я використовував вище, була створена за допомогою моделі BERN, тому ми знаємо, що вона виявляє гени, хвороби, ліки, види, мутації та шляхи в тексті.

На жаль, модель BERN не призначає ідентифікатори цільової бази знань для всіх концепцій. Тож я підготував сценарій, який спочатку перевіряє, чи надано окремий ідентифікатор для концепції, а якщо ні, він використовуватиме ім’я сутності як ідентифікатор. Ми також обчислимо sha256 тексту речень, щоб легше ідентифікувати конкретні речення пізніше, коли ми будемо робити виділення відношень.

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

Я перевірив результати зв’язування названого об’єкта, і, як і очікувалося, воно не ідеальне. Наприклад, він не визначає стовбурові клітини як медичну концепцію. З іншого боку, він виявив єдину сутність під назвою «серце, мозок, нерви та нирки». Однак BERN все ще є найкращою біомедичною моделлю з відкритим кодом, яку я міг знайти під час свого дослідження.

Побудуйте графік знань

Перш ніж розглянути методи виділення відносин, ми побудуємо графік біомедичних знань, використовуючи лише сутності, і розглянемо можливі застосування. Як згадувалося, я підготував а Блокнот Google Colab які ви можете використовувати для наслідування прикладів коду в цій публікації. Для збереження нашого графіка ми будемо використовувати Neo4j. Вам не потрібно мати справу з підготовкою локального середовища Neo4j. Замість цього ви можете використовувати безкоштовний екземпляр Neo4j Sandbox.

Пісочниця Neo4j

Почніть Порожній проект у пісочниці і скопіюйте деталі підключення до блокнота Colab.

Деталі підключення Neo4j Sandbox. Зображення автора.

Тепер ви можете підготувати підключення Neo4j у ноутбуці.

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

Ми почнемо з імпортування автора та статті в графік. Вузол статті міститиме лише назву.

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

Якщо ви відкриєте браузер Neo4j, ви побачите наступний графік.

Зображення автора.

Ви можете імпортувати речення та згадані сутності, виконавши такий запит 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})

Ви можете виконати такий запит Cypher, щоб перевірити побудований графік:

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

Якщо ви правильно імпортували дані, ви повинні побачити подібну візуалізацію.

Вилучення сутності зберігається у вигляді графіка. Зображення автора.

Програми для графіків знань

Навіть без потоку вилучення відношень, для нашого графіка вже є кілька варіантів використання.

Пошукова система

Ми могли б використовувати наш графік як пошукову систему. Наприклад, ви можете використовувати наступний запит Cypher, щоб знайти речення або статті, у яких згадується конкретна медична установа.

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

результати

Зображення автора.

Аналіз спільної появи

Другий варіант – це аналіз спільної появи. Ви можете визначити спільну зустріч між медичними установами, якщо вони з’являються в одному реченні або статті. Я знайшов статтю[2], яка використовує мережу медичних супутніх випадків, щоб передбачити нові можливі зв’язки між медичними установами.

Прогнозування посилань у мережі спільного виникнення MeSH: попередні результати – PubMed

Ви можете використовувати наступний запит Cypher, щоб знайти об’єкти, які часто зустрічаються в одному реченні.

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

результати

сутність 1 сутність 2 спільне виникнення
шкірні захворювання діабетичних виразок 2
хронічні рани діабетичних виразок 2
шкірні захворювання хронічні рани 2

Очевидно, що результати були б кращими, якби ми проаналізували тисячі чи більше статей.

Перевірити кваліфікацію автора

Ви також можете використовувати цей графік, щоб знайти досвід автора, дослідивши медичні установи, про які вони найчастіше пишуть. Маючи цю інформацію, ви також можете запропонувати майбутню співпрацю.

Виконайте наведений нижче запит Cypher, щоб перевірити, які медичні установи наш єдиний автор згадав у дослідницькій роботі.

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

результати

автор суб'єкта вважати
Мохаммадреза Ахмаді колаген 9
Мохаммадреза Ахмаді опіки 4
Мохаммадреза Ахмаді шкірні захворювання 4
Мохаммадреза Ахмаді ферменти колагенази 2
Мохаммадреза Ахмаді Бульозний епідермоліз 2

Вилучення відношення

Зараз ми спробуємо виділити співвідношення між медичними поняттями. З мого досвіду, вилучення відношення принаймні на порядок важче, ніж вилучення названої сутності. Якщо ви не повинні очікувати ідеальних результатів із зв’язуванням іменованих об’єктів, то ви точно можете очікувати деяких помилок з технікою виділення відношень.

Я шукав доступні моделі вилучення біомедичних стосунків, але не знайшов нічого, що працювало б із коробки чи не вимагало б точного налаштування. Схоже, що сфера вилучення відносин знаходиться на передовій, і, сподіваюся, ми побачимо більше уваги до неї в майбутньому. На жаль, я не фахівець з НЛП, тому уникав точного налаштування власної моделі. Замість цього ми будемо використовувати екстрактор відношень нульового кадру на основі паперу Дослідження межі нульового пострілу для FewRel[3]. Хоча я б не рекомендував запускати цю модель у виробництво, її достатньо для простої демонстрації. Модель доступна на HuggingFace, тому нам не доведеться займатися навчанням або налаштуванням моделі.

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)

За допомогою екстрактора відношень нульового рівня ви можете визначити, які відносини ви хочете виявити. У цьому прикладі я використав асоційований та  взаємодіє відносини. Я також пробував більш конкретні типи стосунків, такі як ласощі, причини та інші, але результати не були чудовими.

За допомогою цієї моделі ви повинні визначити, між якими парами сутностей ви хочете виявити зв’язки. Ми будемо використовувати результати зв’язування названої сутності як вхідні дані для процесу вилучення відношень. Спочатку ми знаходимо всі речення, де згадуються дві або більше сутності, а потім запускаємо їх через модель вилучення відношень, щоб виділити будь-які зв’язки. Я також визначив порогове значення 0.85, що означає, що якщо модель передбачає зв’язок між об’єктами з імовірністю нижче 0.85, ми ігноруємо прогноз.

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

Ми зберігаємо зв’язки, а також вихідний текст, який використовується для виділення цього зв’язку на графіку.

Витягнуті відносини зберігаються в графі. Зображення автора.

Ви можете перевірити вилучені зв’язки між сутностями та вихідним текстом за допомогою такого запиту 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

результати

Зображення автора.

Як уже згадувалося, модель НЛП, яку я використовував для вилучення стосунків, не є ідеальною, і оскільки я не лікар, я не знаю, скільки зв’язків вона упустила. Однак ті, які він виявив, здаються розумними.

Зовнішнє збагачення бази даних

Як я вже згадував раніше, ми все ще можемо використовувати зовнішні бази даних, такі як CHEBI або MESH, для збагачення нашого графіка. Наприклад, наш графік містить медичну особу Бульозний епідермоліз і ми також знаємо його ідентифікатор MeSH.

Ви можете отримати ідентифікатор MeSH для бульозного епідермолізу за допомогою такого запиту:

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

Ви можете перейти і перевірити MeSH, щоб знайти доступну інформацію:

Пов’язані дані MeSH

Скріншот автора. Дані надано Національною медичною бібліотекою США.

Ось знімок екрана з доступною інформацією на веб-сайті MeSH щодо бульозного епідермолізу. Як уже згадувалося, я не лікар, тому я не знаю, який би був найкращим способом моделювати цю інформацію на графіку. Однак я покажу вам, як отримати цю інформацію в Neo4j за допомогою процедури apoc.load.json для отримання інформації з кінцевої точки MeSH REST. Потім ви можете попросити експерта з домену допомогти вам змоделювати цю інформацію.

Запит Cypher для отримання інформації з кінцевої точки MeSH REST:

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

Графік знань як вхідні дані машинного навчання

На завершення я швидко розповім вам, як ви можете використовувати графік біомедичних знань як вхідні дані для робочого процесу машинного навчання. Останніми роками було багато досліджень і вдосконалень у сфері вбудовування вузлів. Моделі вбудовування вузлів переводять топологію мережі в простір вбудовування.

Авторське право © 2017 Manan Shah, SNAP Group. Зображення доступне за ліцензією MIT у https://github.com/snap-stanford/cs224w-notes.

Припустимо, ви побудували графік біомедичних знань, що містить медичні сутності та концепції, їх зв’язки та збагачення з різних медичних баз даних. Ви можете використовувати методи вбудовування вузлів, щоб вивчити представлення вузлів, які є векторами фіксованої довжини, і ввести їх у свій робочий процес машинного навчання. Цей підхід використовується в різних сферах застосування, починаючи від перепрофілювання ліків і закінчуючи прогнозуванням побічних ефектів або побічних ефектів. Я знайшов дослідницьку роботу, яка використовує прогнозування посилань для потенційного лікування нових захворювань[4].

Висновок

Біомедичний домен є яскравим прикладом, де можна застосувати графіки знань. Існує багато додатків, починаючи від простих пошукових систем і закінчуючи більш складними процесами машинного навчання. Сподіваюся, читаючи цю публікацію в блозі, ви придумали кілька ідей щодо того, як можна використовувати графіки біомедичних знань для підтримки ваших додатків. Ви можете почати а безкоштовна пісочниця Neo4j і почніть досліджувати сьогодні.

Як завжди, код доступний на GitHub.

посилання

[1] Д. Кім та ін., «Інструмент нейронного розпізнавання іменованих сутностей та багатотипової нормалізації для аналізу біомедичного тексту», в Доступ IEEE, том 7, с. 73729–73740, 2019, doi: 10.1109/ACCESS.2019.2920708.

[2] Кастрін А., Ріндфлеш Т.С., Христовський Д. Прогноз зв'язку в мережі спільного виникнення MeSH: попередні результати. Stud Health Technol Inform. 2014;205:579–83. PMID: 25160252.

[3] Четолі, А. (2020). Дослідження межі нульового пострілу для FewRel. в Матеріали 28-ї Міжнародної конференції з комп’ютерної лінгвістики (с. 1447–1451). Міжнародний комітет комп’ютерної лінгвістики.

[4] Чжан Р., Христовський Д., Шутте Д., Кастрін А., Фішман М. і Кілікоглу Х. (2021). Перепрофілювання ліків від COVID-19 за допомогою заповнення графіка знань. Журнал біомедичної інформатики, 115, 103696.

Ця стаття була спочатку опублікована на Назустріч науці про дані та повторно опубліковано в TOPBOTS з дозволу автора.

Вам подобається ця стаття? Підпишіться на отримання нових оновлень AI.

Ми повідомимо вас, коли випустимо більше технічної освіти.

Повідомлення Побудуйте графік біомедичних знань за допомогою НЛП вперше з'явився на ТОПБОТИ.

Часова мітка:

Більше від ТОПБОТИ