chembl-database-bioactivity について
chembl-database-bioactivityは、公開REST APIでChEMBLの化合物、標的、生物活性を検索するスキルです。創薬やケモインフォマティクスに向け、SDKや認証なしで構造検索や条件指定付きページングを利用できます。
主な機能
- 01名称、ID、物性による化合物検索
- 02標的と生物活性レコードの照会
- 03SMILESによる類似性・部分構造検索
- 04薬剤の作用機序と適応症の取得
- 05条件指定とページングによる結果整理
活用シーン
- 01標的に対する阻害活性の検索
- 02化合物系列間の構造活性相関の比較
- 03薬剤類似性の物性による分子の選別
- 04承認薬の作用機序と適応症の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jaechang-hits/ sciagent-skills --skill chembl-database-bioactivityインストール後、Claude Code で/chembl-database-bioactivityを入力して読み込まれたか確認します。
詳細
ChEMBL Database — 生物活性クエリ
SDK がない理由は?
chembl_webresource_clientパッケージは、認証不要の公開 REST/JSON API(https://www.ebi.ac.uk/chembl/api/data/)を便利に利用するためのラッパーです。SDK が利用できない場合でも、すべての操作は通常のrequestsと URL パラメーターで再現できます。この SKILL.md では、requestsがインストールされているあらゆる環境でコードを実行できるよう、全体を通して REST を使用しています。Django 形式のフィルター構文(field__icontains=…、field__lte=…、field__range=a,b)は、URL クエリパラメーターとして機能します。
概要
ChEMBL は EMBL-EBI の生物活性分子データベースです。200 万件以上の化合物、1,900 万件以上の生物活性測定値(IC50、Ki、EC50、Kd、…)、1 万 3,000 件以上のターゲットが登録されています。https://www.ebi.ac.uk/chembl/api/data/ の REST API は JSON(.json を追加)または XML/YAML を返し、認証は不要です。また、URL パラメーターによる Django 形式のクエリフィルターと、page_meta.next によるカーソル形式のページネーションに対応しています。
使用する場面
- 名前、ChEMBL ID、または物理化学的特性で化合物を検索する
- 特定のターゲットの生物活性データ(IC50、Ki、EC50)をクエリする
- SMILES を使って類似性検索や部分構造検索を行う
- 薬物の作用機序や臨床適応症を取得する
- ターゲットに対する阻害剤、アゴニスト、生物活性分子を特定する
- 化合物シリーズ全体の構造活性相関(SAR)を分析する
- リピンスキーのルール・オブ・ファイブなど、薬物らしさの基準で分子をフィルタリングする
- 一般的なケモインフォマティクス(SMILES の操作、フィンガープリント、記述子)には、代わりに
rdkit-cheminformaticsを使用してください - 別の化合物データベース(NIH、より広範な網羅性)を使う場合は、
pubchem-compound-searchを使用してください
前提条件
- Python パッケージ:
requests(唯一の必須パッケージ)。任意:表形式で分析する場合はpandas。 - API キー不要:ChEMBL は無料で利用できます。
- レート制限:公表された厳格な制限はありません。インフラストラクチャは共有されているため、一括処理のループではリクエスト間に
time.sleep(0.2-0.5)を追加し、HTTP 429 が発生した場合はバックオフしてください。
pip install requests
# Optional, for DataFrame work:
pip install pandas
クイックスタート
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"
# Retrieve a molecule by ChEMBL ID
r = requests.get(f"{BASE}/molecule/CHEMBL25.json", timeout=15)
r.raise_for_status()
aspirin = r.json()
print(f"{aspirin['pref_name']}: MW={aspirin['molecule_properties']['mw_freebase']}")
# ASPIRIN: MW=180.16
# Search targets by full name (acronyms like 'EGFR' don't match pref_name — use full term)
r = requests.get(
f"{BASE}/target.json",
params={"pref_name__icontains": "epidermal growth factor receptor",
"target_type": "SINGLE PROTEIN", "limit": 5},
timeout=15,
)
targets = r.json()["targets"]
print(f"EGFR-like targets: {len(targets)}, first={targets[0]['target_chembl_id']}")
# Potent bioactivities: EGFR (CHEMBL203) IC50 <= 100 nM
r = requests.get(
f"{BASE}/activity.json",
params={"target_chembl_id": "CHEMBL203",
"standard_type": "IC50",
"standard_value__lte": 100,
"standard_units": "nM",
"limit": 5},
timeout=30,
)
data = r.json()
print(f"EGFR IC50 ≤ 100 nM records: {data['page_meta']['total_count']}")
主な概念
フィルター演算子(Django 形式、URL パラメーターとして指定)
SDK の field__operator=value 構文は、URL クエリパラメーターにそのまま対応します。フィルターを組み合わせるには & を使用してください。
| 演算子 | URL パターン | URL の例 |
|---|---|---|
__exact | field=value | target_type=SINGLE+PROTEIN |
__iexact | field__iexact=value | pref_name__iexact=aspirin |
__contains / __icontains | field__icontains=value | pref_name__icontains=kinase |
__startswith / __endswith | field__startswith=Epi | pref_name__endswith=nib |
__gt / __gte / __lt / __lte | field__lte=100 | standard_value__lte=100 |
__range | field__range=lo,hi | molecule_properties__mw_freebase__range=300,500 |
__in | field__in=a,b,c | standard_type__in=IC50,Ki,Kd |
__isnull | field__isnull=False(Python の False / True 文字列) | pchembl_value__isnull=False |
__regex | field__regex=… | pref_name__regex=^EGF.*kinase$ |
__search | field__search=… | description__search=apoptosis |
requests.get(..., params={...}) に渡すと、ライブラリが URL エンコードを自動的に処理します(__range と __in のコンマを含む)。
コアエンドポイント
すべてのエンドポイントで、.json、.xml、.yaml のサフィックスを使用できます。以下では JSON をデフォルトとします。
| エンドポイント URL | 返される内容 | 主なフィールド |
|---|---|---|
/molecule/{chembl_id}.json | ID で指定した化合物 | pref_name、molecule_chembl_id、molecule_properties、molecule_structures |
/molecule.json?<filters> | 化合物検索 | ページ分割された molecules[] |
/target/{chembl_id}.json | ID で指定した標的 | pref_name、target_type、organism、target_components |
/target.json?<filters> | 標的検索 | ページ分割された targets[] |
/activity.json?<filters> | 生物活性レコード | ページ分割された activities[] |
/assay.json?<filters> | アッセイの詳細 | ページ分割された assays[] |
/drug.json?<filters> | 承認薬の情報 | drugs[]。ページ分割に対応。/drug/{chembl_id}.json も利用可能 |
/mechanism.json?<filters> | 作用機序 | ページ分割された mechanisms[] |
/drug_indication.json?<filters> | 治療適応症 | ページ分割された drug_indications[] |
/similarity/{smiles}/{tanimoto}.json | タニモト類似度(0~100) | similarity フィールドを含む、ページ分割された molecules[] |
/substructure/{smiles}.json | 部分構造検索 | ページ分割された molecules[] |
/image/{chembl_id}.svg | SVG 構造画像 | バイナリ SVG(JSON ではありません) |
/molecule_form/{chembl_id}.json | 親化合物/塩形 | molecule_forms[] |
/protein_class.json | タンパク質分類階層 | 階層形式で参照 |
/document.json?<filters> | 文献ソースレコード | ページ分割された documents[] |
レスポンスの形式
{
"page_meta": {
"limit": 20,
"offset": 0,
"total_count": 12145,
"next": "/chembl/api/data/activity.json?...&offset=20",
"previous": null
},
"activities": [ /* or molecules[], targets[], etc. */ ]
}
page_meta.next(相対 URL。先頭に https://www.ebi.ac.uk を付けます)が null になるまで、順にたどります。
分子特性
各レコードの molecule_properties から次のプロパティにアクセスできます。
| フィールド | 説明 |
|---|---|
mw_freebase | 分子量(遊離塩基) |
full_mwt | 全分子量(塩を含む) |
alogp | 計算 LogP |
hba | 水素結合受容体 |
hbd | 水素結合供与体 |
psa | 極性表面積 |
rtb | 回転可能結合 |
num_ro5_violations | リピンスキーの Rule of 5 違反数 |
ro3_pass | Rule of 3 への適合 |
cx_most_apka / cx_most_bpka | 最も酸性/塩基性の pKa |
標的情報のフィールド
| フィールド | 説明 |
|---|---|
target_chembl_id | ChEMBL 標的識別子 |
pref_name | 優先名(標的の正式名称)。「EGFR」のような略称では一致しません。正式名称を使用してください |
target_type | SINGLE PROTEIN、PROTEIN COMPLEX、ORGANISM、… |
organism | 標的の生物種(例:Homo sapiens) |
tax_id | NCBI 分類 ID |
target_components[] | 構成要素(UniProt アクセッション、配列、…) |
生物活性データのフィールド
| フィールド | 説明 |
|---|---|
standard_type | 活性の種類:IC50、Ki、Kd、EC50、… |
standard_value | 活性の数値 |
standard_units | 単位:nM、uM、… |
pchembl_value | 正規化された -log10 活性値(6 超は高活性) |
activity_comment | 活性に関する注釈 |
data_validity_comment | データ品質フラグ(解析前に確認してください) |
potential_duplicate | 重複フラグ |
コア API
1. 分子クエリ
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"
# By ChEMBL ID
r = requests.get(f"{BASE}/molecule/CHEMBL25.json", timeout=15)
aspirin = r.json()
print(f"{aspirin['pref_name']}: MW={aspirin['molecule_properties']['mw_freebase']}")
# By name (case-insensitive substring)
r = requests.get(f"{BASE}/molecule.json",
params={"pref_name__icontains": "imatinib", "limit": 5},
timeout=15)
for mol in r.json()["molecules"]:
print(f" {mol['molecule_chembl_id']} {mol.get('pref_name')!r}")
# By Lipinski-compliant property ranges
r = requests.get(f"{BASE}/molecule.json",
params={"molecule_properties__mw_freebase__range": "300,500",
"molecule_properties__alogp__lte": 5,
"molecule_properties__hba__lte": 10,
"molecule_properties__hbd__lte": 5,
"limit": 3},
timeout=15)
print(f"Lipinski-compliant total: {r.json()['page_meta']['total_count']}")
2. 標的クエリ
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"
# By ChEMBL ID
r = requests.get(f"{BASE}/target/CHEMBL203.json", timeout=15)
egfr = r.json()
print(f"{egfr['pref_name']} ({egfr['organism']}) — type={egfr['target_type']}")
# Search by full name (NOT acronym) + type
r = requests.get(f"{BASE}/target.json",
params={"pref_name__icontains": "kinase",
"target_type": "SINGLE PROTEIN", "limit": 5},
timeout=15)
d = r.json()
print(f"Kinase SINGLE_PROTEIN targets: total={d['page_meta']['total_count']}")
for t in d["targets"][:5]:
print(f" {t['target_chembl_id']:12s} {t.get('pref_name')!r} ({t['organism']})")
# By organism
r = requests.get(f"{BASE}/target.json",
params={"organism": "Homo sapiens", "limit": 3},
timeout=15)
print(f"Human targets: total={r.json()['page_meta']['total_count']}")
3. 生物活性データ
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"
# Potent inhibitors for a target (EGFR = CHEMBL203)
r = requests.get(f"{BASE}/activity.json",
params={"target_chembl_id": "CHEMBL203",
"standard_type": "IC50",
"standard_value__lte": 100,
"standard_units": "nM",
"limit": 5},
timeout=30)
data = r.json()
print(f"EGFR IC50≤100nM: total={data['page_meta']['total_count']}")
for act in data["activities"][:5]:
print(f" {act['molecule_chembl_id']:14s} IC50={act['standard_value']} nM "
f"pChEMBL={act.get('pchembl_value')}")
# All pChEMBL-tagged activities for a compound
r = requests.get(f"{BASE}/activity.json",
params={"molecule_chembl_id": "CHEMBL25",
"pchembl_value__isnull": "False",
"limit": 5},
timeout=30)
print(f"Aspirin pChEMBL activities: total={r.json()['page_meta']['total_count']}")
# Multiple activity types (CHEMBL240 = D2 dopamine receptor)
r = requests.get(f"{BASE}/activity.json",
params={"target_chembl_id": "CHEMBL240",
"standard_type__in": "IC50,Ki,Kd",
"limit": 5},
timeout=30)
print(f"D2 receptor IC50/Ki/Kd: total={r.json()['page_meta']['total_count']}")
4. 構造ベースの検索
import requests
from urllib.parse import quote
BASE = "https://www.ebi.ac.uk/chembl/api/data"
# Similarity search (Tanimoto ≥ 85%)
# Path-style endpoint: /similarity/{smiles}/{threshold}
# The SMILES MUST be URL-encoded (it contains '/', '(', ')' etc.)
aspirin_smiles = quote("CC(=O)Oc1ccccc1C(=O)O", safe="")
r = requests.get(f"{BASE}/similarity/{aspirin_smiles}/85.json",
params={"limit": 5}, timeout=30)
data = r.json()
print(f"Similar to aspirin (≥85% Tanimoto): total={data['page_meta']['total_count']}")
for m in data["molecules"][:5]:
print(f" {m['molecule_chembl_id']} similarity={m.get('similarity')}")
# Substructure search
benzimidazole = quote("c1ccc2[nH]cnc2c1", safe="")
r = requests.get(f"{BASE}/substructure/{benzimidazole}.json",
params={"limit": 3}, timeout=30)
print(f"Benzimidazole substructure total: {r.json()['page_meta']['total_count']}")
5. 薬剤と作用機序のデータ
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"
# Drug record (max clinical phase, ATC class, etc.)
r = requests.get(f"{BASE}/drug/CHEMBL941.json", timeout=15) # imatinib
drug = r.json()
print(f"Imatinib max_phase={drug.get('max_phase')}")
# Mechanisms of action — note: not every drug has mechanism records.
# Imatinib (CHEMBL941) returns 0 mechanism rows; sunitinib (CHEMBL535) has many.
r = requests.get(f"{BASE}/mechanism.json",
params={"molecule_chembl_id": "CHEMBL535"}, timeout=15)
for m in r.json()["mechanisms"]:
print(f" {m['mechanism_of_action']} → target {m.get('target_chembl_id')}")
# Therapeutic indications
r = requests.get(f"{BASE}/drug_indication.json",
params={"molecule_chembl_id": "CHEMBL941", "limit": 5},
timeout=15)
for ind in r.json()["drug_indications"]:
print(f" {ind.get('mesh_heading')!r} max_phase_for_ind={ind.get('max_phase_for_ind')}")
# SVG molecular structure image — direct binary response, NOT JSON
# Do NOT call /image/{cid}.json — that endpoint raises JSONDecodeError.
r = requests.get(f"{BASE}/image/CHEMBL25.svg", timeout=15)
r.raise_for_status()
with open("aspirin.svg", "w") as f:
f.write(r.text)
print(f"Saved aspirin.svg ({len(r.text)} bytes, looks_svg={'<svg' in r.text})")
一般的なワークフロー
ワークフロー 1:標的の阻害剤を検索する
注: pref_name__icontains は正式名称に一致します。'EGFR' や 'BRAF' のような略称では結果が 0 件になるため、'epidermal growth factor receptor' または 'B-raf'(ハイフンあり)を使用してください。
import requests, pandas as pd, time
BASE = "https://www.ebi.ac.uk/chembl/api/data"
# Step 1: Resolve the target by full name
r = requests.get(f"{BASE}/target.json",
params={"pref_name__icontains": "B-raf",
"target_type": "SINGLE PROTEIN", "limit": 5},
timeout=15)
targets = r.json()["targets"]
human_braf = next(t for t in targets if t["organism"] == "Homo sapiens")
target_id = human_braf["target_chembl_id"]
print(f"Using {target_id} — {human_braf['pref_name']}")
# Step 2: Paginate all potent IC50 activities (cap at 500 for demo)
url = (f"{BASE}/activity.json"
f"?target_chembl_id={target_id}"
f"&standard_type=IC50"
f"&standard_value__lte=100"
f"&standard_units=nM"
f"&pchembl_value__isnull=False"
f"&limit=200")
records = []
while url and len(records) < 500:
r = requests.get(url, timeout=30)
r.raise_for_status()
data = r.json()
records.extend(data["activities"])
nxt = data["page_meta"].get("next")
url = f"https://www.ebi.ac.uk{nxt}" if nxt else None
time.sleep(0.2)
df = pd.DataFrame(records)
df["standard_value"] = pd.to_numeric(df["standard_value"])
print(f"Retrieved {len(df)} potent {target_id} compounds")
print(df[["molecule_chembl_id", "standard_value", "pchembl_value"]].head(10))
ワークフロー 2:既知の薬剤を解析する
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"
# Sunitinib (CHEMBL535) — has documented mechanisms + indications.
# Imatinib (CHEMBL941) sometimes returns 0 mechanism rows depending on ChEMBL release.
chembl_id = "CHEMBL535"
# Molecule record
m = requests.get(f"{BASE}/molecule/{chembl_id}.json", timeout=15).json()
print(f"Name: {m['pref_name']}")
print(f"MW : {m['molecule_properties']['mw_freebase']}")
# Mechanisms
mechs = requests.get(f"{BASE}/mechanism.json",
params={"molecule_chembl_id": chembl_id},
timeout=15).json()["mechanisms"]
for mc in mechs:
print(f" Mechanism: {mc['mechanism_of_action']}")
# Indications
inds = requests.get(f"{BASE}/drug_indication.json",
params={"molecule_chembl_id": chembl_id, "limit": 5},
timeout=15).json()["drug_indications"]
for ind in inds:
print(f" Indication: {ind.get('mesh_heading')} "
f"(Phase {ind.get('max_phase_for_ind')})")
# Bioactivity record count
total = requests.get(f"{BASE}/activity.json",
params={"molecule_chembl_id": chembl_id,
"pchembl_value__isnull": "False",
"limit": 1},
timeout=30).json()["page_meta"]["total_count"]
print(f"Total bioactivity records (pChEMBL-tagged): {total}")
ワークフロー 3:SAR 研究
import requests, pandas as pd, time
from urllib.parse import quote
BASE = "https://www.ebi.ac.uk/chembl/api/data"
# Step 1: Similar compounds to a lead (e.g., quinoline scaffold)
lead_smiles = "c1ccc2c(c1)cc(nc2N)c3ccc(cc3)NC(=O)c4ccccc4"
r = requests.get(f"{BASE}/similarity/{quote(lead_smiles, safe='')}/80.json",
params={"limit": 20}, timeout=30)
analogs = r.json()["molecules"]
print(f"Analogs found: {len(analogs)}")
# Step 2: Collect bioactivities for each analog
records = []
for compound in analogs[:20]:
cid = compound["molecule_chembl_id"]
acts = requests.get(f"{BASE}/activity.json",
params={"molecule_chembl_id": cid,
"standard_type": "IC50",
"pchembl_value__isnull": "False",
"limit": 20},
timeout=30).json()["activities"]
for act in acts:
records.append({
"chembl_id": cid,
"target": act.get("target_pref_name"),
"IC50_nM": act.get("standard_value"),
"pchembl": act.get("pchembl_value"),
"mw": (compound.get("molecule_properties") or {}).get("mw_freebase"),
"alogp": (compound.get("molecule_properties") or {}).get("alogp"),
})
time.sleep(0.2)
df = pd.DataFrame(records)
if not df.empty:
df["IC50_nM"] = pd.to_numeric(df["IC50_nM"])
print(df.groupby("target")["IC50_nM"].describe())
よく使うレシピ
レシピ:バーチャルスクリーニング用フィルター(リピンスキーの Rule of 5)
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"
r = requests.get(f"{BASE}/molecule.json",
params={"molecule_properties__mw_freebase__range": "300,500",
"molecule_properties__alogp__lte": 5,
"molecule_properties__hba__lte": 10,
"molecule_properties__hbd__lte": 5,
"molecule_properties__num_ro5_violations": 0,
"limit": 1},
timeout=15)
print(f"Drug-like candidates: {r.json()['page_meta']['total_count']}")
レシピ:活性データをページ分割して CSV に出力する
import requests, pandas as pd, time
BASE = "https://www.ebi.ac.uk/chembl/api/data"
url = (f"{BASE}/activity.json"
f"?target_chembl_id=CHEMBL203"
f"&standard_type=IC50"
f"&pchembl_value__isnull=False"
f"&limit=500")
all_acts = []
while url:
r = requests.get(url, timeout=60)
r.raise_for_status()
data = r.json()
all_acts.extend(data["activities"])
nxt = data["page_meta"].get("next")
url = f"https://www.ebi.ac.uk{nxt}" if nxt else None
time.sleep(0.3)
df = pd.DataFrame(all_acts)
df.to_csv("egfr_activities.csv", index=False)
print(f"Exported {len(df)} records → egfr_activities.csv")
レシピ:リトライ機能付きの堅牢なセッション
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
def chembl_session(retries=3, backoff=1.0):
s = requests.Session()
s.headers.update({"Accept": "application/json"})
s.mount("https://", HTTPAdapter(max_retries=Retry(
total=retries, backoff_factor=backoff,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["GET"])))
return s
session = chembl_session()
r = session.get("https://www.ebi.ac.uk/chembl/api/data/molecule/CHEMBL25.json", timeout=15)
print(r.json()["pref_name"])
レシピ:SVG 構造画像をダウンロードする
import requests
r = requests.get("https://www.ebi.ac.uk/chembl/api/data/image/CHEMBL25.svg", timeout=15)
r.raise_for_status()
with open("aspirin.svg", "w") as f:
f.write(r.text)
主要なパラメーター
| パラメーター | エンドポイント | デフォルト | 説明 |
|---|---|---|---|
limit | すべてのリストエンドポイント | 20 | ページサイズ。最大 1000 |
offset | すべてのリストエンドポイント | 0 | ページネーションのオフセット(または page_meta.next をたどります) |
format | すべてのエンドポイント | json(.json サフィックス経由) | .xml、.yaml も利用できます |
pref_name__icontains | /target、/molecule | — | 名前全体に対する部分文字列検索です。略称は一致しないため、正式名称を使用してください |
target_chembl_id | /activity | — | 例:CHEMBL203(EGFR)、CHEMBL240(D2 受容体) |
molecule_chembl_id | /activity、/mechanism、/drug_indication | — | 例:CHEMBL25(アスピリン) |
standard_type | /activity | — | IC50、Ki、Kd、EC50 |
standard_value__lte | /activity | — | 活性値の最大値(standard_units と組み合わせて使用) |
pchembl_value__isnull | /activity | — | pChEMBL タグ付きデータを必須にするには "False" を指定します |
target_type | /target | — | SINGLE PROTEIN、PROTEIN COMPLEX、ORGANISM、… |
{tanimoto}(パス) | /similarity/{smiles}/{tanimoto} | — | Tanimoto 閾値(0~100) |
{smiles}(パス) | /similarity、/substructure | — | URL エンコードされた SMILES(urllib.parse.quote(s, safe="")) |
トラブルシューティング
| 問題 | 原因 | 解決策 |
|---|---|---|
pref_name__icontains=EGFR(または BRAF)が 0 件を返す | ChEMBL では正式名称が保存されており、略称は一致しません | "epidermal growth factor receptor" を使用してください。BRAF にはハイフン付きの "B-raf" を使用してください |
mechanism.json?molecule_chembl_id=CHEMBL941 が空を返す | すべてのリリースですべての薬剤にメカニズムの行があるわけではありません(例:現在のデータではイマチニブは 0 件です) | データが登録されていることが分かっている例として、CHEMBL535(スニチニブ)または CHEMBL192(シルデナフィル)を使用してください |
/image/{cid}.json で JSONDecodeError が発生する | 画像エンドポイントは JSON ではなくバイナリです | 必ず .svg または .png サフィックスを使用してください:/image/{cid}.svg |
/molecule/{id} で 404 が発生する | ChEMBL ID の形式が無効です | ID にはプレフィックスが必要です:25 ではなく CHEMBL25 |
| 類似性検索で 400 が発生する | SMILES がエンコードされていません(/ が URL パスと衝突します) | URL エンコードしてください:urllib.parse.quote(smiles, safe="") |
total_count はより大きいのに next ページが空 | 内部制限に達しました(offset ページネーションでは通常 10000 件です) | フィルター(期間、標的クラス)を絞り込んで再度ページネーションを行ってください。または、10 万件を超えるレコードには ChEMBL FTP ダウンロードを使用してください |
HTTP 429 Too Many Requests | リクエストの間隔が短すぎます | time.sleep(0.3) を追加し、Retry アダプターを設定してください(レシピを参照) |
activity レコードの単位が混在している | アッセイによって nM/µM/阻害率(%)で報告されています | standard_units="nM" でフィルターし、アッセイ間の比較には pchembl_value を優先してください |
data_validity_comment が空ではない | キュレーションフラグが設定されています(例:「転記ミスの可能性あり」、「通常の範囲外」) | SAR/回帰分析の前にこれらの行を除外してください |
| 活性レコードが重複している | 同じ測定値が複数のソースで報告されています | potential_duplicate=True を確認して重複を除去してください |
ベストプラクティス
- 複数の研究間で比較する場合は、
pchembl_valueを使用してください。IC50/Ki/EC50を、比較可能な-log10スケールに正規化します。 - 集計を計算する前に、必ず
data_validity_commentを確認してください。フラグ付きの行は分布を歪める可能性があります。 - 活性クエリでは、nMとµMが混在しないよう、
standard_units="nM"を指定してください。 offsetを手動で増やす代わりに、ページネーションではpage_meta.nextに従ってください。URLに適切なカーソルがすでに含まれています。- パス形式のエンドポイント(
/similarity/{smiles}/...、/substructure/{smiles})では、urllib.parse.quote(smi, safe="")を使用してSMILESをURLエンコードしてください。 - バッチ処理では、リトライアダプターを設定した
Sessionを使用してください(レシピを参照)。ChEMBLはかなりのトラフィックを処理しており、502/503を返すことがあります。 - 10万件を超えるレコードの場合は、ページネーション付きのAPI呼び出しよりもChEMBL FTP ダウンロードを利用してください。
pref_name__icontainsでの略語の使用には注意してください。EGFR、BRAF、HER2はいずれも検索結果が0件になります。正式名称を使用するか、代わりにtarget_components__accession=<UniProt>で絞り込んでください。
関連スキル
rdkit-cheminformatics— SMILESの操作、フィンガープリント、記述子datamol-cheminformatics— 分子の前処理と特徴量化pubchem-compound-search— 代替の化合物データベース(NIH。対象範囲はより広いものの、生物活性の情報は少なめです)pdb-database— RCSB PDB REST APIを介したChEMBLターゲットの3D構造opentargets-database— ChEMBLの医薬品とターゲットのエビデンスを疾患との関連付けに紐付けます
参考資料
- ChEMBLウェブサイト:https://www.ebi.ac.uk/chembl/
- REST APIルート:https://www.ebi.ac.uk/chembl/api/data/
- APIドキュメント:https://www.ebi.ac.uk/chembl/api/data/docs
- インターフェースのドキュメント(Djangoのフィルター構文):https://chembl.gitbook.io/chembl-interface-documentation/web-services
- 一括ダウンロード(10万件を超えるレコード向け):https://chembl.gitbook.io/chembl-interface-documentation/downloads
- SDKを使用する場合は、PyPIパッケージの
chembl_webresource_clientを参照してください。このSKILL.mdでは基盤となるREST APIを直接使用するため、SDKのインストールは不要です。