概要
- arXivから文献一覧を被引用数を追加して取得する方法を忘備録として記載する。取得にはPythonを使用
- arXivのサイトだけでは引用数を確認できなかったため、Schemantic Scholarを活用する
- なお、本内容は以下のサイトを主に参考にした。ただし、パッケージ等の更新により修正が必要であったために投稿する
- 使用パッケージ(Python)
- arxiv (arXiv APIのPythonラッパー)
- requests
- numpy
- pandas
- openpyxl
文献の抽出
arXivからの文献抽出
- Pythonのarxivのパッケージを用いて文献を抽出する
- Query(検索条件)の作成方法は以下を参照
- 5.1. Details of Query Construction
- ただし、上記ではスペースには"+"を使用する記載があるが、arxivのパッケージでは"+"を用いると想定した検索ができず
- "+"ではなく普通にスペースを使用することで解決
- 例として、以下の条件で検索したプログラムを示す
- 検索条件:要約に"RAG"を含む。カテゴリは"AI"。期間は2021/1/1から2025/5/4
-
(補足) QueryのPrefix一覧
prefix explanation ti Title au Author abs Abstract co Comment jr Journal Reference cat Subject Category rn Report Number id Id (use id_list instead) all All of the above
プログラム例
- arxivから一覧の取得するプログラムの例を示す
- resultsはジェネレータである点に注意する。pandasのDataFrameへの変換例は後述する
import arxiv
def set_client_search(query: str):
client = arxiv.Client(
page_size = 1000, # 1リクエストでの抽出数。2000以下, default 100
delay_seconds = 3.0, # 遅延時間(秒)。rxivの規約上、1リクエスト以上/3秒はNG
)
search = arxiv.Search(
query = query, # 検索文字, str
# id_list = [], # 文献ID. List[str]
max_results = 2000, # 最大抽出数. 30000以下
sort_by = arxiv.SortCriterion.Relevance, # Relevance, LastUpdatedDate, SubmittedDate
sort_order = arxiv.SortOrder.Descending, # Ascending, Descending
)
return client, search
# 要約にRAGを含み、カテゴリ: AI、期間; 20210101-20250504で検索
query = "abs:RAG AND cat:cs.AI AND submittedDate:[202101010000 TO 202505042359]"
client, search = set_client_search(query)
results = client.results(search)
DataFrame型に変換
- 取得したresultsをDataFrame型に変換する
- 結果項目の詳細はarXiv API User Manual: Details of Atom Results ReturnedarXivを参照のこと
- 検索の関連度に関するパラメータが結果に含まれないため、"Relevance"として一致度を設定
- 一致度(Relevance)は、arxivでの検索結果をRelevanceでDescendingとしてソートしていることを利用して、0-1となるようにした
プログラム例
import pandas as pd
def convert_to_str(vals): # 文字列に変換
if isinstance(vals, list):
return list(map(str, vals))
elif vals is None:
return vals
else:
return str(vals)
def create_df(results):
res0 = []
for res in results:
res_dict = dict(
entry_id = res.entry_id,
pdf_url = res.pdf_url,
updated = res.updated,
published = res.published,
title = res.title,
authors = convert_to_str(res.authors), # 文字列に変換
summary = res.summary,
comment = res.comment,
journal_ref = res.journal_ref,
doi = res.doi,
primary_category = res.primary_category,
categories = res.categories,
links = convert_to_str(res.links), # 文字列に変換
)
res0.append(res_dict)
df = pd.DataFrame(res0)
ndata = len(df)
df['Relevance'] = [i/ndata for i in range(ndata, 0, -1)] # 一致度を0~1の範囲で設定。検索がRelevanceでDescendingでソートしているため。
return df
df = create_df(results)
Semantic Scholarによる引用数の取得
-
arxivには引用数に関連する項目がないため、Semantic ScholarのAPIを利用
-
Shemantic ScholarのAPIについては以下を参照のこと
-
追加する項目は以下とした
- citationCount: 被引用数
- influentialCitationCount: 影響力があると判断された引用数
- referenceCount: 参考文献数(参考用)
プログラム例
- バッチ処理するための文献IDを"arxiv_id"として設定する
- バッチ処理において、サーバ状況・リクエストの間隔によってエラーが生じやすい。再実行時に不都合が生じにくいようにデータ(DataFame)は結合(merge)ではなく、updateを使用
- 一度に処理できる文献ID数は500件である点に注意する
import numpy as np
def create_url(aid: str):
apath = aid.split("/")[-1].split("v")[0]
arxiv_id = f'ARXIV:{apath}'
search_url = f'{semantic_base_url}/{arxiv_id}' + '?fields=' + fields
return arxiv_id
semantic_base_url = 'https://api.semanticscholar.org/graph/v1/paper' # Semantic ScholarのベースURL
fields = 'citationCount,influentialCitationCount,referenceCount' # サイトから取得する追加項
df['arxiv_id'] = df['entry_id'].apply(create_url)
tcol = fields.split(",")
df[tcol] = np.nan # 初期化
- バッチ処理
import requests
import time
def get_citation_batch(df, start=0, batch_size=500):
ndata = len(df)
nbatch = (ndata // batch_size) + 1
data = df['arxiv_id'].tolist()
for i in range(start, ndata, batch_size):
batch = data[i:i+batch_size]
semantic_batch_url = semantic_base_url + '/batch'
# ---
print(f"{i+1}/{nbatch} Processing batch: {i} to {i+batch_size}")
r = requests.post(semantic_batch_url, params={'fields': fields}, json={"ids": batch})
print(r.status_code)
if r.status_code != 200:
print('---')
print('Error: ', r.status_code)
if r.status_code == 429:
print('Too many requests. Wait a while and try again.')
return df
# ---
batch_output = dict(zip(batch, r.json()))
batch_output = pd.DataFrame(batch_output).T
df.set_index('arxiv_id', inplace=True) # arxiv_idをキーとしてdfのデータを更新
df.update(batch_output)
df.reset_index(inplace=True)
# ---
time.sleep(5) # 時間を空けるため
return df
start = 0 # 開始行
batch_size = 500 # バッチ数。500以下
df = get_citation_batch(df, start=start, batch_size=batch_size)
データの整理(ソート、フィルタ)と出力
- データをソートしてエクセル出力する
- 本例ではinfluentialCitaionCount, citationCount, Relevanceの順に降順でソート
- クリックして参照PDFに飛べるようにハイパーリンクを追加
- リンク追加前: arxiv_list.xlsx として出力。csv出力しても良い
- リンク追加後: add_link_arxiv_list.xlsx として出力
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
from openpyxl.styles import Font
outfilename = "arxiv_list.xlsx"
data = df.copy()
# データのソート
tcols = fields.split(",") + ['Relevance']
data[tcols] = data[tcols].apply(pd.to_numeric, errors='coerce') # ignore, coerce
tcols = ['updated', 'published']
for t in tcols:
data[t] = data[t].apply(lambda x: x.strftime('%Y-%m-%d'))
data = data.sort_values(by=['influentialCitationCount', 'citationCount', 'Relevance'], ascending=[False, False, False])
data.to_excel(outfilename, index=False)
# ハイパーリンクの追加
wb = load_workbook(outfilename)
ws = wb.active
hyperlink_colname = ['entry_id', 'pdf_url']
col_index = [data.columns.get_loc(s) for s in hyperlink_colname]
for row in range(2, ws.max_row + 1): # Excelの行は1始まり
for c in col_index:
cell = ws[f"{get_column_letter(c+1)}{row}"] # B列(2列目)
cell.value = f'=HYPERLINK("{cell.value}", "{cell.value}")' # Excelのハイパーリンク関数
cell.font = Font(color="0563C1", underline="single") # デフォルトの青色(#0563C1)+ アンダーライン
wb.save('add_link_' + outfilename)
wb.close()
参照サイト
- PyPi: arxiv
- arXiv API
- Qiita
- Semantic Scholar API