いろいろ倉庫

KNIME、EXCEL、R、Pythonなどの備忘録

【Python】PubMedからアブストを引っ張ってきたい

・お題:論文のアブストを題材に自然言語処理で遊ぼうと思ったところ、アブストを集めるのが面倒だった。キーワードからアブストを集めるところを、Pythonにやってほしい。

 

・少し調べたところ、biopythonでできるらしい。正しいことは公式サイトをご確認いただきたい。

biopython.org

・また、日本語の以下記事を参考にさせて頂いた。

qiita.com

・とりあえず、Biopythonをインストール。

conda install -c conda-forge biopython

・Entrezをインポート。

from Bio import Entrez

・自分のメールアドレスを入力し、情報を収集。EntrezでNCBIのいろいろなデータベースからデータをすっぱ抜けるようなので、データベースでpubmedを指定し、キーワードにcancer、論文数に10を指定した。論文数はあまり多いとサーバに負荷がかかるかもしれないので、自己責任で良識の範囲内に設定することをお勧めする。また、何かあれば指定したメールアドレスに連絡が入るらしいので、ちゃんと連絡が取れるメールアドレスを記載した方が良い。

Entrez.email = "abcd@efg.hij"
handle = Entrez.esearch(db="pubmed", term="cancer",  retmax="10")
record = Entrez.read(handle)

・これで、recordの中身は以下になる。

{'Count': '4710307', 'RetMax': '10', 'RetStart': '0', 'IdList': ['36409799', '36411032', '36411031', '36411024', '36410986', '36410985', '36410983', '36410982', '36410981', '36410980'], 'TranslationSet': [{'From': 'cancer', 'To': '"neoplasms"[MeSH Terms] OR "neoplasms"[All Fields] OR "cancer"[All Fields]'}], 'TranslationStack': [{'Term': '"neoplasms"[MeSH Terms]', 'Field': 'MeSH Terms', 'Count': '3758206', 'Explode': 'Y'}, {'Term': '"neoplasms"[All Fields]', 'Field': 'All Fields', 'Count': '3030639', 'Explode': 'N'}, 'OR', {'Term': '"cancer"[All Fields]', 'Field': 'All Fields', 'Count': '2778333', 'Explode': 'N'}, 'OR', 'GROUP'], 'QueryTranslation': '"neoplasms"[MeSH Terms] OR "neoplasms"[All Fields] OR "cancer"[All Fields]'}

アブストをとって来るのに必要なのは、このうち'IdList'だと思われる。IdListをとって来ると、以下のような感じ。

record["IdList"]

['36409799', '36411032', '36411031', '36411024', '36410986', '36410985', '36410983', '36410982', '36410981', '36410980']

・次に、このIDから文献情報を引っ張ってくる。とりあえず、最初の文献を例にやってみる。

from Bio import Medline
handle = Entrez.efetch(db="pubmed", id = record["IdList"][0], rettype = "medline", retmode = "text")
records = Medline.parse(handle)
records = list(records)

・resultsの中身は入れ子構造の文献情報(以下)になっている。

[{'PMID': '36409799',
  'STAT': 'Publisher',
  'ISBN': ['978-0-309-27577-4', '0-309-27577-6'],
  'PB': ['National Academies Press (US)'],
  'DP': '2022 Oct 20',
  'BTI': ['Leveraging Advances in Modern Science to Revitalize Low-Dose Radiation Research',
   'in the United States'],
  'AB': 'Radiation exposure at low doses (below 100 milligray) or low-dose rates (less than 5 milligray per hour) occurs in......

・ここからお目当てのAbstractを引っ張ってくる。

records[0]["AB"]

'Radiation exposure at low doses (below 100 milligray) or low-dose rates (less than 5 milligray per hour) occurs in a wide range of medical, industrial, military, and commercial settings. The effects of exposure at these levels are not fully understood,…....

・あとはこれをrecord["IdList"]に対してやってみる。

Abstracts=
for ID in record["IdList"]:
    handle = Entrez.efetch(db="pubmed", id=ID, rettype="medline",retmode="text")
    records = Medline.parse(handle)
    Abstracts.append(list(records)[0]["AB"])

・すると、エラーが返ってきた。KeyError: 'AB'とのことなので、どうもキー"AB"がないらしい。調べてみると、ID 36411024の論文情報にアブストが含まれておらず、エラーが返ってきたらしい。確かに、PubMed上でも"No abstract available"になっている。ということは、エラーになった場合はスルーし、処理が通ったもののみのアブストをリスト化する必要がある(以下)。

Abstracts=

for ID in record["IdList"]:
    handle = Entrez.efetch(db="pubmed", id=ID, rettype="medline",retmode="text")
    records = Medline.parse(handle)
    try:
        Abstracts.append(list(records)[0]["AB"])
    except KeyError:
        pass

・これで、9件の論文のアブストのリストを入手することができた。これだと完全にアブスト情報しか残らないので、IDをキーとした辞書としてアブストを集めても良いかも。それを踏まえて、処理を上から書くと以下みたいになった。

from Bio import Entrez
Entrez.email = "abc@def.ghi"
handle = Entrez.esearch(db="pubmed", term="cancer", retmax="10")
record = Entrez.read(handle)

from Bio import Medline
Abstracts={}
for ID in record["IdList"]:
    handle = Entrez.efetch(db="pubmed", id=ID, rettype="medline",retmode="text")
    records = Medline.parse(handle)
    try:
        Abstracts[ID]=list(records)[0]["AB"]
    except KeyError:
        pass

・これで、IDをキーとしたアブストの辞書Abstractsを作成できた。

 

おわり。