fda-database について
fda-databaseは、openFDAの公開規制データを検索するスキルで、薬剤安全性の監視、添付文書の確認、製品調査に利用できます。REST APIでFAERSの有害事象、薬剤ラベル、NDC製品、リコール情報を検索・集計します。
主な機能
- 01FAERSの薬剤有害事象報告の検索
- 02薬剤ごとの主な有害事象の集計
- 03薬剤ラベルと警告情報の取得
- 04NDCまたは成分による製品検索
- 05薬剤リコールと執行措置の検索
活用シーン
- 01関連薬剤の有害事象報告の比較
- 02適応症・禁忌・警告の抽出
- 03薬剤リコールと執行記録の確認
- 04薬剤安全性シグナル監視ワークフローの構築
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jaechang-hits/ sciagent-skills --skill fda-databaseインストール後、Claude Code で/fda-databaseを入力して読み込まれたか確認します。
詳細
openFDA 医薬品および有害事象データベース
概要
openFDA は、シンプルな REST API を通じて FDA の規制データに一般公開でアクセスできるようにします。主なデータセットには、2,000 万件以上の有害事象報告を含む FDA 有害事象報告システム(FAERS)、医薬品製品ラベル(NDC、SPL)、医薬品承認情報(Drugs@FDA)、医療機器報告、リコールおよび規制措置が含まれます。この API は、Elasticsearch 形式の構文を使用した全文検索と構造化クエリに対応しています。
使用する場面
- 医薬品の有害事象報告を取得し、安全性シグナルや副作用プロファイルを評価する場合
- FAERS をクエリし、不均衡分析(医薬品ごとの有害事象プロファイルを比較する分析)を行う場合
- 医薬品名または NDC で公式の医薬品ラベル(適応症、禁忌、警告、用法・用量)を検索する場合
- 医薬品名または企業名で医薬品のリコールや規制措置を検索する場合
- 特定の有効成分を含む市販製品をすべて特定する場合
- 公開規制データから医薬品の安全性シグナルを監視するファーマコビジランスのパイプラインを構築する場合
- 臨床試験の有効性データには
clinicaltrials-database-searchを、医薬品の構造や標的にはdrugbank-database-accessを使用してください
前提条件
- Python パッケージ:
requests、pandas - データ要件:医薬品名、有効成分、MedDRA 用語、NDC コード
- 環境:インターネット接続。基本的な使用に認証は不要です
- レート制限:API キーなしでは 1 日あたり 1000 リクエスト、https://open.fda.gov/apis/authentication/ から無料の API キーを取得すると 1 日あたり 120,000 リクエスト
pip install requests pandas
クイックスタート
import requests
BASE = "https://api.fda.gov/drug"
# Optional: add api_key parameter for higher rate limits
# Find adverse events for aspirin
r = requests.get(
f"{BASE}/event.json",
params={
"search": 'patient.drug.medicinalproduct:"aspirin"',
"count": "patient.reaction.reactionmeddrapt.exact",
"limit": 10
}
)
r.raise_for_status()
data = r.json()
print("Top adverse reactions for aspirin:")
for item in data["results"][:5]:
print(f" {item['term']:40s} count={item['count']}")
コア API
クエリ 1:有害事象報告の検索(FAERS)
FDA 有害事象報告システムを検索し、医薬品と事象の関連を調べます。
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def faers_search(drug_name, limit=100):
"""Search FAERS for adverse event reports mentioning a drug."""
r = requests.get(f"{BASE}/event.json",
params={"search": f'patient.drug.medicinalproduct:"{drug_name}"',
"limit": limit})
r.raise_for_status()
return r.json()
data = faers_search("warfarin", limit=5)
total = data["meta"]["results"]["total"]
print(f"Total FAERS reports for warfarin: {total:,}")
# Show first report summary
report = data["results"][0]
print(f"\nReport {report['safetyreportid']}:")
print(f" Date : {report.get('receivedate', 'n/a')}")
print(f" Serious : {report.get('serious', 'n/a')}")
drugs = [d.get("medicinalproduct", "n/a") for d in report.get("patient", {}).get("drug", [])]
print(f" Drugs : {drugs[:5]}")
reactions = [r.get("reactionmeddrapt", "n/a") for r in report.get("patient", {}).get("reaction", [])]
print(f" Reactions: {reactions[:5]}")
クエリ 2:医薬品の有害事象上位項目の集計
count パラメーターを使用して、有害事象用語を集計します。
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def top_adverse_events(drug_name, limit=20):
"""Get the most frequently reported adverse events for a drug."""
r = requests.get(f"{BASE}/event.json",
params={
"search": f'patient.drug.medicinalproduct:"{drug_name}"',
"count": "patient.reaction.reactionmeddrapt.exact",
"limit": limit
})
r.raise_for_status()
results = r.json()["results"]
return pd.DataFrame(results).rename(columns={"term": "reaction", "count": "reports"})
df_atorvastatin = top_adverse_events("atorvastatin", limit=15)
print("Top adverse events for atorvastatin:")
print(df_atorvastatin.head(10).to_string(index=False))
df_atorvastatin.to_csv("atorvastatin_adverse_events.csv", index=False)
# Compare two drugs: adverse event profile overlap
df_drug1 = top_adverse_events("simvastatin", limit=20)
df_drug2 = top_adverse_events("atorvastatin", limit=20)
common = set(df_drug1["reaction"]) & set(df_drug2["reaction"])
print(f"\nCommon adverse events (simvastatin ∩ atorvastatin): {len(common)}")
print("Shared reactions:", list(common)[:10])
クエリ 3:医薬品ラベルの検索
公式の医薬品ラベル(適応症、警告、用法・用量、禁忌)を取得します。
import requests
BASE = "https://api.fda.gov/drug"
def get_label(drug_name):
"""Retrieve FDA drug label by brand or generic name."""
r = requests.get(f"{BASE}/label.json",
params={"search": f'openfda.brand_name:"{drug_name}"',
"limit": 1})
if r.status_code == 404:
r = requests.get(f"{BASE}/label.json",
params={"search": f'openfda.generic_name:"{drug_name}"',
"limit": 1})
r.raise_for_status()
results = r.json()["results"]
return results[0] if results else None
label = get_label("Lipitor")
if label:
print(f"Brand name : {label.get('openfda', {}).get('brand_name', ['n/a'])[0]}")
print(f"Generic name: {label.get('openfda', {}).get('generic_name', ['n/a'])[0]}")
print(f"Manufacturer: {label.get('openfda', {}).get('manufacturer_name', ['n/a'])[0]}")
indications = label.get("indications_and_usage", ["n/a"])[0]
print(f"\nIndications (first 300 chars):\n{indications[:300]}...")
クエリ 4:NDC による医薬品製品の検索
National Drug Code によって市販製品の情報を取得します。
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def ndc_search(ndc_or_name, limit=10):
"""Search NDC directory for drug product information."""
# Search by product name or NDC
r = requests.get(f"{BASE}/ndc.json",
params={"search": f'generic_name:"{ndc_or_name}"',
"limit": limit})
r.raise_for_status()
return r.json()
data = ndc_search("metformin", limit=10)
total = data["meta"]["results"]["total"]
print(f"Metformin products: {total}")
rows = []
for prod in data["results"]:
rows.append({
"product_ndc": prod.get("product_ndc"),
"brand_name": prod.get("brand_name"),
"generic_name": prod.get("generic_name"),
"dosage_form": prod.get("dosage_form"),
"route": ", ".join(prod.get("route", [])),
"labeler": prod.get("labeler_name"),
})
df = pd.DataFrame(rows)
print(df.to_string(index=False))
クエリ 5:医薬品リコールの検索
医薬品名または企業名で FDA の規制措置や医薬品リコールを検索します。
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def drug_recalls(drug_name, limit=20):
"""Find FDA drug recalls for a given drug name."""
r = requests.get(f"{BASE}/enforcement.json",
params={
"search": f'product_description:"{drug_name}"',
"limit": limit
})
if r.status_code == 404:
return pd.DataFrame()
r.raise_for_status()
results = r.json()["results"]
return pd.DataFrame([{
"recalling_firm": rec.get("recalling_firm"),
"product": rec.get("product_description", "")[:80],
"reason": rec.get("reason_for_recall", "")[:100],
"classification": rec.get("classification"),
"recall_date": rec.get("recall_initiation_date"),
"status": rec.get("status"),
} for rec in results])
recalls = drug_recalls("metformin", limit=5)
print(f"Metformin recalls: {len(recalls)}")
if not recalls.empty:
print(recalls[["recalling_firm", "classification", "recall_date", "status"]].to_string(index=False))
クエリ 6:製品横断での有効成分の検索
特定の有効成分を含む医薬品製品をすべて検索します。
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def products_by_ingredient(ingredient, limit=50):
"""Find all FDA-listed products with a given active ingredient."""
r = requests.get(f"{BASE}/ndc.json",
params={
"search": f'active_ingredients.name:"{ingredient}"',
"limit": limit
})
r.raise_for_status()
data = r.json()
print(f"Total products with {ingredient}: {data['meta']['results']['total']}")
rows = []
for prod in data["results"]:
for ai in prod.get("active_ingredients", []):
if ingredient.lower() in ai.get("name", "").lower():
rows.append({
"brand": prod.get("brand_name"),
"generic": prod.get("generic_name"),
"strength": ai.get("strength"),
"dosage_form": prod.get("dosage_form"),
"route": ", ".join(prod.get("route", [])),
})
return pd.DataFrame(rows)
df = products_by_ingredient("metformin hydrochloride")
print(df.drop_duplicates(subset=["generic", "strength", "dosage_form"]).head(10).to_string(index=False))
主な概念
openFDA API エンドポイント
| エンドポイント | データセット | 主な用途 |
|---|---|---|
/drug/event.json | FAERS(有害事象) | ファーマコビジランス、安全性シグナル |
/drug/label.json | 構造化製品ラベル | 適応症、警告、用法・用量 |
/drug/ndc.json | NDC ディレクトリ | 市販製品、含量 |
/drug/enforcement.json | リコールおよび規制措置 | 医薬品のリコール、市場からの撤退 |
/device/event.json | MAUDE(医療機器の事象) | 医療機器の有害事象 |
クエリ構文
openFDA では Elasticsearch 形式のクエリを使用します。完全一致には field:"exact phrase"、あいまい検索には field:term、AND 条件には +field1:"A" +field2:"B" を使用します。count パラメーターを使用すると集計できます(GROUP BY と同等です)。ページネーションには limit(1~1000)を使用し、オフセットには skip を指定します。
一般的なワークフロー
ワークフロー 1:医薬品の安全性シグナル分析
目的:同じ治療クラスに属する複数の医薬品について有害事象の頻度を比較し、安全性プロファイルの違いを特定します。
import requests, pandas as pd, time
BASE = "https://api.fda.gov/drug"
drugs = ["atorvastatin", "simvastatin", "rosuvastatin"]
def count_reactions(drug, limit=20):
r = requests.get(f"{BASE}/event.json",
params={"search": f'patient.drug.medicinalproduct:"{drug}"',
"count": "patient.reaction.reactionmeddrapt.exact",
"limit": limit})
if r.status_code != 200:
return pd.Series(dtype=float, name=drug)
df = pd.DataFrame(r.json()["results"])
df.columns = ["reaction", drug]
return df.set_index("reaction")[drug]
series_list = []
for drug in drugs:
s = count_reactions(drug, limit=20)
series_list.append(s)
time.sleep(0.5)
comparison = pd.concat(series_list, axis=1).fillna(0)
comparison = comparison.sort_values(drugs[0], ascending=False)
print("Adverse event count comparison (statins):")
print(comparison.head(10).to_string())
comparison.to_csv("statin_safety_comparison.csv")
ワークフロー 2:医薬品ラベル情報の抽出
目的:複数の医薬品について適応症、禁忌、警告を抽出し、CSV に保存します。
import requests, pandas as pd, time, re
BASE = "https://api.fda.gov/drug"
def get_label_sections(drug_name):
r = requests.get(f"{BASE}/label.json",
params={"search": f'openfda.generic_name:"{drug_name}"', "limit": 1})
if r.status_code != 200 or not r.json()["results"]:
return None
label = r.json()["results"][0]
def clean(field):
text = " ".join(label.get(field, [""]))
return re.sub(r"\s+", " ", text).strip()[:500]
return {
"drug": drug_name,
"indications": clean("indications_and_usage"),
"contraindications": clean("contraindications"),
"warnings": clean("warnings_and_cautions") or clean("warnings"),
}
drugs = ["metformin", "atorvastatin", "lisinopril", "omeprazole"]
rows = []
for drug in drugs:
info = get_label_sections(drug)
if info:
rows.append(info)
time.sleep(0.4)
df = pd.DataFrame(rows)
df.to_csv("drug_labels.csv", index=False)
print(df[["drug", "indications"]].to_string(index=False))
主要なパラメーター
| パラメーター | モジュール | デフォルト | 範囲/オプション | 効果 |
|---|---|---|---|---|
search | すべてのエンドポイント | — | Elasticsearch 構文 | クエリをフィルタリングします |
count | すべてのエンドポイント | — | フィールド名 + .exact | フィールド値ごとに集計/カウントします |
limit | すべてのエンドポイント | 1 | 1~1000 | 1 リクエストあたりの結果数 |
skip | すべてのエンドポイント | 0 | 整数 | ページネーションのオフセット |
api_key | すべてのエンドポイント | — | API キー文字列 | レート制限を 1 日あたり 120K に引き上げます |
.exact サフィックス | count フィールド | — | フィールド名に追加 | トークン化ではなく、文字列を完全一致で照合します |
ベストプラクティス
-
無料の API キーを取得する:https://open.fda.gov/apis/authentication/ で即時登録でき、上限が 1 日あたり 1,000 件から 120,000 件に増加します。本番環境での利用には不可欠です。
-
医薬品名の検索には
.exactを使用する:patient.drug.medicinalproductではなくpatient.drug.medicinalproduct.exactを使うと、フレーズ全体が完全一致し、カウントを水増しする部分一致を防げます。 -
医薬品名を正規化する:FAERS の報告者はさまざまな表記(例:「Lipitor」、「atorvastatin calcium」、「ATORVASTATIN」)を使用します。複数の名称の表記ゆれを検索するか、網羅性を保つために一般名成分フィールドを使用してください。
-
FAERS の件数は慎重に解釈する:報告件数は発生率と同じではありません。FAERS は任意報告であり、報告バイアスの影響を受けます。件数の多さは、リスクの高さではなく、市場規模やメディアの注目度を反映している場合があります。
-
大きな結果セットはページネーションする:
limitの最大値は 1000 です。大きな結果セットをページネーションするにはskipを使用してください(meta.results内のtotalを参照)。
よく使うレシピ
レシピ:医薬品の FAERS 報告総数を確認する
使用する場面:医薬品の有害事象報告数の合計をすばやく確認する場合。
import requests
drug = "ibuprofen"
r = requests.get("https://api.fda.gov/drug/event.json",
params={"search": f'patient.drug.medicinalproduct.exact:"{drug}"',
"limit": 1})
total = r.json()["meta"]["results"]["total"]
print(f"Total FAERS reports for {drug}: {total:,}")
レシピ:重篤な有害事象のみを検索する
使用する場面:重篤(死亡、入院、障害)に分類された報告を FAERS から絞り込む場合。
import requests, pandas as pd
r = requests.get("https://api.fda.gov/drug/event.json",
params={
"search": 'patient.drug.medicinalproduct:"warfarin" AND serious:1',
"count": "patient.reaction.reactionmeddrapt.exact",
"limit": 10
})
df = pd.DataFrame(r.json()["results"])
df.columns = ["reaction", "serious_reports"]
print(df.to_string(index=False))
レシピ:医薬品の販売承認状況を確認する
使用する場面:医薬品が FDA の NDA/ANDA 承認を受けているかを確認し、承認年を調べる場合。
import requests
r = requests.get("https://api.fda.gov/drug/label.json",
params={"search": 'openfda.generic_name:"metformin"', "limit": 1})
label = r.json()["results"][0]
openfda = label.get("openfda", {})
print(f"Application numbers: {openfda.get('application_number', ['n/a'])}")
print(f"Product type: {openfda.get('product_type', ['n/a'])}")
print(f"NDA sponsor: {openfda.get('manufacturer_name', ['n/a'])}")
トラブルシューティング
| 問題 | 原因 | 解決策 |
|---|---|---|
{"error": {"code": "NOT_FOUND"}} を伴う HTTP 404 | クエリに一致する結果がありません | 医薬品名のスペルを確認し、別の名称表記を試してください |
HTTP 429 Too Many Requests | レート制限を超過しています | API キーに登録し、リクエストの間に time.sleep(1) を追加してください |
| カウント結果が想定と異なる | 医薬品名のトークン化 | .exact サフィックスを使用してください:medicinalproduct ではなく medicinalproduct.exact |
| ラベル検索で別の医薬品が返される | 名称が曖昧です | +openfda.product_type:"HUMAN PRESCRIPTION DRUG" を追加して絞り込んでください |
| FAERS 報告にフィールドがない | 任意報告が不完全です | .get("field", "n/a") を使ってフィールドが存在するか確認してください |
skip + limit > 26000 エラー | ページネーションの上限 | openFDA はページネーションを 26,000 件に制限しています。それを超える集計には count エンドポイントを使用してください |
関連スキル
clinicaltrials-database-search— openFDA で特定した医薬品の臨床試験データdrugbank-database-access— FDA データの背景情報となる医薬品の構造、標的、相互作用chembl-database-bioactivity— FAERS データベース内の医薬品の前臨床生物活性データstring-database-ppi— 有害事象分析で見つかった医薬品標的のタンパク質相互作用
参考資料
- openFDA API ドキュメント — API の全リファレンス、エンドポイント、クエリ構文
- openFDA API キーの登録 — レート制限を引き上げるための無料登録
- FAERS の概要 — FAERS データとその制限について
- openFDA GitHub — ソースコードとデータのダウンロードに関する参考情報