@nahisaho/satori 0.20.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -39
- package/package.json +1 -1
- package/src/.github/skills/scientific-biothings-idmapping/SKILL.md +4 -0
- package/src/.github/skills/scientific-cellxgene-census/SKILL.md +257 -0
- package/src/.github/skills/scientific-clingen-curation/SKILL.md +258 -0
- package/src/.github/skills/scientific-clinical-nlp/SKILL.md +250 -0
- package/src/.github/skills/scientific-clinical-pharmacology/SKILL.md +361 -0
- package/src/.github/skills/scientific-clinical-standards/SKILL.md +444 -0
- package/src/.github/skills/scientific-crispr-design/SKILL.md +369 -0
- package/src/.github/skills/scientific-drug-repurposing/SKILL.md +4 -0
- package/src/.github/skills/scientific-environmental-ecology/SKILL.md +5 -0
- package/src/.github/skills/scientific-epidemiology-public-health/SKILL.md +5 -0
- package/src/.github/skills/scientific-epigenomics-chromatin/SKILL.md +5 -0
- package/src/.github/skills/scientific-glycomics/SKILL.md +274 -0
- package/src/.github/skills/scientific-gtex-tissue-expression/SKILL.md +5 -2
- package/src/.github/skills/scientific-hgnc-nomenclature/SKILL.md +282 -0
- package/src/.github/skills/scientific-human-cell-atlas/SKILL.md +3 -0
- package/src/.github/skills/scientific-human-protein-atlas/SKILL.md +4 -0
- package/src/.github/skills/scientific-immunoinformatics/SKILL.md +9 -0
- package/src/.github/skills/scientific-lipidomics/SKILL.md +284 -0
- package/src/.github/skills/scientific-metabolomics/SKILL.md +3 -0
- package/src/.github/skills/scientific-metabolomics-network/SKILL.md +311 -0
- package/src/.github/skills/scientific-metagenome-assembled-genomes/SKILL.md +299 -0
- package/src/.github/skills/scientific-model-organism-db/SKILL.md +8 -0
- package/src/.github/skills/scientific-pharmacogenomics/SKILL.md +4 -0
- package/src/.github/skills/scientific-pharos-targets/SKILL.md +276 -0
- package/src/.github/skills/scientific-protein-structure-analysis/SKILL.md +4 -0
- package/src/.github/skills/scientific-public-health-data/SKILL.md +11 -0
- package/src/.github/skills/scientific-systems-biology/SKILL.md +11 -0
- package/src/.github/skills/scientific-variant-effect-prediction/SKILL.md +7 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-clinical-pharmacology
|
|
3
|
+
description: |
|
|
4
|
+
臨床薬理学モデリングスキル。PopPK (NLME 混合効果モデル)・
|
|
5
|
+
PBPK シミュレーション・TDM 投与量最適化・
|
|
6
|
+
Emax/Sigmoid PD モデリング・薬物間相互作用予測・
|
|
7
|
+
臨床薬理パイプライン。
|
|
8
|
+
TU 外スキル (Python + nlmixr2/mrgsolve ラッパー)。
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Scientific Clinical Pharmacology
|
|
12
|
+
|
|
13
|
+
母集団薬物動態 (PopPK)・生理学的薬物動態 (PBPK)・
|
|
14
|
+
薬力学 (PD) モデリングを統合した臨床薬理学
|
|
15
|
+
解析パイプラインを提供する。
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
- 母集団 PK (PopPK) の NLME 解析を行うとき
|
|
20
|
+
- PBPK モデルで薬物動態をシミュレーションするとき
|
|
21
|
+
- TDM (Therapeutic Drug Monitoring) 投与量を最適化するとき
|
|
22
|
+
- Emax/Sigmoid PD モデルを当てはめるとき
|
|
23
|
+
- 薬物間相互作用 (DDI) の影響を予測するとき
|
|
24
|
+
- 小児・腎障害・肝障害の用量調節を検討するとき
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
## 1. コンパートメント PK モデル
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import numpy as np
|
|
34
|
+
import pandas as pd
|
|
35
|
+
from scipy.integrate import odeint
|
|
36
|
+
from scipy.optimize import minimize
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def one_compartment_iv(y, t, cl, v):
|
|
40
|
+
"""1-コンパートメント IV ボーラス ODE。"""
|
|
41
|
+
return [-cl / v * y[0]]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def two_compartment_iv(y, t, cl, v1, q, v2):
|
|
45
|
+
"""2-コンパートメント IV ボーラス ODE。"""
|
|
46
|
+
c1 = y[0] / v1
|
|
47
|
+
c2 = y[1] / v2
|
|
48
|
+
dy1 = -cl * c1 - q * (c1 - c2)
|
|
49
|
+
dy2 = q * (c1 - c2)
|
|
50
|
+
return [dy1, dy2]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def simulate_pk(dose, model="1cmt",
|
|
54
|
+
params=None,
|
|
55
|
+
times=None):
|
|
56
|
+
"""
|
|
57
|
+
PK モデルシミュレーション。
|
|
58
|
+
|
|
59
|
+
Parameters:
|
|
60
|
+
dose: float — 投与量 (mg)
|
|
61
|
+
model: str — "1cmt" or "2cmt"
|
|
62
|
+
params: dict — PK パラメータ
|
|
63
|
+
1cmt: {cl, v}
|
|
64
|
+
2cmt: {cl, v1, q, v2}
|
|
65
|
+
times: array — 時間点 (h)
|
|
66
|
+
"""
|
|
67
|
+
if times is None:
|
|
68
|
+
times = np.linspace(0, 24, 241)
|
|
69
|
+
if params is None:
|
|
70
|
+
params = ({"cl": 5.0, "v": 50.0}
|
|
71
|
+
if model == "1cmt"
|
|
72
|
+
else {"cl": 5.0, "v1": 50.0,
|
|
73
|
+
"q": 2.0, "v2": 30.0})
|
|
74
|
+
|
|
75
|
+
if model == "1cmt":
|
|
76
|
+
y0 = [dose]
|
|
77
|
+
sol = odeint(one_compartment_iv, y0,
|
|
78
|
+
times,
|
|
79
|
+
args=(params["cl"],
|
|
80
|
+
params["v"]))
|
|
81
|
+
conc = sol[:, 0] / params["v"]
|
|
82
|
+
else:
|
|
83
|
+
y0 = [dose, 0.0]
|
|
84
|
+
sol = odeint(two_compartment_iv, y0,
|
|
85
|
+
times,
|
|
86
|
+
args=(params["cl"],
|
|
87
|
+
params["v1"],
|
|
88
|
+
params["q"],
|
|
89
|
+
params["v2"]))
|
|
90
|
+
conc = sol[:, 0] / params["v1"]
|
|
91
|
+
|
|
92
|
+
df = pd.DataFrame({
|
|
93
|
+
"time": times, "concentration": conc})
|
|
94
|
+
cmax = conc.max()
|
|
95
|
+
t_half = 0.693 * params.get(
|
|
96
|
+
"v", params.get("v1", 50)) / params["cl"]
|
|
97
|
+
print(f"PK sim ({model}): Cmax={cmax:.2f}, "
|
|
98
|
+
f"t1/2={t_half:.1f}h")
|
|
99
|
+
return df
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## 2. 母集団 PK (PopPK) 推定
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
def popk_estimation(data, model="1cmt"):
|
|
106
|
+
"""
|
|
107
|
+
母集団 PK パラメータ推定 (簡易 NLME)。
|
|
108
|
+
|
|
109
|
+
Parameters:
|
|
110
|
+
data: pd.DataFrame — 個体別濃度データ
|
|
111
|
+
columns: [id, time, dv, dose, (covariates)]
|
|
112
|
+
model: str — "1cmt" or "2cmt"
|
|
113
|
+
"""
|
|
114
|
+
subjects = data["id"].unique()
|
|
115
|
+
|
|
116
|
+
def _objective(theta):
|
|
117
|
+
"""集団目的関数 (OFV)。"""
|
|
118
|
+
tv_cl = np.exp(theta[0])
|
|
119
|
+
tv_v = np.exp(theta[1])
|
|
120
|
+
omega_cl = np.exp(theta[2])
|
|
121
|
+
omega_v = np.exp(theta[3])
|
|
122
|
+
sigma = np.exp(theta[4])
|
|
123
|
+
|
|
124
|
+
ofv = 0.0
|
|
125
|
+
for subj in subjects:
|
|
126
|
+
sdata = data[data["id"] == subj]
|
|
127
|
+
dose = sdata["dose"].iloc[0]
|
|
128
|
+
times = sdata["time"].values
|
|
129
|
+
obs = sdata["dv"].values
|
|
130
|
+
|
|
131
|
+
# 個体パラメータ (EBE 近似)
|
|
132
|
+
eta_cl = 0.0
|
|
133
|
+
eta_v = 0.0
|
|
134
|
+
cl_i = tv_cl * np.exp(eta_cl)
|
|
135
|
+
v_i = tv_v * np.exp(eta_v)
|
|
136
|
+
|
|
137
|
+
pred = dose / v_i * np.exp(
|
|
138
|
+
-cl_i / v_i * times)
|
|
139
|
+
pred = np.maximum(pred, 1e-10)
|
|
140
|
+
|
|
141
|
+
# OFV 要素
|
|
142
|
+
residual = np.log(obs + 1e-10) - np.log(
|
|
143
|
+
pred)
|
|
144
|
+
ofv += np.sum(
|
|
145
|
+
residual**2 / sigma**2
|
|
146
|
+
+ np.log(sigma**2))
|
|
147
|
+
|
|
148
|
+
return ofv
|
|
149
|
+
|
|
150
|
+
# 初期値
|
|
151
|
+
x0 = [np.log(5), np.log(50),
|
|
152
|
+
np.log(0.3), np.log(0.3),
|
|
153
|
+
np.log(0.2)]
|
|
154
|
+
|
|
155
|
+
result = minimize(_objective, x0,
|
|
156
|
+
method="Nelder-Mead",
|
|
157
|
+
options={"maxiter": 5000})
|
|
158
|
+
|
|
159
|
+
estimates = {
|
|
160
|
+
"tv_cl": round(np.exp(result.x[0]), 3),
|
|
161
|
+
"tv_v": round(np.exp(result.x[1]), 3),
|
|
162
|
+
"omega_cl": round(np.exp(result.x[2]), 3),
|
|
163
|
+
"omega_v": round(np.exp(result.x[3]), 3),
|
|
164
|
+
"sigma": round(np.exp(result.x[4]), 3),
|
|
165
|
+
"ofv": round(result.fun, 2),
|
|
166
|
+
"converged": result.success,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
print(f"PopPK: CL={estimates['tv_cl']} L/h, "
|
|
170
|
+
f"V={estimates['tv_v']} L, "
|
|
171
|
+
f"OFV={estimates['ofv']}")
|
|
172
|
+
return estimates
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## 3. TDM 投与量最適化
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
def tdm_dose_optimization(
|
|
179
|
+
current_conc, current_dose,
|
|
180
|
+
target_range, pk_params,
|
|
181
|
+
interval=12):
|
|
182
|
+
"""
|
|
183
|
+
TDM ベース投与量最適化。
|
|
184
|
+
|
|
185
|
+
Parameters:
|
|
186
|
+
current_conc: float — 現在トラフ濃度
|
|
187
|
+
current_dose: float — 現在投与量 (mg)
|
|
188
|
+
target_range: tuple — 目標濃度範囲 (min, max)
|
|
189
|
+
pk_params: dict — {cl, v} PK パラメータ
|
|
190
|
+
interval: float — 投与間隔 (h)
|
|
191
|
+
"""
|
|
192
|
+
cl = pk_params["cl"]
|
|
193
|
+
v = pk_params["v"]
|
|
194
|
+
ke = cl / v
|
|
195
|
+
target_mid = (target_range[0]
|
|
196
|
+
+ target_range[1]) / 2
|
|
197
|
+
|
|
198
|
+
# 線形 PK 仮定: 用量比例
|
|
199
|
+
ratio = target_mid / max(current_conc, 0.01)
|
|
200
|
+
new_dose = current_dose * ratio
|
|
201
|
+
|
|
202
|
+
# シミュレーション検証
|
|
203
|
+
times = np.linspace(0, interval, 100)
|
|
204
|
+
conc_profile = (new_dose / v
|
|
205
|
+
* np.exp(-ke * times))
|
|
206
|
+
cmax = conc_profile[0]
|
|
207
|
+
ctrough = conc_profile[-1]
|
|
208
|
+
|
|
209
|
+
in_range = (target_range[0] <= ctrough
|
|
210
|
+
<= target_range[1])
|
|
211
|
+
|
|
212
|
+
result = {
|
|
213
|
+
"current_dose": current_dose,
|
|
214
|
+
"current_trough": current_conc,
|
|
215
|
+
"recommended_dose": round(new_dose, 1),
|
|
216
|
+
"predicted_cmax": round(cmax, 2),
|
|
217
|
+
"predicted_trough": round(ctrough, 2),
|
|
218
|
+
"target_range": target_range,
|
|
219
|
+
"in_target": in_range,
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
status = "✓" if in_range else "✗"
|
|
223
|
+
print(f"TDM: {current_dose}mg → "
|
|
224
|
+
f"{new_dose:.1f}mg "
|
|
225
|
+
f"(trough {ctrough:.2f}) {status}")
|
|
226
|
+
return result
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## 4. Emax PD モデル
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
def emax_model(conc, emax, ec50, hill=1):
|
|
233
|
+
"""Emax / Sigmoid Emax モデル。"""
|
|
234
|
+
return emax * conc**hill / (
|
|
235
|
+
ec50**hill + conc**hill)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def fit_emax(conc_data, effect_data,
|
|
239
|
+
sigmoid=False):
|
|
240
|
+
"""
|
|
241
|
+
Emax モデルフィッティング。
|
|
242
|
+
|
|
243
|
+
Parameters:
|
|
244
|
+
conc_data: array — 濃度データ
|
|
245
|
+
effect_data: array — 薬効データ
|
|
246
|
+
sigmoid: bool — Sigmoid (Hill) モデル
|
|
247
|
+
"""
|
|
248
|
+
from scipy.optimize import curve_fit
|
|
249
|
+
|
|
250
|
+
conc = np.array(conc_data)
|
|
251
|
+
effect = np.array(effect_data)
|
|
252
|
+
|
|
253
|
+
if sigmoid:
|
|
254
|
+
def _model(c, emax, ec50, hill):
|
|
255
|
+
return emax_model(c, emax, ec50, hill)
|
|
256
|
+
p0 = [max(effect), np.median(conc), 1.0]
|
|
257
|
+
bounds = ([0, 0, 0.1], [np.inf, np.inf, 10])
|
|
258
|
+
else:
|
|
259
|
+
def _model(c, emax, ec50):
|
|
260
|
+
return emax_model(c, emax, ec50, 1)
|
|
261
|
+
p0 = [max(effect), np.median(conc)]
|
|
262
|
+
bounds = ([0, 0], [np.inf, np.inf])
|
|
263
|
+
|
|
264
|
+
popt, pcov = curve_fit(
|
|
265
|
+
_model, conc, effect, p0=p0,
|
|
266
|
+
bounds=bounds, maxfev=5000)
|
|
267
|
+
|
|
268
|
+
perr = np.sqrt(np.diag(pcov))
|
|
269
|
+
|
|
270
|
+
result = {
|
|
271
|
+
"emax": round(popt[0], 3),
|
|
272
|
+
"ec50": round(popt[1], 3),
|
|
273
|
+
"emax_se": round(perr[0], 3),
|
|
274
|
+
"ec50_se": round(perr[1], 3),
|
|
275
|
+
}
|
|
276
|
+
if sigmoid:
|
|
277
|
+
result["hill"] = round(popt[2], 3)
|
|
278
|
+
result["hill_se"] = round(perr[2], 3)
|
|
279
|
+
|
|
280
|
+
print(f"PD fit: Emax={result['emax']}, "
|
|
281
|
+
f"EC50={result['ec50']}"
|
|
282
|
+
+ (f", Hill={result['hill']}"
|
|
283
|
+
if sigmoid else ""))
|
|
284
|
+
return result
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## 5. 臨床薬理統合パイプライン
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
def clinical_pharmacology_pipeline(
|
|
291
|
+
pk_data, pd_data=None,
|
|
292
|
+
target_range=(10, 20),
|
|
293
|
+
output_dir="results"):
|
|
294
|
+
"""
|
|
295
|
+
臨床薬理学統合パイプライン。
|
|
296
|
+
|
|
297
|
+
Parameters:
|
|
298
|
+
pk_data: pd.DataFrame — PK 濃度データ
|
|
299
|
+
pd_data: pd.DataFrame | None — PD 効果データ
|
|
300
|
+
target_range: tuple — 目標トラフ範囲
|
|
301
|
+
output_dir: str — 出力ディレクトリ
|
|
302
|
+
"""
|
|
303
|
+
from pathlib import Path
|
|
304
|
+
out = Path(output_dir)
|
|
305
|
+
out.mkdir(parents=True, exist_ok=True)
|
|
306
|
+
|
|
307
|
+
# 1) PopPK 推定
|
|
308
|
+
pk_est = popk_estimation(pk_data)
|
|
309
|
+
|
|
310
|
+
# 2) TDM 最適化 (最新トラフがあれば)
|
|
311
|
+
latest = pk_data.sort_values("time").iloc[-1]
|
|
312
|
+
tdm = tdm_dose_optimization(
|
|
313
|
+
latest["dv"], latest["dose"],
|
|
314
|
+
target_range,
|
|
315
|
+
{"cl": pk_est["tv_cl"],
|
|
316
|
+
"v": pk_est["tv_v"]})
|
|
317
|
+
|
|
318
|
+
# 3) PD モデル (データがあれば)
|
|
319
|
+
pd_result = None
|
|
320
|
+
if pd_data is not None:
|
|
321
|
+
pd_result = fit_emax(
|
|
322
|
+
pd_data["concentration"],
|
|
323
|
+
pd_data["effect"],
|
|
324
|
+
sigmoid=True)
|
|
325
|
+
|
|
326
|
+
# 4) シミュレーション
|
|
327
|
+
sim = simulate_pk(
|
|
328
|
+
tdm["recommended_dose"],
|
|
329
|
+
params={"cl": pk_est["tv_cl"],
|
|
330
|
+
"v": pk_est["tv_v"]})
|
|
331
|
+
sim.to_csv(out / "pk_simulation.csv",
|
|
332
|
+
index=False)
|
|
333
|
+
|
|
334
|
+
print(f"Clinical PK pipeline → {out}")
|
|
335
|
+
return {
|
|
336
|
+
"popk": pk_est,
|
|
337
|
+
"tdm": tdm,
|
|
338
|
+
"pd": pd_result,
|
|
339
|
+
"simulation": sim,
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## パイプライン統合
|
|
346
|
+
|
|
347
|
+
```
|
|
348
|
+
admet-pharmacokinetics → clinical-pharmacology → pharmacogenomics
|
|
349
|
+
(ADMET 予測) (臨床 PK/PD) (遺伝薬理学)
|
|
350
|
+
│ │ ↓
|
|
351
|
+
drug-repurposing ────────────┘ clinical-decision-support
|
|
352
|
+
(薬剤リパーパシング) (臨床意思決定)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## パイプライン出力
|
|
356
|
+
|
|
357
|
+
| ファイル | 説明 | 次スキル |
|
|
358
|
+
|---------|------|---------|
|
|
359
|
+
| `pk_simulation.csv` | PK シミュレーション | → dose-response |
|
|
360
|
+
| `popk_estimates.json` | PopPK パラメータ | → pharmacogenomics |
|
|
361
|
+
| `tdm_recommendation.json` | TDM 推奨用量 | → clinical-decision |
|