NLPを使用して生物医学知識グラフを作成する

ソースノード: 1401511

私はすでに方法を示しました ウィキペディアのページから知識グラフを作成する。 ただし、投稿が注目を集めたため、NLP手法を使用して知識グラフを作成することが理にかなっている他のドメインを探索することにしました。 私の意見では、生物医学分野は、遺伝子、病気、薬、タンパク質などの間の相互作用や関係を分析することが多いため、データをグラフとして表すことが理にかなっている代表的な例です。

アスコルビン酸と他の生物医学的概念との関係を示すサブグラフの例。 著者による画像。

上記の視覚化では、ビタミンCとしても知られているアスコルビン酸と他の概念との関係のいくつかがあります。 たとえば、ビタミンCが慢性胃炎の治療に使用できることを示しています。

今、あなたはドメインの専門家のチームにあなたのために薬、病気、そして他の生物医学の概念の間のそれらの関係のすべてをマッピングさせることができます。 しかし、残念ながら、私たちの多くは私たちのために仕事をするために医師のチームを雇う余裕がありません。 その場合、NLP手法を使用して、これらの関係を自動的に抽出することができます。 良い点は、NLPパイプラインを使用して、そこにあるすべての研究論文を読むことができることです。悪い点は、得られたすべての結果が完全であるとは限らないことです。 ただし、関係を手動で抽出する準備ができている科学者のチームがいないため、NLP手法を使用して独自の生物医学知識グラフを作成します。

このブログ投稿では、単一の研究論文を使用して、生物医学知識グラフを作成するために必要なすべての手順を説明します– 皮膚再生と発毛の組織工学.

論文はによって書かれました モハマドレザ・アフマディ。 この記事のPDFバージョンは、CC0ライセンスの下で入手できます。 知識グラフを作成するには、次の手順を実行します。

  • OCRでPDFドキュメントを読む
  • テキストの前処理
  • 生物医学の概念の認識とリンク
  • 関係の抽出
  • 外部データベースの強化

この投稿の終わりまでに、次のスキーマでグラフを作成します。

生物医学グラフスキーマ。 著者による画像。

ラベル付きプロパティグラフモデルを備えたグラフデータベースであるNeo4jを使用して、グラフを保存します。 各記事にはXNUMX人以上の著者を含めることができます。 記事の内容を文に分割し、NLPを使用して医療機関とその関係の両方を抽出します。 エンティティ間の関係を関係ではなく中間ノードとして保存するのは少し直感に反するかもしれません。 この決定の背後にある重要な要素は、関係が抽出されたソーステキストの監査証跡が必要なことです。 ラベル付きプロパティグラフモデルでは、別の関係を指す関係を持つことはできません。 このため、医療概念間の接続を中間ノードにリファクタリングします。 これにより、ドメインエキスパートは、リレーションが正しく抽出されたかどうかを評価することもできます。

その過程で、構築されたグラフを使用して保存された情報を検索および分析するアプリケーションについても説明します。

すぐに飛び込みましょう!

この詳細な教育コンテンツがあなたに役立つ場合は、 AIリサーチメーリングリストに登録する 新しい素材がリリースされたときに警告が表示されます。

OCRでPDFドキュメントを読む

前述のように、研究論文のPDFバージョンはCC0 1.0ライセンスの下で一般に公開されています。つまり、Pythonで簡単にダウンロードできます。 を使用します ピテセラクト PDFからテキストを抽出するためのライブラリ。 私の知る限り、pytesseractライブラリはOCRで最も人気のあるライブラリのXNUMXつです。 コード例をフォローしたい場合は、私が用意しました GoogleColabノートブック、したがって、コードを自分でコピーして貼り付ける必要はありません。

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)

生物医学的な名前付きエンティティリンキング

今、エキサイティングな部分が来ます。 NLPを初めて使用し、名前付きエンティティの認識とリンクを行う場合は、いくつかの基本から始めましょう。 固有表現抽出技術は、テキスト内の関連するエンティティまたは概念を検出するために使用されます。 たとえば、生物医学の分野では、テキスト内のさまざまな遺伝子、薬、病気、およびその他の概念を特定したいと考えています。

生物医学的概念の抽出。 著者による画像。

