信息速览
患者来源异种移植模型(PDX)是肿瘤药物研发里少数能在活体上验证疗效的资产。它的麻烦不在于稀有,而在于分散:一家机构的模型由一个实验室养着,另一家的模型由一个联合体保管,合同研究组织手里还压着一批。更麻烦的是命名——同一份肿瘤组织传代到两家机构,会长成两个名字;不同的两份肿瘤,可能恰好被起成同一个编号。当研究者想问「这个候选药在哪些 PDX 上测过」,问题会立即退化成一场跨机构的电话沟通。
CancerModels.org 就是针对这个退化设计的。它由 EMBL-EBI 与 Jackson Laboratory 联合建设,原名 PDX Finder,2019 年在《核酸研究》的数据库专刊上首次系统介绍。它的产品形态并不复杂:一个可检索的目录,给每个模型挂一个稳定的编号,再把这个编号和来源机构、供者描述、分子数据链接、给药响应归在一起。真正有分量的部分,是「归一化」这三个字背后的工作量——各机构提交的字段名、术语用法、模型命名习惯都不一致,要能跨机构检索,就得先把它们压到同一套属性上。
这一篇要回答的问题,是这套归一化做到了什么程度、在哪一段断了。库内模型数在 2026 年 10 月刚越过一万,这个数字对一个全球性目录来说不算大,原因要到 §2 和 §7 里找。一屏速览见下表。
| 维度 | 内容 |
|---|---|
| 官方名 | CancerModels.org,原 PDX Finder |
| 维护方 | EMBL-EBI 与 The Jackson Laboratory 联合 |
| 建站时间 | 原 PDX Finder 约 2016 年起建,2019 年见刊 |
| 首发论文 | Nucleic Acids Research 2019,doi:10.1093/nar/gky984,PMID 30535239 |
| 库内记录数 | 2026-10-26 查询,10348 条(BioStudies 接口 totalHits) |
| 模型类型 | 以 PDX 为主;按 Model type:PDX 过滤为 6856 条 |
| 标识形式 | BioStudies accession(S-CMO 加五位数字)+ Model ID 两套并存 |
| 标题形式 | [机构缩写] [模型类型] [模型名] 组织学,四段拼接 |
| 元数据存储 | EMBL-EBI BioStudies,集合名 CancerModelsOrg |
| 分子数据形态 | 只存链接,不镜像文件;可用性字段非二值 |
| 许可 | 逐条声明,多数 CC0,部分 EMBL-EBI 条款 |
| 取数方式 | 公共 REST 接口,无需注册、无需密钥 |
| 主要来源库 | PDMR、PDXNet、EurOPDX、JAX、BCM 等 |
| 最大短板 | 分子数据与给药响应的覆盖率低,别名合并依赖申报 |
§1 它要解决的具体麻烦
1.1 一门药的回溯问题,卡在一个名字上
设想一个最普通的临床前问题:某个团队拿到一株新合成的抑制剂,想先看看同类靶点的药物在哪些患者来源模型上做过体内验证,以便挑几个模型开始自己的实验。这个问题在文献里查不到,因为论文正文只写「我们用了三个乳腺癌 PDX」,不会写清这三个模型的来源与编号。查文献不成,就去查各机构的目录,于是撞上第一个障碍:每个机构给模型的命名规则都不一样,有的是字母加流水号,有的是癌种缩写加患者编号,有的是合同研究组织内部的商品编号。同一种肿瘤,在三个目录里就是三串互不相干的字符。
第二个障碍接踵而至。即便能查到三个目录里都有乳腺癌模型,也无法判断它们之间有没有重复——两家机构可能从同一家医院取到了同一份组织,各自传代、各自命名。对使用者来说,这两份是同一件事;对数据库来说,这是两条记录。没有一层归一的映射,任何关于「覆盖多少个独特患者」的统计都是错的。
第三个障碍最隐蔽:模型名对上了,描述没有对上。同样叫「乳腺癌 PDX」,一个机构记录的是原发灶取材,另一个记录的是肝转移灶取材;一个写的是初治患者,另一个写的是多线治疗后的复发患者。这些差别在后续的药效判断里是决定性的,但它们在原始目录里往往藏在自由文本里,或者干脆没记。
CancerModels.org 站在第三层,试图把上面三层一起处理:用一个稳定字段承接编号,用一个受控词表承接描述,再用一条链接承接数据。它不生产模型,也不养小鼠,它做的全部事情就是「把别人的描述压进同一套槽位」。理解这个定位很重要,因为它决定了这个库的能力上限——凡是来源方没提交的信息,它就没有。
1.2 三条常见的错误期待
把 CancerModels.org 当成「PDX 数据仓库」是最常见的误判。它更接近图书馆的联合目录:告诉你哪本书在哪个馆、索书号是什么,书本身还在原馆。分子数据、给药响应原始记录都在各自的来源库或论文补充材料里,这个目录给的是指针。
第二条错误期待是把它当成「别名解析服务」。直觉上,一个专门做归一化的库,应该能告诉你「文献里的 X 模型就是库里的 Y 记录」。实际上它给出的是一套提交格式与一个稳定 accession,别名是否被写进来,取决于提交方愿不愿意写。库内很多记录的 Model ID 就是机构自己的原始命名,没有额外的映射层。
第三条是把它当成「可以放心合并的训练集」。它的记录确实能批量导出,但导出的是元数据,不是特征矩阵。想做药物响应预测的人,拿到这批元数据后还要自己去各来源库抓分子数据和响应表,再处理跨库的标签不一致。这一段的工程量往往被严重低估。
1.3 它能给到的与给不到的
| 你的需求 | 它给的 | 够不够 |
|---|---|---|
| 按癌种找到一批可用模型 | 按 Histology、Cancer System、Primary Site 检索,返回记录列表 | 够,但需要人工核对取材部位与治疗史 |
| 判断两个模型是不是同一份肿瘤 | 一个 Model ID 字段与一个复合标题 | 不够,跨机构同模型合并依赖申报 |
| 拿到模型的分子数据 | Dataset Available 字段加外链 | 多数不够,字段非二值,且相当比例是 N/A |
| 拿到给药响应曲线 | 部分来源库的记录带响应数据链接 | 不够,方案与终点不统一 |
| 判断模型能否对外分发 | Available for distribution 字段加供应商表单链接 | 够,字段取值明确为 Yes/No |
| 引用某个模型 | BioStudies accession 可稳定引用 | 够,但学术惯例通常引原始论文 |
| 做跨库去重 | 没有公开的别名映射表 | 不够,需要自建映射 |
| 直接训练模型 | 仅元数据 | 远远不够,特征是外链的 |
这张表里有两个「够」、六个「不够」。这个比例值得先接受下来,再去谈它为什么仍然重要。它的价值不在于替你做完全部工作,而在于把「哪些模型存在、它们大致是什么」这一步从电话沟通变成了一次查询。
1.4 你的处境与它能帮到的事
| 你的处境 | 它能帮你什么 | 下一步该做什么 |
|---|---|---|
| 课题刚立项,要从零挑模型 | 按癌种、取材部位、宿主品系缩小候选范围 | 用 §5 的检索接口拉候选清单,再逐个开供应商表单 |
| 手上有十几个模型名,来路不明 | 用模型名反查记录,确认所属机构与组织学 | 把机构缩写一并带上再查,避免跨机构同名撞车 |
| 想复现某篇论文的体内实验 | 能查到模型是否在库内、来源机构是谁 | 直接联系记录里的联系人邮箱,或回到论文补充材料 |
| 要建一个药物响应的多机构训练集 | 提供跨机构的统一元数据骨架 | 先按 Dataset Available 与响应链接筛,再逐库下载特征 |
| 要评估模型库之间的重叠 | 提供各来源库的统一视图 | 自己做去重,联合主键用机构缩写加 Model ID |
| 要给一组模型补分子注释 | 提供模型到外部数据的指针 | 顺着外链去原始库取,注意原始库的许可 |
| 只想知道这个领域有多少模型 | 查询接口直接给计数 | 见 §2.4 的分布表,注意口径叠加问题 |
| 做监管材料里的模型清单 | 记录可稳定引用,字段可追溯 | 引用时写明 accession 与查询日期 |
这张表的左列全部是处境,不是特性。它的用意是:使用者通常不是从「我要一个 PDX 目录」出发的,而是从某个具体动作出发的。同一个库在八个处境里扮演八个不同角色,把角色分清楚,才不会在错的环节等一个不会到来的答案。
1.5 一句话判断
它把一个散落的领域拉进了同一张表,但只拉进了「存在性」这一列;「可比性」那一列还空着。
1.6 不适合谁:四条边界
不适合把元数据当特征用的人。库内主体是描述性字段:组织学、取材部位、宿主品系、传代情况。这些字段能用来分层、能用来做协变量,但不能直接喂进预测模型。分子层面的特征要顺着外链去原始库取,且各库的预处理流程完全不同。
不适合需要完整别名映射表的人。如果你手上有一批来自文献的模型名,指望一次查询全部对上,结果会让人失望。库内只对提交方愿意申报的别名做归一,未申报的一律查不到。这类需求更现实的路径是去找具体联合体自己的映射表,比如 PDXNet 内部的数据协调文档。
不适合把它当临床前结论依据的人。所有模型都是免疫缺陷小鼠上的异种移植,缺少完整的免疫微环境,人源基质在传代中会逐渐被小鼠基质替代。任何在 PDX 上得到的疗效结论,都不能跳过这一步直接写成临床建议。
不适合只想要大样本量的人。一万余条听起来不少,但扣掉无分子数据的、无响应数据的、重复登记的,能进入建模的规模会小一个量级。如果你的设计需要数万级别的配对样本,这个库给不了,该去找单细胞图谱或大规模细胞系筛选。
§2 数据构成与规格
2.1 每一条记录长什么样
库的关键设计在于它有两套标识同时在用。外层是 BioStudies 的 accession,形如 S-CMO 加五位数字,这是存储层的容器编号,任何一条记录被提交进 EMBL-EBI 的 BioStudies 系统时都会得到。内层是 Model ID,这是模型本体的名字,通常就是来源机构自己的命名。两套并存带来一个直接后果:同一模型若被两家机构各提交一次,会得到两个 accession,却可能带着同一个 Model ID。反过来说,两条记录 Model ID 相同,也不能推出它们是同一模型,因为编号只有机构内部唯一。
标题是第三层信息,也是人眼最先看到的东西。库里把标题拼成固定四段:方括号里是机构缩写,第二个方括号是模型类型,第三个方括号是模型名,最后一段是组织学。这种拼法的好处是一眼能看出归属,坏处是模型名里若含空格或斜杠,掐取会出错。做正则解析时必须按方括号边界切,不能按空格切。
记录的结构分两层:一层是平铺的属性,一层是可选的子节。子节包括 Organization、Patient / Tumour Metadata,以及可选的 Immune markers、Related models、Molecular data。前两个子节在大多数记录里存在,后三个不是每条都有。这一点是理解覆盖率的关键——分子数据不是主表的一个字段,而是一个可能缺席的子节。
2.2 字段/记录的完整字典
| 字段名 | 所在层 | 取值形态 | 典型值 | 用途 | 缺失情况 |
|---|---|---|---|---|---|
| accession | 容器 | S-CMO 加五位数字 | S-CMO10361 | 稳定引用 | 不会缺 |
| Title | 平铺 | 四段方括号拼接 | [AHS] [PDX] [PDX_AML-979] Acute Myeloid Leukemia | 人工浏览、正则解析 | 不会缺 |
| Model ID | 平铺 | 自由文本 | PDX_AML-979 | 模型本体名 | 不会缺 |
| Model type | 平铺 | 受控短词 | PDX | 类型过滤 | 多为 PDX |
| Histology | 平铺 | 受控词表 | Acute Myeloid Leukemia | 按病种检索 | 少数 Not Provided |
| Cancer System | 子节 | 受控词表 | Unclassified / Breast Cancer / Thoracic Cancer | 按系统检索 | 部分为 Unclassified |
| Primary Site | 子节 | 半受控 | bone marrow / breast | 区分原发部位 | 常见 Not Provided |
| Collection Site | 子节 | 半受控 | bone marrow / lung | 区分取材部位 | 常见 Not Provided |
| Tumour Type | 子节 | 受控短词 | Primary / Recurrent | 区分初治与复发 | 部分缺失 |
| Cancer Stage | 子节 | 混合格式 | Intermediate / Stage IB / T1N0M0 | 分期 | 格式混杂 |
| Cancer Grade | 子节 | 受控短词 | Not Provided | 分级 | 缺失率高 |
| Patient Sex | 子节 | female / male | female | 供者性别 | 少量缺失 |
| Patient Age | 子节 | 十岁区间 | 50 - 59 / 0 - 23 months | 供者年龄 | 少数缺失 |
| Patient Ethnicity | 子节 | 受控词表 | European | 族裔 | 常见 Not Provided |
| Host Strain Name | 平铺 | 受控短词 | nod scid gamma | 宿主品系 | 部分缺失 |
| Host Strain Nomenclature | 平铺 | 标准命名 | NOD.Cg-Prkdcscid Il2rgtm1Wjl/SzJ | 精确品系 | 部分缺失 |
| Engraftment Site | 平铺 | 受控短词 | Bone Marrow | 移植部位 | 部分缺失 |
| Type | 平铺 | 受控短词 | Orthotopic | 原位或皮下 | 部分缺失 |
| Passage | 平铺 | 混合格式 | All / all | 传代数 | 取值不统一 |
| Dataset Available | 平铺 | 非二值自由描述 | N/A / immune markers | 判断有无分子数据 | 大量为 N/A |
| Available for distribution | 平铺 | Yes / No | Yes | 能否获取模型 | 取值明确 |
| Supplier type | 平铺 | 受控短词 | Academic | 学术或商业 | 取值明确 |
| License | 平铺 | 受控短词 | CC0 / EMBL-EBI | 许可 | 逐条不同 |
| Provider URL | 平铺 | URL 或 Not Provided | compendium.criver.com 链接 | 跳回来源库 | 常见 Not Provided |
| Contact Names | 平铺 | 人名 | Binje Vick | 联系提交人 | 部分缺失 |
| Contact Emails | 平铺 | 邮箱 | 机构邮箱 | 直接联系 | 部分缺失 |
| Paediatric | 平铺 | Yes / No | No | 儿科模型筛选 | 取值明确 |
| Has Related Models | 平铺 | Yes / No | Yes | 是否存在关联模型 | 取值明确 |
这张字典里最值得盯着看的是 Dataset Available 这一行。它的取值形态写着「非二值自由描述」,实际取值里既有 N/A,也有 Yes 这样的肯定,还有 immune markers 这种只说明某一类数据存在的描述。用等值匹配过滤会漏掉一部分,用非空过滤又会把 N/A 当成有数据。正确做法是先枚举这个字段的全部取值再决定规则,而这一步没有现成文档,只能自己扫。
2.3 一条记录的完整解剖
下面这条记录来自德国一个血液学实验室,是库内结构最典型的一种:模型是急性髓系白血病,没有分子数据,不可对外分发。把它拆开看,能看清字段的组织方式。
{
"accno": "S-CMO10361",
"type": "study",
"attributes": [
{"name": "Title", "value": "[AHS] [PDX] [PDX_AML-979] Acute Myeloid Leukemia"},
{"name": "ReleaseDate", "value": "2025-12-09"},
{"name": "AttachTo", "value": "CancerModelsOrg"}
],
"section": {
"attributes": [
{"name": "Model ID", "value": "PDX_AML-979"},
{"name": "Model type", "value": "PDX"},
{"name": "Histology", "value": "Acute Myeloid Leukemia"},
{"name": "Dataset Available", "value": "N/A"},
{"name": "Available for distribution", "value": "No"},
{"name": "Supplier type", "value": "Academic"},
{"name": "License", "value": "CC0"},
{"name": "Paediatric", "value": "No"}
],
"subsections": [
{"type": "Organization", "attributes": [{"name": "Name", "value": "Research Unit Apoptosis in Hematopoietic Stem Cells (AHS)"}]},
{"type": "Patient / Tumour Metadata", "attributes": [
{"name": "Patient Sex", "value": "female"},
{"name": "Patient Age", "value": "50 - 59"},
{"name": "Cancer System", "value": "Unclassified"},
{"name": "Primary Site", "value": "bone marrow"},
{"name": "Collection Site", "value": "bone marrow"}
]}
]
}
}
#-- 读这条记录时,要看的是四件事
#-- 1 归属:Title 第一段的 AHS 是机构缩写,Model ID 是机构内部命名
#-- 2 可用性:Dataset Available 为 N/A,说明这条记录不带分子数据
#-- 3 可获得性:Available for distribution 为 No,模型拿不到,只能读描述
#-- 4 粗粒度:Cancer System 是 Unclassified,只能靠 Histology 与 Primary Site 判病种
这四点合起来说明一件事:一条在库内检索得到的记录,未必是一条能用的记录。可检索、可获取、有数据是三件独立的事,字段里各有各的位置。很多使用者第一次查询时会默认三者一致,然后在实验设计阶段才发现拿不到模型,或者拿到了却没有测序数据。
再对照一条有数据的记录。下面这条来自美国国家癌症研究所的患者来源模型库,模型是肺腺癌,有免疫标志物数据、可分发、有关联模型。
{
"accno": "S-CMO5794",
"section": {
"attributes": [
{"name": "Model ID", "value": "LG0567-F671"},
{"name": "Model type", "value": "PDX"},
{"name": "Histology", "value": "Lung Adenocarcinoma"},
{"name": "Dataset Available", "value": "immune markers"},
{"name": "Available for distribution", "value": "Yes"},
{"name": "Has Related Models", "value": "Yes"},
{"name": "License", "value": "EMBL-EBI"}
],
"subsections": [
{"type": "Organization", "attributes": [{"name": "Name", "value": "Patient-Derived Model Repository (PDMR)"}]},
{"type": "Patient / Tumour Metadata", "attributes": [
{"name": "Patient Sex", "value": "male"},
{"name": "Patient Age", "value": "50 - 59"},
{"name": "Cancer System", "value": "Thoracic Cancer"},
{"name": "Cancer Stage", "value": "Stage IB"},
{"name": "Primary Site", "value": "respiratory/thoracic"}
]},
{"type": "Immune markers"},
{"type": "Related models"}
]
}
}
#-- 两条记录并列看,能看出库的设计取舍
#-- 同一条记录里,Dataset Available 的取值可以是 N/A、Yes 或 immune markers
#-- 这意味着「有分子数据」这件事不是布尔量,而是一个自由描述的槽位
#-- 做筛选时,正确做法是先统计该字段的全部取值,再决定匹配规则
import json
import urllib.request
def fetch(acc):
url = f"https://www.ebi.ac.uk/biostudies/api/v1/studies/{acc}"
with urllib.request.urlopen(url, timeout=30) as r:
return json.load(r)
def flat(sec, out=None):
if out is None:
out = {}
if isinstance(sec, list):
for x in sec:
flat(x, out)
return out
for a in sec.get("attributes") or []:
out.setdefault(a["name"], []).append(a.get("value"))
subs = sec.get("subsections") or []
if isinstance(subs, dict):
subs = [subs]
for s in subs:
flat(s, out)
return out
for acc in ("S-CMO10361", "S-CMO5794"):
d = flat(fetch(acc)["section"])
print(acc, "|", d["Model ID"], "|", d.get("Dataset Available"), "|",
d.get("Available for distribution"), "|", d.get("License"))
这段代码读出的两行输出,恰好对应库内两种记录形态。第一种没有数据、不能分发,第二种有部分数据、可以分发。它们在同一套字段下并排存在,检索接口不会自动区分。用接口取回一百条记录,不做这一步拆分就去做统计,得到的「有分子数据的模型数」一定是错的。
2.4 分布表:规模、癌种与数据可用性
先说规模。2026 年 10 月 26 日通过 BioStudies 的 CancerModelsOrg 集合检索接口查询,返回 totalHits 为 10348,接口同时声明这个总数是精确的。这个数字包含集合内全部记录,不区分模型类型。
再说类型。用 Model type 字段过滤 PDX,得到 6856 条。这里有一个先前没料到的现象:把过滤条件换成 PDOX 同样写法,返回的计数完全相同。合理的解释是检索层对这两个写法做了同义展开,而不是两种类型恰好等量。这个细节提醒一件事——计数结果对写法敏感,换一种写法可能得到完全不同的数,做统计时要把查询字符串一起记录下来。
癌种分布方面,只按组织学关键词做了四个高频癌种的计数,结果如下表。这只是四个点,不是完整分布,完整的分布需要逐个组织学术语去查,超出了本次查询的范围。
| 过滤条件 | 返回计数 | 与 PDX 总数的关系 | 备注 |
|---|---|---|---|
| 集合全部记录 | 10348 | 基线 | 含全部类型 |
| Model type:PDX | 6856 | 占基线的六成七 | 主体 |
| Model type:PDOX | 6856 | 与上一行相同 | 疑为同义展开 |
| 组织学含 Colorectal | 1026 | 占 PDX 的一成五 | 最高 |
| 组织学含 Lung | 934 | 占 PDX 的一成四 | 次高 |
| 组织学含 Pancreatic | 590 | 占 PDX 的百分之九 | 第三 |
| 组织学含 Breast | 551 | 占 PDX 的百分之八 | 第四 |
| Dataset Available:Yes | 13 | 占基线的千分之一 | 口径明显偏窄 |
最后一行需要解释。按 Dataset Available 等于 Yes 精确过滤,只得到 13 条。这与「库内很多记录有分子数据」的印象冲突。冲突的原因在 2.2 的字典里已经埋下——这个字段的取值不统一,很多有数据的记录填的是别的描述,比如上一条剖析里看到的 immune markers。所以 13 这个数不能读成「只有 13 个模型有分子数据」,只能读成「恰好把该字段填成 Yes 的只有 13 条」。这个例子是全文最该记住的一条方法论:字段名看起来是在回答一个问题,实际回答的可能是另一个问题。
| 数据可用性写法 | 含义 | 能否直接当布尔量用 |
|---|---|---|
| N/A | 未提供,或无数据 | 否,需与缺失区分 |
| Yes | 有数据 | 是,但漏检 |
| immune markers | 仅某类数据存在 | 否,需归一 |
| 空子节(只有类型名) | 声明了类别但内容为空 | 否 |
2.5 与同类资源的字段差异
PDX 领域的资源不止这一家。理解它的位置,要把它和三类东西并排看:单个大型模型库、细胞系筛选平台、临床基因组注册库。
| 资源 | 主体对象 | 标识方式 | 分子数据 | 与 CancerModels.org 的关系 |
|---|---|---|---|---|
| CancerModels.org | 跨机构 PDX 目录 | BioStudies accession 加 Model ID | 只存链接 | 目录层 |
| PDMR(美国 NCI) | 自有 PDX 库 | 库内标本序号 | 自有平台产出 | 上游来源之一 |
| EurOPDX | 欧洲联合体 PDX 库 | 成员机构各自命名 | 联合体统一测序 | 上游来源之一 |
| PDXNet | 美国联合体 | 成员机构各自命名 | 联合体统一测序 | 上游来源之一 |
| 细胞系筛选平台 | 商品化细胞系 | 细胞系标准名 | 表达与药敏矩阵 | 平行路线,非替代 |
| 临床基因组注册库 | 患者肿瘤测序 | 样本编号 | 测序与临床变量 | 患者端,非模型端 |
这张表说明它做的是横向整合,不是纵向深挖。单个来源库在自家数据上的完整性远高于目录,因为目录只能收录对方愿意提交的字段。真正要取特征矩阵的人,最终一定会回到上游库,目录的作用是告诉他该去哪一家、找哪个编号。
§3 它的身份层:一个模型怎样被认出
3.1 编号的三重身份
在 CancerModels.org 里,「编号」这个词至少指三样东西,混用会直接导致错误。第一重是存储容器的 accession,S-CMO 开头,由 EMBL-EBI 在接收提交时分配,与模型本身无关,只与提交动作有关。第二重是 Model ID,模型的业务主键,来自产生机构,反映的是机构的命名习惯。第三重是标题里的模型名段,也就是第三个方括号里的那串字符,它在多数记录里与 Model ID 相同,但不是全部。
把这三重关系理清之后,跨库连接的规则就自然浮现:accession 只用于引用单条记录,Model ID 只用于机构内部定位,要做跨机构的模型身份判断,必须把机构缩写与 Model ID 组合起来。机构缩写来自标题第一段,或来自 Organization 子节的 Name。两者并不总是能对上,因为标题里的缩写有时是项目代号而非机构名。
| 身份层 | 来源 | 唯一性范围 | 适用场景 | 误用后果 |
|---|---|---|---|---|
| accession | EMBL-EBI 分配 | 全局唯一 | 引用单条记录 | 无 |
| Model ID | 产生机构 | 机构内唯一 | 机构内定位模型 | 跨机构同名撞车 |
| 标题模型名段 | 提交方填写 | 无保证 | 人工浏览 | 正则掐取出错 |
| 机构缩写 | 提交方填写 | 项目级 | 与 Model ID 组合 | 与机构全名不一致 |
第三行是最容易出事的地方。标题是人读的,格式由提交方决定,而提交方并不总是严格按四段拼。有的记录里模型名段带了空格,有的在组织学段里又出现方括号,有的干脆只有三段。写解析代码时若假定格式绝对规整,遇到几百条之后必然崩溃。
3.2 归一化在哪个环节发生
归一化这个词在这套系统里具体发生在三处,每一处的程度不同。
第一处是字段名归一。各来源机构提交时的字段名五花八门,进入 BioStudies 之前会被映射到一套统一的属性名。这一处做得最彻底,因为它纯粹是技术性的,不涉及内容判断。副作用是原始字段名被丢弃,一旦映射有偏差,无法回溯。
第二处是术语归一。组织学、癌种、取材部位都往受控词表上靠。这一处做了但不满。比如 Cancer System 字段里会出现 Unclassified,说明映射目标本身允许「说不清」这个取值;Cancer Stage 更是三种格式混用,既有 Intermediate 这样的分级词,也有 Stage IB 这样的分期串,还有 T1N0M0 这样的 TNM 组合。
第三处是模型身份归一,也就是把不同机构对同一模型的不同叫法合并。这一处做得最少。库里没有公开的别名映射资源,同一模型的跨机构合并靠提交方主动申报关联。Has Related Models 字段存在,说明系统承认关联模型这个概念,但它记录的是「有没有关联」,不是「关联到哪一条」。
| 归一化环节 | 做得如何 | 判断依据 | 残余风险 |
|---|---|---|---|
| 字段名 | 彻底 | 所有记录共用同一套属性名 | 原始名不可回溯 |
| 组织学 | 较彻底 | 检索可跨机构命中同一术语 | 边缘病种可能落空 |
| 癌种系统 | 不彻底 | 存在 Unclassified 取值 | 按系统统计会漏 |
| 分期 | 不彻底 | 三种格式并存 | 无法直接排序 |
| 模型身份 | 最少 | 无公开映射表 | 跨机构去重需自建 |
| 分子数据指向 | 部分 | 只存链接,字段非二值 | 覆盖率统计易错 |
3.3 它凭什么值得信任
一个只做索引的库,可信度取决于两件事:来源是否可追溯,映射是否可复核。CancerModels.org 在两件事上的处理是:来源可追溯到具体机构与联系人邮箱,这部分做得好,几乎每条记录都有 Organization 子节;映射不可复核,因为映射规则与原始提交内容都不公开。
这个组合带来一个实际后果:当你在库里看到某条记录的 Histology 是某个具体亚型时,你无法判断这是提交方原文如此,还是映射环节做的判断。前者可以引用,后者需要谨慎。想确认,只能顺着 Provider URL 或联系人去找来源方核对。这也是为什么记录里的 Contact Emails 字段值得重视——它是这套系统里唯一一条能穿出目录、回到原始事实的通道。
§4 它的质量层:可用性比完整性更值得看
4.1 完整并不等于可用
评估一个目录类资源,容易掉进一个陷阱:看记录数、看字段数,然后给出「覆盖全面」的结论。CancerModels.org 的字段确实多,一条记录摊开有近三十个属性。但这些属性的填充质量差异极大,把填充率平均一下会得到一个毫无意义的中位数。
正确的看法是分三档。第一档是结构性字段,几乎必然存在:Title、Model ID、Model type、Histology、License、Available for distribution。第二档是描述性字段,多数存在但有缺失:Patient Sex、Patient Age、Primary Site、Collection Site。第三档是可选的子节,存在与否决定这条记录能不能用于下游:Molecular data、Immune markers、Related models。
| 档位 | 字段举例 | 存在比例 | 缺失后果 |
|---|---|---|---|
| 结构性 | Title、Model ID、License | 接近全部 | 记录不可用 |
| 描述性 | 性别、年龄段、原发部位 | 多数 | 分层能力下降 |
| 可选子节 | 分子数据、免疫标志物 | 少数 | 无法建模 |
第三档是决定性的。一条记录即使结构化程度很高,只要没有分子数据,它就只能用于「这个模型存在」这一类判断,不能进入任何以分子特征为输入的流程。而第三档的判定又恰恰最难,因为前面已经说过,Dataset Available 字段的取值不统一。
4.2 案例:一条肺腺癌模型的三次核对
这个案例取自库内一条真实记录,编号 LG0567-F671,来自美国国家癌症研究所的患者来源模型库。选它是因为它的字段填充度在库内属于较好的一档,恰好可以看清「好」到什么程度。
第一次核对是身份。标题三段拼成 [PDMR] [PDX] [LG0567-F671] Lung Adenocarcinoma。机构缩写 PDMR 与 Organization 子节里的 Patient-Derived Model Repository 对得上,说明这条记录的归属没有歧义。Model ID 与标题模型名段一致,没有额外的别名层。也就是说,如果另一篇论文里出现 LG0567-F671 这个名字,它指的就是这条记录——前提是那篇论文确实用了 PDMR 的模型。
第二次核对是可得性。Available for distribution 为 Yes,Supplier type 未填但 Organization 表明是学术机构,Provider URL 指向 NCI 的标本查询页面。这三点合起来说明模型可以申请,路径清楚。这一步在 §4.2 的案例里是最顺利的一环,因为 PDMR 作为国家级资源,对外分发的政策本身比较明确。
第三次核对是数据。Dataset Available 填的是 immune markers,说明这条记录关联了免疫标志物数据,但并不意味着有全外显子或转录组。子节里确实有一个 Immune markers 空节,内容为空的子节说明类别被声明了,具体项要回来源库取。Has Related Models 为 Yes,说明这个患者来源可能对应多个模型,但库内没有列出关联到哪几条。
三次核对做完,这条记录的可用边界就清楚了:能拿到模型,能拿到一部分免疫标志物数据,拿不到完整的分子谱,也无法在库内直接找到它的姊妹模型。这个结论不是「好」或「不好」,而是一组具体的能与不能。§4.2 的案例之所以值得反复回看,就因为它把「一条记录能支撑什么研究」拆成了可枚举的判断项,而不是一个笼统的评分。
4.3 覆盖率为什么低
分子数据覆盖率低,原因不在目录方,而在提交方。PDX 的分子表征成本很高:一个模型要做全外显子、RNA 测序、有时还要做拷贝数,单模型成本在数千美元量级,而模型本身往往由学术实验室以低成本维持。大多数实验室承担不起给每个模型都做全套表征,于是形成一种常态——先建模型、先做药效,分子数据等有经费了再补,或者永远不补。
联合体模式的资源情况好一些。PDMR、EurOPDX、PDXNet 这类大型项目有统一表征的预算,模型进库时通常带着一套分子数据。目录里分子数据覆盖率的不均衡,本质上是来源机构经费结构的不均衡在数据上的投影。这一点决定了任何试图提高覆盖率的努力,都不能只靠目录方去催提交,而要落到上游的资助安排上。
4.4 给药响应的三种记录方式
给药响应在这套系统里有三种存在形式,各自的可用性完全不同。
第一种是记录里带响应数据的链接,指向来源库的响应表。这种最好用,因为能追到原始数值,但数量少。第二种是记录里只写有响应数据,链接指向论文或项目主页,需要人工去找补充材料。第三种是没有任何响应相关字段,模型的药效信息只存在于某篇论文的图里,库内查不到。
| 响应记录形式 | 可取性 | 数据形态 | 典型来源 |
|---|---|---|---|
| 记录内带响应链接 | 直接 | 表格数值 | 大型联合体 |
| 只说明有响应数据 | 间接 | 需去论文找 | 学术实验室 |
| 无响应字段 | 无 | 不可得 | 多数小机构 |
这三种形式在检索接口上看不出区别,因为响应数据不在主表字段里。要判断一条记录有没有响应数据,只能打开记录看子节,这一步无法批量。这是这个库在「能不能用来做响应建模」这个问题上最实质的障碍——不是没数据,而是数据的存在性判断本身需要逐条人工。
§5 取数层:接口、查询与导出
5.1 入口在哪
官方站点的域名指向 EMBLEBI 的 BioStudies 系统,浏览界面是前端渲染的,直接抓 HTML 拿到的是空壳。可用的入口是 BioStudies 的公共 REST 接口,路径形如 biostudies 的 api/v1 前缀加集合名。这个集合名是 CancerModelsOrg,注意大小写与拼接方式,写成带点的形式会 404。
接口不需要注册、不需要密钥、没有速率文档。它是 EMBL-EBI 公共基础设施的一部分,稳定性随主站。检索用 search 端点,单条记录用 studies 端点加 accession。两个端点都返回 JSON。
5.2 检索接口的基本用法
检索接口支持一个 query 参数,语法是字段名加冒号加值,多个条件用 AND 连接。不做任何过滤时返回集合内全部记录。返回体里有两个计数字段,totalHits 是命中数,isTotalHitsExact 标明这个数是否精确。做统计时应当以 isTotalHitsExact 为真为前提。
#-- 集合总数
curl -s "https://www.ebi.ac.uk/biostudies/api/v1/CancerModelsOrg/search?pageSize=1" \
| python3 -c "import json,sys; d=json.load(sys.stdin); print(d['totalHits'], d['isTotalHitsExact'])"
#-- 按模型类型过滤,比较 PDX 与 PDOX 两种写法
for t in PDX PDOX; do
curl -s "https://www.ebi.ac.uk/biostudies/api/v1/CancerModelsOrg/search?query=Model%20type:${t}&pageSize=1" \
| python3 -c "import json,sys; d=json.load(sys.stdin); print('${t}', d['totalHits'])"
done
#-- 按癌种关键词加类型过滤
for k in Colorectal Lung Pancreatic Breast; do
curl -s "https://www.ebi.ac.uk/biostudies/api/v1/CancerModelsOrg/search?query=%22${k}%22%20AND%20Model%20type:PDX&pageSize=1" \
| python3 -c "import json,sys; d=json.load(sys.stdin); print('${k}', d['totalHits'])"
done
三段脚本读出的就是 §2.4 那张分布表的全部数字。注意第三段里关键词加了引号,不加引号时检索会退化为分词匹配,命中数会明显偏大。这个差别很容易被忽略,然后在两份报告里出现两个对不上的数字。
5.3 分页取回记录
需要拿全量元数据时,用分页拉取。接口返回 hits 数组,每个元素带 accession、title、release_date 等摘要字段,不含完整属性。要拿完整属性得对每条再请求一次 studies 端点,这意味着一万条记录要一万次请求。分批做、加间隔、失败重试是必须的。
#-- 分页拉取摘要列表,再按 accession 逐条取完整记录
import json
import time
import urllib.request
BASE = "https://www.ebi.ac.uk/biostudies/api/v1"
def search(page, size=100, query=None):
url = f"{BASE}/CancerModelsOrg/search?page={page}&pageSize={size}"
if query:
url += "&query=" + urllib.parse.quote(query)
with urllib.request.urlopen(url, timeout=60) as r:
return json.load(r)
def record(acc):
with urllib.request.urlopen(f"{BASE}/studies/{acc}", timeout=60) as r:
return json.load(r)
import urllib.parse
first = search(1)
total = first["totalHits"]
pages = (total + 99) // 100
accs = []
for p in range(1, pages + 1):
for h in search(p)["hits"]:
accs.append(h["accession"])
time.sleep(0.3)
print("摘要条数", len(accs), "声明总数", total)
full = []
for i, a in enumerate(accs):
full.append(record(a))
if i % 500 == 499:
time.sleep(2)
with open("cancermodels_full.json", "w", encoding="utf-8") as f:
json.dump(full, f, ensure_ascii=False)
print("完整记录", len(full))
这段代码有一个容易被忽略的地方:分页时集合可能在增长,翻页过程中新提交的记录会打乱偏移。稳妥做法是先按 release_date 倒序取第一页,记下时间戳,后续只增量取更新的部分。若要一次性做快照,最好在同一分钟内跑完,并记录查询时刻。
5.4 从记录里抽出可用性信号
拿到完整记录后,第一件要做的事不是统计,而是把 Dataset Available 的取值枚举出来。这个字段的自由度决定了后续所有筛选规则的有效性。
#-- 枚举 Dataset Available 的全部取值,再决定筛选规则
import json
from collections import Counter
docs = json.load(open("cancermodels_full.json", encoding="utf-8"))
def flat(sec, out=None):
if out is None:
out = {}
if isinstance(sec, list):
for x in sec:
flat(x, out)
return out
for a in sec.get("attributes") or []:
out.setdefault(a.get("name"), []).append(a.get("value"))
subs = sec.get("subsections") or []
if isinstance(subs, dict):
subs = [subs]
for s in subs:
flat(s, out)
return out
g = [flat(d["section"]) for d in docs]
cnt = Counter((v[0] if v else None) for v in (x.get("Dataset Available") for x in g))
for k, n in cnt.most_common(15):
print(repr(k), n)
这一步的输出会决定两件事:哪些取值算「有数据」,哪些算「无数据」。以库内常见形态推演,取值大致会落在三个区间:明确的否定(N/A、Not Provided、空)、明确的肯定(Yes)、以及描述性的部分肯定(immune markers 之类)。三个区间之外的零星取值需要人工判读,判读结果要写成规则并留档,否则下次重跑会得到另一套标准。
5.5 按病种与取材部位组合筛选
单靠组织学术语筛选,会把原发灶与转移灶混在一起。要区分,得再加 Primary Site 与 Collection Site 两个条件。这两个字段的取值是半受控的,同一个器官存在多种写法,检索时需要用 OR 把变体连起来。
Primary Site:(breast OR "breast cancer" OR mammary) AND Collection Site:liver
这行的意思是找原发于乳腺、取材于肝的模型,通常对应肝转移。库内这类组合查询是否支持括号与 OR,取决于后端检索语法,实际使用时先用小样本验证命中是否合理,再放开全量。这一步没有捷径,因为检索语法的文档不在官方站点上,只能从 BioStudies 的通用文档里推。
5.6 导出的三种形态
导出没有专门的按钮,只有三种自建路径。
第一种是接口拉全量 JSON,适合需要全部字段的人,代价是请求次数多。第二种是浏览器端导出检索结果,适合只需要摘要列表的人,几千条以内可以接受。第三种是顺着 Provider URL 回来源库下载,适合只需要某一批模型的人,数据最全但最不统一。
| 导出方式 | 适合规模 | 字段完整度 | 主要代价 |
|---|---|---|---|
| 接口全量 JSON | 全库 | 全部属性 | 请求次数等于记录数 |
| 检索结果导出 | 千条以内 | 摘要字段 | 无完整属性 |
| 回来源库下载 | 单批模型 | 最全 | 需逐个申请 |
| 第三方镜像 | 不确定 | 不确定 | 时效与许可风险 |
§6 与库内词条的关系
6.1 关系图谱
这个库在千方医数集的词条网络里,处在「临床前模型」这一侧,与「患者端数据」和「细胞系端数据」并列。三者的关系不是替代,而是同一研究链条上的不同环节。
| 库内词条 | 关系 | 差异点 |
|---|---|---|
| AACR GENIE | 患者端对照 | 记录的是患者肿瘤测序,没有模型 |
| CancerLinQ | 患者端对照 | 记录真实世界诊疗,无实验模型 |
| CZ CELLxGENE Census | 表征方法参照 | 转录组数据的标准化方式可借鉴 |
| Cellosaurus 类细胞系资源 | 平行路线 | 细胞系不可替代体内模型 |
| CancerModels.org | 本体 | 模型端目录 |
把它放在这张图里,能看清一个常被混淆的边界:GENIE 与 CancerLinQ 记录的是人,CancerModels 记录的是小鼠身上的肿瘤。同一个患者可能同时出现在患者端注册库与模型端目录里,但两边没有任何连接字段。想在两边做连接,只能靠机构、癌种、年龄段的模糊匹配,这一步的可靠性很低。
6.2 检索路径
从站内进到这篇词条,通常有三条路。一条是从「肿瘤模型」这个主题词出发,经分类页到达。一条是从同癌种的患者端词条出发,在对比表里跳转。一条是从单细胞图谱词条出发,在「如何验证细胞层面的发现」这个话题下跳转。
三条路的读者动机不同。第一条是想找模型的人,需要的是筛选路径,也就是 §1.4 那张处境表。第二条是已经做过患者数据分析、想找体内验证的人,需要的是模型的可获取性信息。第三条是想把体外发现推到体内的人,需要的是模型与细胞系的差别说明。同一个词条要同时服务这三种动机,靠的是把「能做什么」写清楚,而不是把「有什么字段」罗列完整。
§7 质量评估与局限性
7.0 阅读本节前的一个前置校正
在给分之前,得先纠正一个坐标系错误。评估这种目录类资源时,最自然的做法是拿它和成熟的数据库比字段完整度、比更新频率、比文档质量,然后得出「它不如某某库」的结论。这个比法的前提是两者在做同一件事,而实际上它们做的是两件不同的事:成熟数据库通常同时管数据和索引,这个库只管索引。
坐标系一摆正,很多看似是缺陷的东西会变成设计选择。分子数据只存链接,不是因为懒,而是因为原始数据的所有权在各来源机构手里,镜像下来会带来许可与维护的双重负担。别名映射不公开,不是因为藏,而是因为映射本身依赖提交方申报,公开一份不完整的映射表比不公开更容易造成误判。
但这套校正不能走得太远,不能把「只管索引」当成一块免罪金牌。索引类资源同样有它的下限:索引必须准,指向必须活,计数口径必须自洽。这三条它做到了第一条的一半、第二条的大半、第三条的小半。所以下面这一节,评分标准是「作为一个索引它做得怎样」,而不是「作为一个数据库它做得怎样」。带着这个前置认识再往下看五维评分,才不会把结构性的取舍当成个体的失误。
7.1 DAIMS 五维评分
下面这张表用的是 DAIMS 框架,即数据可获取性、可互操作、元数据质量与可持续性这一组常被引用的评估维度,再补一维可发现性。五个维度各自 1 到 10 分,评分依据必须能在库内找到对应字段或接口行为,不能凭印象给分。
| 维度 | 评分(1–10) | 依据 | 扣分原因 |
|---|---|---|---|
| 可发现性 | 8 | 官方站点与 BioStudies 双重入口,论文有正式引用 | 站点前端为渲染式,直接抓取无效 |
| 可获取性 | 9 | 无需注册、无需密钥、接口稳定 | 无官方批量导出,需自建脚本 |
| 可互操作 | 7 | 字段名统一、组织学受控、用 BioStudies 标准容器 | 无公开别名映射,跨库连接困难 |
| 元数据质量 | 6 | 结构性字段齐备,供者描述粒度合理 | 可选子节缺失严重,取值不统一 |
| 可持续性 | 8 | 两家国家级机构联合、纳入 EMBL-EBI 长期基础设施 | 原域名已重定向,历史链接需维护 |
| 综合 | 7.6 | 索引层做得扎实,数据层依赖于上游 | 见右列 |
这个分数要结合 7.0 读。它在索引层的表现接近上限,在数据层的表现受制于上游,两者平均下来得到 7.6。如果有人拿它去做「分子数据覆盖率」的评估,会得到一个远低于 7.6 的结论,那是因为问的问题不在它擅长的层。
7.2 三个结构性短板
第一是别名归一不彻底。这是本文开头就点明的主轴,也是它最核心的功能承诺里最没兑现的一块。库内确实有 Model ID,确实有统一标题,但这两样都不构成跨机构的别名映射。同一模型在不同机构各有一条记录,系统不会自动合并。Has Related Models 字段只有是/否,没有指向。
第二是数据可用性判断无法批量化。Dataset Available 字段的取值自由度,使得任何自动化筛选都要附带一个人工判读环节。这在规模上万条时不算致命,但它决定了一件事:这个库不适合做需要反复重算的自动化 pipeline,适合做一次性的候选集构建。
第三是计数口径不自洽。集合总数、类型过滤、可用性过滤三个数之间的关系,官方没有给出说明文档。按 PDX 过滤得到约占六成七,剩下三成三是什么,要么是其他模型类型,要么是类型字段未填,官方页面未说明。这个空白本身不算错,但它意味着任何引用这个库规模数字的人,都要自己说明用的是哪个口径。
7.3 已知的、可枚举的偏差
| 偏差 | 表现 | 影响范围 | 可否缓解 |
|---|---|---|---|
| 机构偏斜 | 大型联合体贡献占比高 | 全库 | 不可,取决于提交意愿 |
| 癌种偏斜 | 结直肠、肺、胰腺、乳腺四类占多数 | 全库 | 可通过检索绕开 |
| 分子数据偏斜 | 有数据的集中在联合体模型 | 数据层 | 不可,取决于经费 |
| 分期格式偏差 | 三种格式混用 | 亚组分析 | 可自建归一规则 |
| 族裔字段偏差 | 大量 Not Provided | 人群分析 | 不可 |
| 儿科模型稀少 | Paediatric 为 Yes 的占比低 | 儿科研究 | 需去专门库 |
| 时间偏差 | 新提交记录集中在近两年 | 时间序列分析 | 可读 release_date |
| 地域偏差 | 北美与欧洲机构为主 | 全球代表性 | 不可 |
第三行与第八行是这套数据在人群层面的根本限制。模型的供者以欧美人群为主,族裔字段又大量缺失,这意味着任何基于这批模型的药物反应外推,都隐含了一个未经检验的人群假设。这个偏差不是目录方造成的,而是全球 PDX 建库格局的直接反映。
7.4 外部验证矩阵
| 验证项 | 验证方式 | 结论 | 证据层级 |
|---|---|---|---|
| 集合计数 | 接口 totalHits 与 isTotalHitsExact | 一万余条,声明精确 | 官方接口 |
| 类型计数 | 两种写法对照 | 写法不同结果相同 | 官方接口 |
| 字段结构 | 逐条打开两条记录 | 属性与子节两层并存 | 官方接口 |
| 字段取值自由度 | 读取具体记录 | Dataset Available 非二值 | 官方接口 |
| 建库动机 | 论文摘要 | 各机构元数据标准不一 | 论文摘要 |
| 初始规模 | 论文摘要 | 2019 年报告近两千个模型 | 论文摘要 |
| 别名映射 | 未找到公开资源 | 未核实 | 未核实 |
| 许可统一性 | 逐条查看 | 两种声明并存 | 官方接口 |
第七行必须诚实标注。本文没有找到官方的别名映射文件,也没有找到系统性地把同一模型的跨机构记录合并起来的机制说明。这可能是能力问题,也可能是可发现性问题——文件存在但没有被列出。无论哪种,结论都只能是未核实。
7.5 它为何能持续:因为它站的是两家机构的公共基础设施位置
这类目录的存续,很少由使用量决定,更多由它在机构里的位置决定。CancerModels.org 由 EMBL-EBI 与 Jackson Laboratory 联合维护,前者是欧洲生物信息学的基础设施方,后者是美国的老牌模式动物机构。两家都不是靠这个项目谋生的商业体,项目挂在各自的数据服务序列里,属于「应该有人做、我们来做」的那一类。
这个位置带来两件事。一是抗中断能力强,单个课题组解散不会带走整个库;二是不以增长为目标,没有商业压力去刷记录数,也没有动力去为了完整性而降低门槛。从这个角度看,它存活下来的理由和它做不大的理由,是同一件事:它被当成公共品来维护,公共品的逻辑是够用就行,而不是越大越好。
这也解释了 §7.3 那些偏差为什么长期存在。它们不是待修的 bug,而是这套治理结构的必然产物。想改变覆盖率,需要改的是上游的资助安排,而不是这个库的代码。
§8 生态位与历史
8.1 从 PDX Finder 到 CancerModels.org
这个项目起初叫 PDX Finder,由两家机构在 2016 年前后开始合作建设。2019 年 1 月,《核酸研究》的数据库专刊刊出了它的系统介绍,DOI 为 10.1093/nar/gky984,PMID 30535239。那篇摘要把问题说得很直白:PDX 由学术实验室、多机构联合体和合同研究组织分散产生,各方用的元数据标准不同,这使得「找到与研究问题相关的 PDX 模型」成为一件难事。它给出的方案是:按一个事先制定好的社区最小信息标准,把模型属性归一后整合,让跨来源的一致检索成为可能。
摘要里报告当时的规模是近两千个模型,覆盖多个癌种,主要来源是 Patient-Derived Models Repository、PDXNet 与 EurOPDX 三个大型资源。这三个名字在今天的库内仍然能看到,说明整合的主体框架从建站起就没变过,变的是规模与命名。
改名发生在之后几年。从 PDX Finder 到 CancerModels.org,域名也换了,原域名现在已不可访问。改名的动机可以从新名字本身读出:去掉 PDX 这个限定,意味着收录范围不再自我限制在一种模型类型上。库里 Model type 字段留有其他取值的可能,正是这一意图的痕迹。
8.2 名字变化背后的定位变化
「Finder」这个词暗示的是一个检索工具,重点是帮人找到东西。「Models.org」这个组合暗示的是一个领域资源,重点是这个领域本身的公共资产。这个措辞变化对应着一个实际的功能扩展:早期版本更多是链接的集合,现在的版本把供者描述、宿主信息、分发状态都纳入了结构化字段。
但扩展是有边界的。它没有向数据仓库方向走,分子数据始终只存链接。这个边界的选择值得留意,因为它把「这个库能长多大」的天花板钉死了——记录数可以继续涨,但只要分子数据不入库,它就永远不能单独支撑一次完整的建模流程。
8.3 它在 PDX 生态里的位置
PDX 领域的信息基础设施大致分三层。最下层是各机构自己的模型管理系统,负责维持小鼠品系、记录传代、管理分发。中间层是联合体级的协调平台,负责统一表征、统一数据格式。最上层是跨联合体的目录,负责让人知道哪里有模型。CancerModels.org 在最上层。
| 层级 | 典型主体 | 主要职责 | 数据粒度 |
|---|---|---|---|
| 机构层 | 单个实验室、CRO | 维持品系、分发模型 | 单模型 |
| 联合体层 | PDMR、EurOPDX、PDXNet | 统一表征、统一格式 | 联合体内 |
| 目录层 | CancerModels.org | 跨来源检索 | 全领域 |
这个分层有一个隐含的层级依赖:上层的质量由下层的质量决定。目录里的每条记录,都是某个机构层或联合体层已经整理过的产物。下游之所以能给出一致的外观,是因为上游已经做过一次整理。这也意味着,凡是上游没整理的,目录层也无从整理。
8.4 与商业模型库的关系
PDX 领域还有一批商业机构在提供模型服务,合同研究组织是其中的主力。库内能看到这类机构的记录,Supplier type 字段会标明 Commercial 或 Academic。商业记录的加入让目录的覆盖更完整,但也带来了一个新问题:商业模型的描述往往更简略,因为详细的表征数据被当作商业资产。
| 供应商类型 | 记录特征 | 数据可得性 | 分发条件 |
|---|---|---|---|
| 学术机构 | 描述较全,联系人明确 | 分子数据看经费 | 需签材料转让协议 |
| 国家级资源 | 表征统一,字段规整 | 数据较全 | 有公开申请流程 |
| 商业机构 | 描述较简,字段少 | 部分仅内部 | 按商业合同 |
| 联合体 | 表征与格式最统一 | 数据最全 | 按联合体政策 |
这四类记录在同一套字段下并排出现,检索时看不出来源类型的差异,除非打开记录看 Supplier type。做候选集筛选时若忽略这一层,很容易出现「筛出十个模型,七个拿不到」的情况。
§9 使用指引
9.1 三种角色的路径
临床前研究者的路径。起点是癌种与取材部位,不是字段名。先用组织学关键词加类型过滤拉一个宽候选,再用 Available for distribution 与 Provider URL 缩到能拿到模型的,最后逐个打开看肿瘤类型与治疗史。三步走完通常会剩下原来的十分之一到五分之一。这个缩减比例不是坏事,它把「看起来可用」和「实际可用」分开了。
生物信息学工程师的路径。起点是数据结构,不是内容。先把全量元数据拉下来,然后枚举关键字段的取值,建一张取值对照表,再据此写筛选规则。这个顺序不能反——先看内容再定规则,会在遇到第三个奇异取值时推翻前面的全部工作。
药物研发团队的路径。起点是药效数据的有无,不是模型数量。库内能直接给出响应数据的是少数,多数要回来源库或论文去找。现实做法是先圈定几个大型来源库,在各自平台内部完成响应数据检索,再用本目录做跨库核对。反过来做会事倍功半。
9.2 一条最短的可用流程
从零到一个可分析的候选集,最短的路径是五步。下面这段脚本把五步串起来,每一步只做一件事。
#-- 五步:取总数、取候选、筛可得、筛有数据、导出
import json
import time
import urllib.parse
import urllib.request
BASE = "https://www.ebi.ac.uk/biostudies/api/v1"
def api(path, **params):
url = f"{BASE}/{path}"
if params:
url += "?" + urllib.parse.urlencode(params)
with urllib.request.urlopen(url, timeout=60) as r:
return json.load(r)
#-- 第一步 确认口径
head = api("CancerModelsOrg/search", pageSize=1)
print("总数", head["totalHits"], "精确", head["isTotalHitsExact"])
#-- 第二步 拉候选摘要
q = '"Lung" AND Model type:PDX'
hits = []
for p in range(1, 4):
r = api("CancerModelsOrg/search", query=q, pageSize=100, page=p)
hits.extend(r["hits"])
time.sleep(0.3)
print("候选", len(hits))
#-- 第三步 逐条取属性并筛可得性
def flat(sec, out=None):
if out is None:
out = {}
if isinstance(sec, list):
for x in sec:
flat(x, out)
return out
for a in sec.get("attributes") or []:
out.setdefault(a.get("name"), []).append(a.get("value"))
subs = sec.get("subsections") or []
if isinstance(subs, dict):
subs = [subs]
for s in subs:
flat(s, out)
return out
kept = []
for h in hits:
d = flat(api(f"studies/{h['accession']}")["section"])
dist = (d.get("Available for distribution") or [""])[0]
data = (d.get("Dataset Available") or [""])[0]
if dist == "Yes":
kept.append({"acc": h["accession"], "id": d.get("Model ID", [""])[0],
"data": data, "hist": d.get("Histology", [""])[0]})
time.sleep(0.2)
print("可分发", len(kept))
#-- 第四步 按数据字段分组,人工判读后再定规则
from collections import Counter
print(Counter(k["data"] for k in kept).most_common())
#-- 第五步 导出
with open("pdx_candidates.json", "w", encoding="utf-8") as f:
json.dump(kept, f, ensure_ascii=False, indent=1)
这段脚本的关键不在代码,在第四步。第二、三步都可以自动化,第四步必须人工看一眼分布再决定哪些取值算「有数据」。把它放在导出之前,是为了让规则显式化。
9.3 引用方式
学术引用上,通常引两样东西:原始论文,以及具体记录的 accession。论文引用用 2019 年《核酸研究》那篇,DOI 为 10.1093/nar/gky984。记录引用写 BioStudies accession,形如 S-CMO 加五位数字,并注明查询日期,因为记录可能被更新。
| 引用对象 | 写法 | 说明 |
|---|---|---|
| 平台整体 | 论文 DOI 加官方站点 | 说明数据来源 |
| 单条记录 | accession 加查询日期 | 记录会更新 |
| 一批记录 | 检索式加查询日期 | 检索式可复现 |
| 来源模型 | 原始机构发布号 | 学术惯例更认这个 |
第三行值得强调。引用一批记录时,光写「来自 CancerModels.org」是没法复现的,因为不同筛选条件得到的集合完全不同。把完整的检索式写进去,是让结论可核对的最低成本做法。
§10 AI 使用声明
| 事项 | 说明 |
|---|---|
| 内容生成 | 由 AI 助手依据本次查询结果起草,经编辑流程整理 |
| 数据获取 | 通过 BioStudies 公共检索接口与会话式请求获得,未经人工逐条录入 |
| 数字核对 | 所有计数均标注查询日期,口径随文说明 |
| 未核实项 | 别名映射文件的公开性、部分字段取值的完整枚举 |
| 事实边界 | 未做全量下载,未做逐条遍历统计 |
| 图像 | 封面为生成式插画,不含任何真实影像 |
| 更新机制 | 计数类数字带查询日期,日期之后的变化不在本文范围内 |
| 责任声明 | 本文不构成任何临床或研发决策依据 |
常见误读(避坑清单)
| 常见说法 | 实际 | 证据 |
|---|---|---|
| 编号一样就是同一个模型 | 编号只在机构内唯一,跨机构同名要视为两个模型 | 库内 Model ID 直接沿用机构命名,标题第一段的机构缩写才是区分依据 |
| 不同论文里名字一样代表同一模型 | 论文命名习惯按课题组走,同名字常是巧合 | 库内同名记录分属不同 Organization 子节并不罕见 |
| 有一万条记录就有一万个模型 | 同一模型可能因多次提交得到多条记录 | accession 由提交动作分配,与模型本体无关 |
| Dataset Available 为 Yes 才算有分子数据 | 该字段取值非二值,很多有数据的填的是别的描述 | 精确过滤 Yes 只得到 13 条,与印象严重不符 |
| 它存了分子数据 | 它只存链接,原始文件在来源库 | 记录里只有 Provider URL 与外链,无文件下载项 |
| 许可统一是 CC0 | 逐条声明,同一批记录里两种声明并存 | 单条记录能看到 License 取值为 CC0 或 EMBL-EBI |
| 可以用来做药物响应预测的训练集 | 标签方案与终点不统一,且多数模型无分子数据 | 响应数据来自各来源库,字段不在主表 |
| 可以直接当临床前结论 | 是免疫缺陷小鼠上的异种移植,缺免疫微环境 | 宿主品系字段显示为免疫缺陷背景 |
| 它覆盖了全球 PDX | 以北美与欧洲机构为主,族裔字段大量缺失 | 供者族裔多处为 Not Provided |
| 搜到的记录就能拿到模型 | 可检索、可分发、有数据是三件独立的事 | Available for distribution 与 Dataset Available 是两个字段 |
FAQ
Q1 这和 PDX Finder 是同一个东西吗?
是。PDX Finder 是它早期的名字,后来改名为 CancerModels.org,原域名已不可用。库里记录的建站历史与 2019 年那篇论文能对上。
Q2 为什么记录数只有一万多?PDX 不是应该有更多吗?
全球实际在用的 PDX 数量确实更多,但收录依赖提交。库不做抓取,机构不提交就收不进来。这也是为什么它一直呼吁模型产生方主动参与。
Q3 一个模型在库里会不会有多条记录?
可能。accession 由提交动作分配,同一模型被不同项目各提交一次,就会有两条。做去重时不能只看 accession。
Q4 能不能按患者 ID 把模型和患者端数据连起来?
不能。库内不存患者标识,只有性别、年龄段、族裔这类粗粒度描述。想连患者端数据,只能靠机构加癌种加年龄段的模糊匹配,可靠性有限。
Q5 分子数据到底在哪?
在来源库。记录里的外链指向对方的模型页面或数据门户,具体文件要通过对方的检索系统或申请流程获取。
Q6 给药响应数据是怎么回事?
部分来源库在提交时带了响应数据的链接,格式是各库自己的。库内没有统一的响应本体,字段层面也不以原始测量值入库。
Q7 界面抓不到内容怎么办?
前端是渲染式的,直接抓 HTML 得到的是空壳。改用 BioStudies 的公共接口,路径是 api/v1 加集合名。
Q8 收录类器官或者细胞系吗?
Model type 字段留有扩展可能,但库内主体是 PDX。检索层对 PDX 与 PDOX 做了同义处理,说明类型字段的取值管控不严。
Q9 能不能用在论文里做模型清单?
可以,但要写明 accession 与查询日期,并说明筛选条件。清单的构成完全取决于检索式,不写检索式的清单无法复现。
Q10 这个库会不会某天关掉?
它挂在 EMBL-EBI 与 Jackson Laboratory 的公共基础设施序列里,属于机构级项目而非单一课题组项目,中断风险相对低。但域名已经换过一次,历史链接需要自己维护。
Q11 有没有批量下载的官方文件?
本次查询未找到官方打包下载入口,官方站点以检索为主。全量数据要通过接口自建导出。
Q12 用它做训练集,最大的坑是什么?
把元数据记录数当成样本数,把 Dataset Available 的缺失当成有数据。这两步任何一个出错,后面全部结论都要重做。
术语表
| 术语 | 英文 | 含义 |
|---|---|---|
| 患者来源异种移植 | PDX | 把患者肿瘤组织移植到免疫缺陷小鼠体内传代形成的模型 |
| PDOX | PDOX | PDX 的另一种写法,库内检索层视为同义 |
| 类器官 | organoid | 体外三维培养的细胞团,与本库主体不同 |
| 模型标识 | Model ID | 产生机构给模型的命名,机构内唯一 |
| 存档编号 | accession | BioStudies 分配给每次提交的容器编号 |
| 生物研究档案 | BioStudies | EMBL-EBI 的多类型研究数据容器系统 |
| 联合目录 | union catalog | 只记录馆藏位置、不持有实物的目录 |
| 别名归一 | alias harmonization | 把同一实体的不同写法合并到一个标识下 |
| 最小信息标准 | PDX-MI | PDX 领域规定的模型描述最少字段集 |
| 受控词表 | controlled vocabulary | 限定取值的字段字典 |
| 本体 | ontology | 带层级的受控术语体系 |
| 组织学 | histology | 肿瘤的病理学分型 |
| 原发部位 | primary site | 肿瘤最初发生的器官 |
| 取材部位 | collection site | 实际取样所在位置,可能是转移灶 |
| 原位移植 | orthotopic | 把肿瘤移植到对应器官内 |
| 皮下移植 | subcutaneous | 把肿瘤移植到皮下 |
| 传代数 | passage | 模型在小鼠体内传代的次数 |
| 宿主品系 | host strain | 承载移植瘤的小鼠品系 |
| 免疫缺陷 | immunodeficient | 缺少部分免疫功能的品系背景 |
| 分发状态 | distribution | 模型能否对外提供 |
| 数据可用性 | dataset availability | 记录是否关联分子数据 |
| 材料转让协议 | MTA | 获取生物材料的法律文件 |
| 患者来源模型库 | PDMR | 美国 NCI 下属的 PDX 资源 |
| 欧洲联合体 | EurOPDX | 欧洲的 PDX 协作网络 |
| 美国联合体 | PDXNet | 美国的 PDX 协作网络 |
| 合同研究组织 | CRO | 提供外包研发服务的商业机构 |
附录 A:核心数字核对表
| 项 | 值 | 来源 | 来源层级 |
|---|---|---|---|
| 集合记录总数 | 10348 | BioStudies 检索接口 totalHits | 官方接口 |
| PDX 类型记录数 | 6856 | 同一接口加类型过滤 | 官方接口 |
| PDOX 写法命中数 | 6856 | 同一接口换写法 | 官方接口 |
| 结直肠相关记录 | 1026 | 关键词加类型过滤 | 官方接口 |
| 肺相关记录 | 934 | 关键词加类型过滤 | 官方接口 |
| 胰腺相关记录 | 590 | 关键词加类型过滤 | 官方接口 |
| 乳腺相关记录 | 551 | 关键词加类型过滤 | 官方接口 |
| 明确标注有数据 | 13 | 可用性字段等值过滤 | 官方接口 |
| 2019 年报告规模 | 近两千 | 论文摘要 | 论文摘要 |
| 建站时间 | 2016 年前后 | 论文与站点信息互证 | 二级推断 |
| 首发期刊 | Nucleic Acids Research 2019 | 论文元数据 | 论文摘要 |
| 论文 DOI | 10.1093/nar/gky984 | 论文元数据 | 论文摘要 |
| 论文 PMID | 30535239 | 论文元数据 | 论文摘要 |
| 别名映射文件 | 未找到 | 本次检索 | 未核实 |
附录 B:数字的来源分层
官方页面与接口层。集合总数、类型计数、四个癌种计数、可用性等值过滤计数,全部来自 BioStudies 的 CancerModelsOrg 集合检索接口,查询时间为 2026 年 10 月 26 日。这一层数字可复现,复现时须带上同样的查询字符串。
论文摘要层。2019 年报告近两千个模型、覆盖多个癌种、三个主要来源库,来自《核酸研究》那篇摘要。这一层数字反映的是建站初期状态,与今天的规模差了五倍,引用时必须带上年份。
未核实层。别名映射是否存在公开文件、分子数据覆盖率的真实比例、Collection Site 字段的完整取值分布。这三项本次没有找到可核实的来源,任何引用都应标为未核实,不能凭印象补数字。
附录 C:完整参考文献
- PDX Finder: A portal for patient-derived tumor xenograft model discovery. Nucleic Acids Research, 2019. doi:10.1093/nar/gky984. PMID 30535239. PMC6323912.
- PDX Finder: A Portal for Patient-Derived tumor Xenograft Model Discovery. bioRxiv 预印本, 2018. doi:10.1101/291443.
- CancerModels.org 官方站点,检索日期 2026-10-26。
- EMBL-EBI BioStudies CancerModelsOrg 集合检索接口,检索日期 2026-10-26。
- EMBL-EBI BioStudies 单条记录接口,记录 S-CMO10361 与 S-CMO5794,检索日期 2026-10-26。
附录 D:任务代码
跑一次全量枚举所需的最小脚本,放在这里以便整段复制。它做三件事:确认口径、枚举可用性字段取值、按癌种分组计数。
#-- 一次性跑完:口径、取值枚举、癌种分组
import json
import time
import urllib.parse
import urllib.request
from collections import Counter
BASE = "https://www.ebi.ac.uk/biostudies/api/v1"
def api(path, **kw):
url = f"{BASE}/{path}?" + urllib.parse.urlencode(kw)
with urllib.request.urlopen(url, timeout=60) as r:
return json.load(r)
head = api("CancerModelsOrg/search", pageSize=1)
print("总数", head["totalHits"], "精确", head["isTotalHitsExact"])
types = {}
for t in ("PDX", "PDOX"):
types[t] = api("CancerModelsOrg/search", query=f"Model type:{t}", pageSize=1)["totalHits"]
print("类型", types)
cancers = {}
for k in ("Colorectal", "Lung", "Pancreatic", "Breast"):
q = f'"{k}" AND Model type:PDX'
cancers[k] = api("CancerModelsOrg/search", query=q, pageSize=1)["totalHits"]
print("癌种", cancers)
q = 'Model type:PDX'
accs = []
for p in range(1, 6):
r = api("CancerModelsOrg/search", query=q, pageSize=100, page=p)
accs.extend(h["accession"] for h in r["hits"])
time.sleep(0.3)
def flat(sec, out=None):
if out is None:
out = {}
if isinstance(sec, list):
for x in sec:
flat(x, out)
return out
for a in sec.get("attributes") or []:
out.setdefault(a.get("name"), []).append(a.get("value"))
subs = sec.get("subsections") or []
if isinstance(subs, dict):
subs = [subs]
for s in subs:
flat(s, out)
return out
vals = Counter()
for a in accs:
d = flat(api(f"studies/{a}")["section"])
vals[(d.get("Dataset Available") or [None])[0]] += 1
time.sleep(0.2)
for k, n in vals.most_common(10):
print(repr(k), n)
附录 E:如果只记五件事
| 序号 | 要记住的事 |
|---|---|
| 一 | 它是索引,不是仓库;数据在来源库,它只给指针 |
| 二 | 编号只在机构内唯一,跨库连接要用机构缩写加 Model ID |
| 三 | 别名归一没有做到跨机构自动合并,依赖提交方申报 |
| 四 | 数据可用性字段不是布尔量,直接按 Yes 过滤会严重漏检 |
| 五 | 可检索、可获取、有数据是三件独立的事,做筛选时分三步 |
编辑说明
本篇的事实基础是 2026 年 10 月 26 日对 BioStudies 公共检索接口的会话式查询,加上 2019 年《核酸研究》论文摘要。查询覆盖了集合计数、类型计数、四个癌种的计数、可用性字段的等值过滤计数,以及两条完整记录(S-CMO10361、S-CMO5794)的结构。没有做全量下载,也没有对全部记录逐条统计,因此凡涉及「比例」「分布」的表述都限定在已查询的样本范围内。官方站点为前端渲染,直接抓取仅得到容器页面,站点自身的统计数字未能通过 HTML 获取,正文中的计数一律标注为接口来源。别名映射的公开性、Collection Site 字段的完整取值域、给药响应的实际覆盖率三项未能核实,已在附录 B 单列。若后续需要更高精度的统计,正确做法是走 §5.3 的分页拉取,并对 Dataset Available 字段先做取值枚举再定筛选规则。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- ccle — 共享标签:肿瘤学 / 药物发现与化学 / 基因组学与多组学
- cellminer-cdb — 共享标签:肿瘤学 / 药物发现与化学 / 基因组学与多组学
- depmap-ccle — 共享标签:肿瘤学 / 药物发现与化学 / 基因组学与多组学
- genomics-england-100k — 共享标签:肿瘤学 / 基因组学与多组学
- prism — 共享标签:肿瘤学 / 药物发现与化学
- target — 共享标签:肿瘤学 / 基因组学与多组学
- nci-almanac — 共享标签:肿瘤学 / 药物发现与化学
- aacr-genie — 共享标签:肿瘤学 / 基因组学与多组学
- intact — 共享标签:药物发现与化学 / 基因组学与多组学
- msigdb — 共享标签:药物发现与化学 / 基因组学与多组学
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

