LoginSignup
7
13

More than 5 years have passed since last update.

PythonでNCBIのAPIから文献情報を取得してみた

Last updated at Posted at 2018-09-30

前回記事では、PubMedの検索結果のWebページをBeautifulSoupでパースして解析しました(邪道ですが、、、)。今回はNCBIのAPIを使って、以下に挑戦してみました。

  1. 特定の用語に関して、年ごとの検索ヒット数の変化を調べる
  2. ヒットした文献の情報をまとめて取得してリスト化する

PubMed情報を取得できるPythonパッケージとしてBiopythonがありますが、今回は一般的なAPIの取り扱いの練習のために自前で実装してみることにしました。

実行環境

  • MacOS Sierra
  • Xcode 9.2
  • Python 3.6.1
  • requests 2.14.2
  • matplotlib 2.0.2
  • pandas 0.20.1
  • jupyter 1.0.0

ソースコード

PubMedクラスの関数として、以下の2つを用意しました。

  • クエリから検索ヒット件数とidのリストを返すsearch関数
  • idのリストから、論文の詳細情報を取得するget_article_info関数

ソースコード(折りたたみ)
%matplotlib inline
import matplotlib.pyplot as plt
import requests
import time
import pandas as pd
from collections import OrderedDict

class PubMed:
    def __init__(self):
        self.baseURL = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/"

    def search(self,*terms):
        terms = "+AND+".join(list(terms))
        query = f"db=pubmed&term={terms}"
        dataFormat = "json"

        search_command = "esearch.fcgi"
        self.searchURI = f"{self.baseURL}{search_command}?{query}&retmode={dataFormat}"
        result = requests.get(self.searchURI)
        print(f"{result}\n")

        data = result.json()
        self.count = data["esearchresult"]["count"]
        self.id_list = data["esearchresult"]["idlist"]

        time.sleep(2) #アクセスしすぎないように配慮

    def get_article_info(self):
        summary_command = "esummary.fcgi"
        pubmedURL = "https://www.ncbi.nlm.nih.gov/pubmed/"
        key_list = ['source','volume','issue','pages']
        new_key_list = ['journal','volume','issue','pages']

        self.result_list = []

        for n,id in enumerate(self.id_list):
            query = f"db=pubmed&id={id}"
            dataFormat = "json"
            result = requests.get(f"{self.baseURL}{summary_command}?{query}&retmode={dataFormat}")
            print(f"{n}:{id}:{result}\n")
            data = result.json()

            result_dic = OrderedDict()

            result_dic['title'] = data['result'][id]['title']

            author_list = []
            for author in data['result'][id]['authors']:
                author_list.append(author['name'])
            result_dic['all_authors'] = ", ".join(author_list)

            publication_date = data['result'][id]['pubdate']
            result_dic['year'] = publication_date.split(" ")[0]

            for key,new_key in zip(key_list,new_key_list):
                result_dic[new_key] = data['result'][id][key]

            result_dic['link'] = f"{pubmedURL}{id}"

            self.result_list.append(result_dic)

            time.sleep(2) #アクセスしすぎないように配慮

結果

1. 特定の用語に関して、年ごとの検索ヒット数の変化を調べる

"rna-seq"という用語に対し、2004年から2018年までの変化を調べてグラフ化してみました。APIで出版年を指定するタグは[DP]だそうです。

pubmed = PubMed()
hit_count = {}
for year in range(2004,2019):
    pubmed.search("rna-seq",f"{year}[DP]")
    hit_count[year] = int(pubmed.count)

うまくいくと、<Response [200]>というメッセージが出るようになっています。HTTPのレスポンス状態コードについてはこちらを参照してください。

hit_countをPandasのDataFrameに変換します。

df = pd.DataFrame(hit_count,index=["count"]).T
df

長いため結果のテーブルは折りたたんでいます。
count
2004 0
2005 0
2006 0
2007 0
2008 6
2009 33
2010 156
2011 359
2012 631
2013 1127
2014 1723
2015 2322
2016 2809
2017 3583
2018 3072

Matplotlibでグラフ化した結果がこちら。

plt.plot(df)
plt.xlabel("Year")
plt.ylabel("Hit count")
plt.show()

20180930_rna-seq_hit_count.png

2008年にはじめの報告があり、その後順調に報告数が増加していることがわかります。

近年はやや減少傾向にありますが、理由はよくわかりません。現状、誰でも実施可能なポピュラーな手法になっているため、わざわざ明記しない報告が増えてきた可能性はあります。

[9/30 22:37追記] 先程気づいたのですが、2018年のみ9ヶ月分の集計ですので、最終的には2017年を超える可能性が高いですね。お詫びして訂正いたします。

2. ヒットした文献の情報をまとめて取得してリスト化する

2008年でヒットした、6件の文献情報を取得してみます。

pubmed = PubMed()
pubmed.search("rna-seq","2008[DP]")

print(pubmed.id_list) #取得したidのリスト
#['19087247', '18599741', '18550803', '18516045', '18488015', '18451266']

pubmed.get_article_info() #全てのidの文献情報取得

こちらも実行すると番号:id:<Response [200]>といった、HTTPレスポンス状態コードが返ってくるようにしました。

文献情報はpubmed.result_listに入っています。(折りたたみ)
import pprint
pprint.pprint(pubmed.result_list[-1])


#OrderedDict([('title',
#              'The transcriptional landscape of the yeast genome defined by '
#              'RNA sequencing.'),
#             ('all_authors',
#              'Nagalakshmi U, Wang Z, Waern K, Shou C, Raha D, Gerstein M, '
#              'Snyder M'),
#             ('year', '2008'),
#             ('journal', 'Science'),
#             ('volume', '320'),
#             ('issue', '5881'),
#             ('pages', '1344-9'),
#             ('link', 'https://www.ncbi.nlm.nih.gov/pubmed/18451266')])

Pandasデータフレームで見るとこんな感じ。

df_paper = pd.DataFrame(pubmed.result_list[-1],index=["details"]).T
df_paper
details
title The transcriptional landscape of the yeast gen...
all_authors Nagalakshmi U, Wang Z, Waern K, Shou C, Raha D...
year 2008
journal Science
volume 320
issue 5881
pages 1344-9
link https://www.ncbi.nlm.nih.gov/pubmed/18451266

この論文が"RNA-Seq"という単語を使った、PubMed上で見られる一番最初の報告であると思われます。なんとなく感慨深いですね。

7
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
13