この例では、NLPモデルにより、テキスト内の遺伝子、疾患、薬物、種、突然変異、および経路が特定されました。 前述のように、このプロセスは固有表現抽出と呼ばれます。 固有表現抽出のアップグレードは、いわゆる固有表現抽出です。 名前付きエンティティリンキング手法は、テキスト内の関連する概念を検出し、それらをターゲットナレッジベースにマッピングしようとします。 生物医学分野では、対象となる知識ベースのいくつかは次のとおりです。

医療機関をターゲットの知識ベースにリンクしたいのはなぜですか? 主な理由は、エンティティの曖昧性解消に対処するのに役立つためです。 たとえば、ドメインの専門家が同じことを教えてくれるので、アスコルビン酸とビタミンCを表すグラフ内の個別のエンティティは必要ありません。 XNUMX番目の理由は、概念をターゲットナレッジベースにマッピングすることにより、マッピングされたコンセプトに関する情報をターゲットナレッジベースからフェッチすることでグラフモデルを充実させることができるためです。 アスコルビン酸の例をもう一度使用すると、CHEBIデータベースから追​​加情報を簡単に取得できます。 CHEBI ID.

CHEBIのウェブサイトでアスコルビン酸に関する濃縮データを入手できます。 ウェブサイト上のすべてのコンテンツは、以下で利用できます。 CC BY4.0ライセンス。 著者による画像。

私はしばらくの間、まともなオープンソースの事前に訓練された生物医学という名前のエンティティリンキングを探していました。 多くのNLPモデルは、遺伝子や病気などの医療概念の特定のサブセットのみを抽出することに焦点を当てています。 ほとんどの医療概念を検出し、それらをターゲットの知識ベースにリンクするモデルを見つけることはさらにまれです。 幸いなことに私はつまずいた ベルン[1]、神経生物医学エンティティ認識およびマルチタイプ正規化ツール。 私が正しく理解していれば、それは、概念を生物医学的ターゲット知識ベースにマッピングするために統合されたさまざまな名前付きエンティティリンクモデルを備えた微調整されたBioBertモデルです。 それだけでなく、無料のRESTエンドポイントも提供するため、依存関係とモデルを機能させるという頭痛の種に対処する必要はありません。 上で使用した生物医学の固有表現抽出の視覚化は、BERNモデルを使用して作成されたため、テキスト内の遺伝子、疾患、薬物、種、突然変異、および経路を検出することがわかっています。

残念ながら、BERNモデルはすべての概念にターゲットナレッジベースIDを割り当てるわけではありません。 そこで、コンセプトに個別のIDが指定されているかどうかを最初に確認するスクリプトを用意しました。指定されていない場合は、エンティティ名をIDとして使用します。 また、後で関係抽出を行うときに、特定の文を簡単に識別できるように、文のテキストの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は、調査中に見つけた最高のオープンソースの生物医学モデルです。

知識グラフを作成する

関係抽出手法を検討する前に、エンティティのみを使用して生物医学知識グラフを作成し、可能なアプリケーションを検討します。 述べたように、私は準備しました GoogleColabノートブック この投稿のコード例に従うために使用できます。 グラフを保存するには、Neo4jを使用します。 ローカルのNeo4j環境の準備に取り組む必要はありません。 代わりに、無料のNeo4jサンドボックスインスタンスを使用できます。

Neo4jサンドボックス

始める サンドボックスの空白のプロジェクト 接続の詳細をColabノートブックにコピーします。

Neo4jサンドボックス接続の詳細。 著者による画像。

これで、ノートブックで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番目のオプションは、共起分析です。 医療機関が同じ文または記事に表示されている場合、それらの間の共起を定義できます。 私は、医療共起ネットワークを使用して、医療エンティティ間の新しい可能な接続を予測する記事[XNUMX]を見つけました。

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クエリを実行して、私たちのXNUMX人の著者が研究論文で言及した医療機関を調べます。

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

関係の抽出

次に、医学的概念間の関係を抽出しようとします。 私の経験から、関係の抽出は、名前付きエンティティの抽出よりも少なくともXNUMX桁難しいです。 名前付きエンティティリンキングで完璧な結果を期待するべきではない場合は、関係抽出手法でいくつかの間違いを間違いなく期待できます。

私は利用可能な生物医学的関係抽出モデルを探していましたが、箱から出してすぐに機能するものや微調整を必要としないものは何も見つかりませんでした。 関係抽出の分野は最先端にあるようであり、将来的にはもっと注目されることを願っています。 残念ながら、私はNLPの専門家ではないため、自分のモデルを微調整することは避けました。 代わりに、論文に基づいたゼロショット関係抽出器を使用します FewRelのゼロショット限界を探る[3]。 このモデルを本番環境に移行することはお勧めしませんが、簡単なデモンストレーションには十分です。 モデルはで利用可能です 抱き合う顔、したがって、モデルのトレーニングやセットアップを行う必要はありません。

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のしきい値を定義しました。これは、モデルがXNUMX未満の確率でエンティティ間のリンクを予測する場合、その予測を無視することを意味します。

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

結果

著者による画像。

前述のように、関係を抽出するために使用したNLPモデルは完全ではなく、私は医師ではないため、接続がいくつ失われたかはわかりません。 ただし、検出されたものは妥当なようです。

外部データベースの強化

前に述べたように、CHEBIやMESHなどの外部データベースを使用してグラフを充実させることができます。 たとえば、グラフには医療エンティティが含まれています 表皮水疱症 また、そのMeSHIDも知っています。

次のクエリを使用して、表皮水疱症のMeSHIDを取得できます。

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

先に進み、MeSHを調べて、利用可能な情報を見つけることができます。

MeSHリンクデータ

著者によるスクリーンショット。 データは米国国立医学図書館の厚意により提供されています。

これは、表皮水疱症に関するMeSHWebサイトで入手可能な情報のスクリーンショットです。 前述のように、私は医師ではないため、この情報をグラフでモデル化するための最良の方法が正確にはわかりません。 ただし、apoc.load.jsonプロシージャを使用してNeo4jでこの情報を取得し、MeSHRESTエンドポイントから情報を取得する方法を説明します。 次に、ドメインの専門家にこの情報のモデル化を支援するよう依頼できます。

MeSHRESTエンドポイントから情報をフェッチするためのCypherクエリは次のとおりです。

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 マナン・シャー、SNAP グループ。 画像は MIT ライセンスに基づいて利用可能です https://github.com/snap-stanford/cs224w-notes.

さまざまな医療データベースから、医療エンティティと概念、それらの関係、および強化を含む生物医学知識グラフを作成したとします。 ノード埋め込み手法を使用して、固定長のベクトルであるノード表現を学習し、それらを機械学習ワークフローに入力できます。 ドラッグリポジショニングから薬物の副作用または副作用の予測に至るまで、さまざまなアプリケーションがこのアプローチを使用しています。 を使用した研究論文を見つけました 新しい病気の潜在的な治療のためのリンク予測[4]。

まとめ

生物医学分野は、知識グラフが適用できる代表的な例です。 単純な検索エンジンからより複雑な機械学習ワークフローに至るまで、多くのアプリケーションがあります。 うまくいけば、このブログ投稿を読んで、アプリケーションをサポートするために生物医学知識グラフを使用する方法についていくつかのアイデアを思いついたでしょう。 あなたは始めることができます 無料のNeo4jサンドボックス 今日から探索を始めましょう。

いつものように、コードはで利用可能です GitHubの.

参考文献

[1] D。キム 。、「生物医学テキストマイニングのためのニューラル固有表現抽出およびマルチタイプ正規化ツール」、 IEEEアクセス、vol。 7、pp。73729–73740、2019、doi:10.1109 /ACCESS.2019.2920708。

[2] Kastrin A、Rindflesch TC、Hristovski D. MeSH共起ネットワークでのリンク予測:予備的な結果。 スタッドヘルステクノルインフォーム。 2014; 205:579–83。 PMID:25160252。

[3] Cetoli、A。(2020)。 FewRelのゼロショット限界を探る。 の 計算言語学に関する第28回国際会議の議事録 (pp。1447–1451)。 計算言語学に関する国際委員会。

[4] Zhang、R.、Hristovski、D.、Schutte、D.、Kastrin、A.、Fiszman、M。、およびKilicoglu、H。(2021)。 知識グラフの完成によるCOVID-19の薬剤転用。 Journal of Biomedical Informatics、115、103696。

この記事は、最初に公開された データサイエンスに向けて 著者の許可を得てTOPBOTSに再公開しました。

この記事をお楽しみください? その他のAIアップデートにサインアップしてください。

技術教育が追加されましたらお知らせします。

ポスト NLPを使用して生物医学知識グラフを作成する 最初に登場した トップボット.

タイムスタンプ:

より多くの トップボット