总览 · ← 返回运行 20261001-140531-search-t1-g23-spark
节点 n9 在终选来历上
组成重加权(数据内禀增殖打分,负 β):按各细胞类型"增殖−凋亡"打分差以 f=clip(exp(β·Δp),0.5,2)、β=-4 重加权 copy_last 抽样;表达原样复制(α=0)。
| 运行?一次完整的自动搜索或 Agent 会话,有自己的锁定配置和证据包。 | 20261001-140531-search-t1-g23-spark |
|---|---|
| 父节点 | n6 |
| 子节点 | n14 |
| 操作?种子:人写的起点;改进:在父节点上改;草稿:从头写;修复:修父节点的报错。 | 改进 |
| 状态 | 已打分 |
| 分数 | 搜索目标分 53.64(+3.6) · proxy 54.79(+4.7) · proxy2 54.79(+4.7) · X3 51.35(+1.3) · 3 次复测均分 53.54 |
| 审查 | 未审查 |
| 用时?从运行开始到结束(或到现在)的挂钟时间。 | 12 分 |
| 程序版本 | 9bc54c87df3d84296ba0664f9edd83cdd3baee71 (programs.git) |
方法说明?节点程序自带的 METHOD.md:这个程序做了什么、为什么。
来自 programs.git 9bc54c87df:solution/METHOD.md
组成重加权(数据内禀增殖打分,负 β):按各细胞类型"增殖−凋亡"打分差以 f=clip(exp(β·Δp),0.5,2)、β=-4 重加权 copy_last 抽样;表达原样复制(α=0)。
方法
- 表达:完全复制最后一个官方输入阶段(proxy=E8.5,X3=E9.0,final=E9.5)的细胞,不做任何位移(节点 6 结论:X3 上任何 α>0 都劣于复制;节点 3 的加性+clip 位移毁 covariation)。位移代码保留(--alpha),默认 0。
- 组成(本节点的改动):对最后官方输入阶段的每个细胞算打分 p_cell = mean(z 增殖基因) − mean(z 凋亡基因),基因按全阶段所有细胞 z-score。基因集为已发表通用细胞周期(Tirosh et al. 2016 风格:Mki67, Top2a, Ccna2, Ccnb1, Cdk1, Pcna, Mcm2/3/5, Rrm2, Tyms, Birc5, Ube2c, Tpx2, Cenpa, E2f1, Hmgb2, Nusp1, Kif23, Ccnb2, Cdkn3, Bub1, Plk1, Aurkb, Kif20a, Anln, Hist1h1c, Smc2, Prim1, Fen1)与凋亡基因(Bax, Casp3/7/9, Bbc3, Tp53, Gadd45a, Bak1, Bok, Apaf1, Bcl2l11, Trp53inp1, Cdkn1a),与面板取交集(通用已发表知识,不含禁窗测量)。
- 每类型均值 p_c 向细胞数加权均值 p̄ 收缩(系数 n_c/(n_c+100)),重加权倍数 f_c = clip(exp(β·(p̂_c−p̄)), 0.5, 2),权重 w_c = n_c·f_c。
- 目标细胞数按 w_c 比例分配(容量上限=3×n_c,超出重分配),类型内无放回抽样,超额时每源细胞最多用 3 次。rng=default_rng(seed),确定性。
- 外部跨数据集输入(proxy2 的 Qiu E9.0)完全忽略(节点 6 结论:批次效应主导;proxy2 预测与 proxy 逐字节相同,已验证 md5 一致)。
- 单输入阶段即可用(打分只用一个快照),无两阶段差外推,final 视图同规则成立。
β 的符号与取值(vec-score A 半,13 次查询)
- 正 β(上调高增殖类型)在两个尺子上都变差:proxy β=+1→45.81,β=+2→43.56(direction 44.75/43.50,de_direction 转负)。
- 负 β 单调改善后平台:proxy β=-1→54.31,-2→55.35,-3→55.57,-4→55.24,-5→55.04(copy_last 基线实测 50.40,父节点记录的 50.04 含 float 往返噪声)。X3 β=-3→51.11,-4→51.34,-5→51.57(基线 50.00)。
- 选 β=-4:proxy 55.24(seed1 复查 55.48,种子噪声 ±0.24)、X3 51.34、proxy2=proxy(md5 相同,实测 55.24)。三尺子均值 ≈53.9 vs 父 50.03。
- 放宽 clip 到 [1/3,3](β=-4):proxy 54.29 变差、X3 51.34 不变 → 保持 [0.5,2]。
为什么负号合理(机制解释,写进程序的知识只有"打分用哪组基因")
打分是快照上的相对增殖活性:快速循环的多能祖细胞(NCC、EXEM、Paraxial Mesoderm、Surface Ectoderm)在接下来一天里大量分化、其祖细胞池被消耗/稀释,而相对退出周期的分化群(心肌、内皮、前肠衍生)在群体层面净扩增(心脏在 E9 开始搏动并快速长大)。两个独立尺子(全胚 proxy、心脏 X3)同向验证了这一点,不是 A 半噪声。β 与 clip 是超参数,方向由数据驱动,无任何硬编码类型名/比例。
验证
- vec-check 三视图全 ok;proxy/proxy2 输出 md5 相同;seed 0/1 分数差 <0.3。
- 运行 ~5s,内存 ~1.3GB,远低于 limits。
未验证 / 局限
- final(E9.5→E10.5,1 天间隔)无法本地查分;β=-4 的幅度在更长间隔上可能偏大或偏小(组成漂移更多由新类型出生驱动,而重加权只能调已有类型的比例)。
- X3 增益 +1.3 小于噪声线(2 分),主要增益来自 proxy/proxy2(+4.8~5.2)。
- 不产生新细胞类型、不改表达谱:cell_state/de_recovery 的提升只来自组成与分布形状。
调研员的计划
| 名称 | 增殖打分驱动的组成重加权(内禀增长率,β 阻尼,β=0 退化为 copy_last) |
|---|---|
| 动机 | 父节点 6 四组全部 ~50(cell_state 49.93 最弱),其 ANALYSIS 明确指出:节点 2 靠组成调整在 proxy 拿 56.23(vs 节点 6 的 50.04,+6.2),'细胞组成重加权比表达位移更有效';而表达位移在 X3 上被否定(α≥0.1 时 de_score 恒饱和 −0.0857)。节点 2 在 X3 只有 46.85(低于 copy 基线 50.00),提示其组成先验可能是硬编码/心脏特异的,跨视图不稳健。本方案用数据内禀信号(各细胞类型的增殖-凋亡打分差)驱动组成重加权:不碰表达矩阵(保住节点 6 已修复的 covariation 50.11),且同一规则在 proxy(单输入)、X3(心脏)、final(全胚)上都成立,属于 T1-13/T1-03 家族,与节点 2 的先验式重加权机制不同。 |
| 做法 | 在节点 6 的 run.py 上改抽样环节,保留 ALPHA=0 的位移代码不动。步骤:(1) 对最后一个官方输入阶段(proxy 为 E8.5,X3 为 E9.0,final 为 E9.5;proxy2 的外部 Qiu 输入按节点 6 结论完全忽略),计算每细胞的增殖打分 p:取已发表通用细胞周期基因集(Tirosh 2016 风格,如 Mki67, Top2a, Ccna2, Ccnb1, Cdk1, Pcna, Mcm2, Mcm5, Rrm2, Tyms, Birc5, Ube2c, Tpx2, Cenpa, E2f1, Hmgb2, Nusp1, Kif23,与面板取交集;全为已发布阶段的通用知识,不含禁窗信息)与凋亡基因集(Bax, Casp3, Casp9, Bbc3, Tp53, Gadd45a 等),基因先按全样本 z-score,p_cell = mean(增殖) − mean(凋亡)。(2) 每类型均值 p_c,对 n_c<100 的类型按 n_c/(n_c+100) 向全体加权均值收缩;权重 w_c = n_c · exp(β·(p_c − p̄)),单类型重加权倍数 clip 到 [1/2, 2]。(3) 目标细胞数按 w_c 归一化做多项式分配(rng 用 seed),各类型内无放回抽样,超过 n_c 时允许重复抽样但单细胞重复次数 ≤3,超出部分按 w 重新分配给其他类型;细胞表达原样复制(不做任何位移,α 保持 0)。(4) β 网格用 vec-score A 半筛选:先跑 β=0 sanity(应复现 proxy≈50.04、X3≈50.00),再 β∈{0.5,1.0,2.0} 查 proxy(proxy 单输入即可测组成重加权,这是本方案相对表达位移的关键优势——不需要两阶段尺子);取 proxy 上最优的 1–2 个 β 再查 X3 与 proxy2,按节点分公式(三尺子均值)选 β;若最优 β 与 β=0 差距 <2 分(噪声内),用不同程序 seed 各复查 2 次再定,仍无差异则定 β=0 保底(不劣于父节点 50.03)。查询预算约 12/20。(5) 单输入阶段天然可用(打分只用一个快照),两阶段时不引入跨阶段组成差外推(X3 已证明其有害,节点 2 的 46.85 是前车之鉴)——统一只用最后阶段的内禀打分。 |
| 风险 | (1) 增殖打分可能不足以预测 1 天内的相对扩增(组成变化还受迁移、新类型出生驱动),β>0 无增益——Engineer 应在前 4 次查询(β 网格 on proxy)内发现,此时直接落 β=0,分数不劣于父节点。(2) 重加权在 X3(心脏、仅 2174 细胞)上可能像节点 2 一样掉分——必须先查 X3 再定 β,若 X3 掉 >2 分而 proxy 涨 <4 分则弃用(三尺子等权,X3 损失会抵消 proxy 增益)。(3) 重复抽样(单细胞 ×3)可能压低 covariation/de_recovery——分配阶段监控重复率,若某类型重复率 >30% 说明 β 过大。(4) 面板基因与细胞周期基因集交集过小(<5 个)时打分噪声大——此时回退 β=0 并在 METHOD.md 记录。(5) A 半/B 半差异:所有 β 决策只依据 A 半且要求超噪声(>2 分),接近噪声时保守取小 β 或 0。 |
代码改动?这个节点的程序和父节点程序的逐行差别:绿色是新增,红色是删除。
对比:父节点版本 83a5263c1a。改动的文件:solution/METHOD.md +25 −13、solution/run.py +158 −27
diff --git a/solution/METHOD.md b/solution/METHOD.mdindex 8159700..9660e59 100644--- a/solution/METHOD.md+++ b/solution/METHOD.md@@ -1,20 +1,32 @@-阻尼伪批量位移(线性空间乘性 + EB 逐基因收缩):X3 上调 α 网格后发现任何位移都劣于复制,α 定为 0,退化为 copy_last,但保留完整位移机制。+组成重加权(数据内禀增殖打分,负 β):按各细胞类型"增殖−凋亡"打分差以 f=clip(exp(β·Δp),0.5,2)、β=-4 重加权 copy_last 抽样;表达原样复制(α=0)。 ## 方法 -- 从最近两个**官方**输入阶段计算每细胞类型伪批量差值 delta = mean(last|c) − mean(prev|c)(log 空间),同时算抽样标准误 se² = var_last/n_last + var_prev/n_prev。-- 逐基因经验贝叶斯收缩:tau²_g = max(0, Var_c(delta_cg) − mean_c(se²_cg)),s_cg = tau²_g/(tau²_g+se²_cg),delta' = clip(s·delta, ±1.5)。-- 应用方式为线性空间乘性缩放:x_new = log1p(expm1(x)·exp(α·delta'_c))。单调、零点保持零点,无父节点加性+clip(≥0) 的零堆积(父节点 covariation 38.53 的主要来源)。-- 前一阶段缺失的类型原样复制;单输入阶段(proxy)退化为 copy_last 抽样;外部跨数据集输入(proxy2 的 Qiu E9.0)不参与 delta——跨技术批次效应会主导差值。+- 表达:完全复制最后一个**官方**输入阶段(proxy=E8.5,X3=E9.0,final=E9.5)的细胞,不做任何位移(节点 6 结论:X3 上任何 α>0 都劣于复制;节点 3 的加性+clip 位移毁 covariation)。位移代码保留(--alpha),默认 0。+- 组成(本节点的改动):对最后官方输入阶段的每个细胞算打分 p_cell = mean(z 增殖基因) − mean(z 凋亡基因),基因按全阶段所有细胞 z-score。基因集为已发表通用细胞周期(Tirosh et al. 2016 风格:Mki67, Top2a, Ccna2, Ccnb1, Cdk1, Pcna, Mcm2/3/5, Rrm2, Tyms, Birc5, Ube2c, Tpx2, Cenpa, E2f1, Hmgb2, Nusp1, Kif23, Ccnb2, Cdkn3, Bub1, Plk1, Aurkb, Kif20a, Anln, Hist1h1c, Smc2, Prim1, Fen1)与凋亡基因(Bax, Casp3/7/9, Bbc3, Tp53, Gadd45a, Bak1, Bok, Apaf1, Bcl2l11, Trp53inp1, Cdkn1a),与面板取交集(通用已发表知识,不含禁窗测量)。+- 每类型均值 p_c 向细胞数加权均值 p̄ 收缩(系数 n_c/(n_c+100)),重加权倍数 f_c = clip(exp(β·(p̂_c−p̄)), 0.5, 2),权重 w_c = n_c·f_c。+- 目标细胞数按 w_c 比例分配(容量上限=3×n_c,超出重分配),类型内无放回抽样,超额时每源细胞最多用 3 次。rng=default_rng(seed),确定性。+- 外部跨数据集输入(proxy2 的 Qiu E9.0)完全忽略(节点 6 结论:批次效应主导;proxy2 预测与 proxy 逐字节相同,已验证 md5 一致)。+- 单输入阶段即可用(打分只用一个快照),无两阶段差外推,final 视图同规则成立。 -## 验证(vec-score,A 半)+## β 的符号与取值(vec-score A 半,13 次查询) -- X3(E8.75+E9.0→E9.5,唯一可测的两阶段尺子):α=1.0 → 48.93;α=0.7 → 48.99;α=0.5 → 49.03;α=0.3 → 49.07;α=0.2 → 49.09;α=0.1 → 49.11;α=0 → 50.00(四组全 50)。-- 关键发现:de_score 在 α≥0.1 时恒为 −0.0857(饱和),即 EB 收缩后的极小 delta(mean|d|≈0.003,原始 ≈0.013)也已把 de_recovery 从 50 压到 47.3——E8.75→E9.0 的 delta 方向对 E9.5 目标基本无益。乘性+EB 相对父节点加性+clip 已把 X3 从 40.53 修到 49.1(covariation 38.5→49.9),但最优仍是 α=0。-- 故默认 ALPHA=0.0:proxy/proxy2/X3 都等于 copy_last 抽样(proxy 50.04,X3 50.00)。位移机制保留在代码里(--alpha 可启用),供后续节点在 final(E9.5→E10.5,官方数据、细胞多、EB 收缩弱得多)上另行验证。+- **正 β(上调高增殖类型)在两个尺子上都变差**:proxy β=+1→45.81,β=+2→43.56(direction 44.75/43.50,de_direction 转负)。+- **负 β 单调改善后平台**:proxy β=-1→54.31,-2→55.35,-3→55.57,-4→55.24,-5→55.04(copy_last 基线实测 50.40,父节点记录的 50.04 含 float 往返噪声)。X3 β=-3→51.11,-4→51.34,-5→51.57(基线 50.00)。+- 选 **β=-4**:proxy 55.24(seed1 复查 55.48,种子噪声 ±0.24)、X3 51.34、proxy2=proxy(md5 相同,实测 55.24)。三尺子均值 ≈53.9 vs 父 50.03。+- 放宽 clip 到 [1/3,3](β=-4):proxy 54.29 变差、X3 51.34 不变 → 保持 [0.5,2]。 -## 未验证 / 已知局限+## 为什么负号合理(机制解释,写进程序的知识只有"打分用哪组基因") -- final 视图(真实任务)无法在本节点查分:X3 的"位移无益"结论基于 2174 细胞、0.25 天间隔、sci-RNA-seq 的外部心脏数据,外推到官方 1 天间隔不保证成立;α=0 是保守选择(copy_last 是 T1 已知强基线,官方常数位移 48.6 也低于它)。-- proxy2 的外部 Qiu E9.0 输入完全未用:其标签(First/Second heart field、Endocardial)与官方 E8.5 标签无一一对应,跨数据集 delta 风险大于潜在收益,未做实测。-- 无网络、无保留阶段数据;未使用 prior/ 资源;无硬编码统计量(一切从视图输入现场计算)。+打分是快照上的**相对**增殖活性:快速循环的多能祖细胞(NCC、EXEM、Paraxial Mesoderm、Surface Ectoderm)在接下来一天里大量分化、其祖细胞池被消耗/稀释,而相对退出周期的分化群(心肌、内皮、前肠衍生)在群体层面净扩增(心脏在 E9 开始搏动并快速长大)。两个独立尺子(全胚 proxy、心脏 X3)同向验证了这一点,不是 A 半噪声。β 与 clip 是超参数,方向由数据驱动,无任何硬编码类型名/比例。++## 验证++- vec-check 三视图全 ok;proxy/proxy2 输出 md5 相同;seed 0/1 分数差 <0.3。+- 运行 ~5s,内存 ~1.3GB,远低于 limits。++## 未验证 / 局限++- final(E9.5→E10.5,1 天间隔)无法本地查分;β=-4 的幅度在更长间隔上可能偏大或偏小(组成漂移更多由新类型出生驱动,而重加权只能调已有类型的比例)。+- X3 增益 +1.3 小于噪声线(2 分),主要增益来自 proxy/proxy2(+4.8~5.2)。+- 不产生新细胞类型、不改表达谱:cell_state/de_recovery 的提升只来自组成与分布形状。diff --git a/solution/run.py b/solution/run.pyindex bce7ea1..d67b68b 100644--- a/solution/run.py+++ b/solution/run.py@@ -1,18 +1,21 @@ #!/usr/bin/env python3-"""Damped pseudobulk shift: multiplicative scaling in linear space + EB shrinkage.--For each cell type present in the two latest official inputs, the pseudobulk-delta (log-space mean difference) is computed with its sampling standard error,-shrunk per gene by an empirical-Bayes factor across types, winsorized, and-applied to a subsample of the latest stage as a multiplicative scaling in-linear space: x_new = log1p(expm1(x) * exp(alpha * delta')).--This is monotone, keeps zeros at zero (no clip-induced zero pile-up), and the-global damping alpha < 1 avoids over-extrapolating a single observed step.-Types missing from the earlier stage are copied unchanged. With a single input-stage there is no delta and the method falls back to copy_last sampling.-External (cross-dataset) inputs are ignored: a delta across datasets/technologies-would be dominated by batch effects.+"""Composition reweighting by intrinsic proliferation-vs-apoptosis score.++Expressions are copied unchanged from the latest official input stage (the+damped multiplicative pseudobulk shift is kept in code, ALPHA=0 by default:+X3 showed any nonzero shift is worse than copy). The change vs copy_last is+in *sampling weights*: each cell type gets a growth factor+ f_c = clip(exp(beta * (p_c - pbar)), 0.5, 2)+where p_c is the type's mean per-cell score mean(z prolif) - mean(z apopt)+over published generic cell-cycle / apoptosis gene sets (Tirosh-2016-style;+general published-stage knowledge, no held-out-window information), genes+z-scored over all cells of the stage, pbar the cell-weighted mean, and p_c+shrunk toward pbar by n_c/(n_c+100) for small types. Target cell count is+allocated multinomially proportional to n_c * f_c, sampled without replacement+within a type (each source cell used at most 3 times when over-allocated).++Works with a single input stage (score uses one snapshot); external+cross-dataset inputs are ignored (batch effects dominate; node 6 finding). """ from __future__ import annotations@@ -28,25 +31,136 @@ from src.task1_temporal.view_io import ( load_manifest, panel_genes, read_stage,- sample_rows, target_n_cells, write_prediction, ) -ALPHA = 0.0 # global damping of the shift (tuned on X3: any shift < copy)+ALPHA = 0.0 # expression shift damping (kept from node 6; 0 = copy)+BETA = -4.0 # composition reweight strength (negative: downweight cycling types) WINSOR = 1.5 # winsorize shrunk deltas (log space)+FACTOR_CLIP = (0.5, 2.0) # per-type reweight factor bounds+MAX_COPIES = 3 # a source cell may appear at most this often+SHRINK_N = 100.0 # small-type shrinkage constant++# Published generic cell-cycle (Tirosh et al. 2016 style) / apoptosis sets.+PROLIF_GENES = [+ "Mki67", "Top2a", "Ccna2", "Ccnb1", "Cdk1", "Pcna", "Mcm2", "Mcm5",+ "Rrm2", "Tyms", "Birc5", "Ube2c", "Tpx2", "Cenpa", "E2f1", "Hmgb2",+ "Nusp1", "Kif23", "Ccnb2", "Cdkn3", "Bub1", "Plk1", "Aurkb", "Kif20a",+ "Anln", "Hist1h1c", "Smc2", "Mcm3", "Prim1", "Fen1",+]+APOPT_GENES = [+ "Bax", "Casp3", "Casp9", "Bbc3", "Tp53", "Gadd45a", "Bak1", "Bok",+ "Casp7", "Apaf1", "Bcl2l11", "Trp53inp1", "Cdkn1a",+] def as_csr(matrix) -> sparse.csr_matrix: return matrix.tocsr() if sparse.issparse(matrix) else sparse.csr_matrix(matrix) -def type_shift_deltas(prev_X, prev_labels, last_X, last_labels):- """EB-shrunk, winsorized per-type log-space deltas.+def gene_indices(genes: list[str], names: list[str]) -> np.ndarray:+ pos = {g: i for i, g in enumerate(genes)}+ return np.array([pos[n] for n in names if n in pos], dtype=np.int64)+++def proliferation_score(X: sparse.csr_matrix, genes: list[str]) -> np.ndarray | None:+ """Per-cell mean(z prolif) - mean(z apopt); None if gene overlap too small."""+ pi = gene_indices(genes, PROLIF_GENES)+ ai = gene_indices(genes, APOPT_GENES)+ if len(pi) < 5 or len(ai) < 3:+ return None+ X = as_csr(X).astype(np.float64)+ n = X.shape[0]++ def col_stats(idx):+ sub = X[:, idx]+ mu = np.asarray(sub.mean(axis=0)).ravel()+ sq = np.asarray(sub.multiply(sub).mean(axis=0)).ravel()+ sd = np.sqrt(np.maximum(sq - mu * mu, 0.0))+ return mu, np.where(sd > 1e-8, sd, 1.0)++ def cell_zmean(idx):+ mu, sd = col_stats(idx)+ dense = np.asarray(X[:, idx].todense(), dtype=np.float64)+ return ((dense - mu) / sd).mean(axis=1)++ return cell_zmean(pi) - cell_zmean(ai)+++def type_factors(p_cell: np.ndarray, labels: np.ndarray) -> tuple[np.ndarray, np.ndarray]:+ """Return (unique types, per-type reweight factor f_c), beta applied later."""+ types = np.unique(labels)+ n_c = np.array([(labels == t).sum() for t in types], dtype=np.float64)+ p_c = np.array([p_cell[labels == t].mean() for t in types], dtype=np.float64)+ pbar = float((n_c * p_c).sum() / n_c.sum())+ shrink = n_c / (n_c + SHRINK_N)+ dp = shrink * (p_c - pbar)+ return types, n_c, dp+++def allocate_counts(w: np.ndarray, n_avail: np.ndarray, total: int, rng) -> np.ndarray:+ """Allocate `total` cells proportional to w, capped at MAX_COPIES*n_avail."""+ cap = (MAX_COPIES * n_avail).astype(np.int64)+ total = min(total, int(cap.sum()))+ frac = w / w.sum()+ alloc = np.floor(frac * total).astype(np.int64)+ rem = total - alloc.sum()+ if rem > 0:+ order = np.argsort(-(frac * total - alloc))+ alloc[order[:rem]] += 1+ for _ in range(20):+ over = np.maximum(alloc - cap, 0)+ if over.sum() == 0:+ break+ excess = int(over.sum())+ alloc -= over+ room = np.maximum(cap - alloc, 0)+ if room.sum() == 0:+ break+ add = np.floor(excess * room / room.sum()).astype(np.int64)+ alloc += add+ left = total - alloc.sum()+ if left > 0:+ room = np.maximum(cap - alloc, 0)+ order = np.argsort(-room)+ for j in order:+ if left <= 0:+ break+ take = min(int(room[j]), left)+ alloc[j] += take+ left -= take+ elif left < 0:+ order = np.argsort(-alloc)+ for j in order:+ if left >= 0:+ break+ take = min(int(alloc[j]), -left)+ alloc[j] -= take+ left += take+ return alloc+++def weighted_sample(labels: np.ndarray, factors: np.ndarray, types: np.ndarray,+ n_target: int, rng) -> np.ndarray:+ n_avail = np.array([(labels == t).sum() for t in types], dtype=np.float64)+ w = n_avail * factors+ alloc = allocate_counts(w, n_avail, n_target, rng)+ rows = []+ for t, k in zip(types, alloc):+ idx = np.flatnonzero(labels == t)+ if k <= len(idx):+ rows.append(rng.choice(idx, size=int(k), replace=False))+ else:+ reps = int(np.ceil(k / len(idx)))+ pool = np.tile(idx, reps)+ rows.append(rng.choice(pool, size=int(k), replace=False))+ return np.concatenate(rows) if rows else np.array([], dtype=np.int64)+ - delta_cg = mean(last|c) - mean(prev|c); se2_cg = var_last/n_last + var_prev/n_prev- tau2_g = max(0, Var_c(delta_cg) - mean_c(se2_cg)); s_cg = tau2_g / (tau2_g + se2_cg)- """+# ---- kept from node 6: damped multiplicative pseudobulk shift (ALPHA=0) ----++def type_shift_deltas(prev_X, prev_labels, last_X, last_labels): prev_X = as_csr(prev_X) last_X = as_csr(last_X) types = [t for t in np.unique(last_labels) if t in set(np.unique(prev_labels).tolist())]@@ -74,7 +188,6 @@ def type_shift_deltas(prev_X, prev_labels, last_X, last_labels): def apply_multiplicative(X, labels, deltas, alpha) -> sparse.csr_matrix:- """x_new = log1p(expm1(x) * exp(alpha * delta[type])) per row.""" X = as_csr(X) blocks = [] order = []@@ -102,20 +215,38 @@ def main() -> None: parser.add_argument("--out", required=True) parser.add_argument("--seed", type=int, default=0) parser.add_argument("--alpha", type=float, default=ALPHA)+ parser.add_argument("--beta", type=float, default=BETA) args = parser.parse_args() manifest = load_manifest(args.data) genes = panel_genes(args.data, manifest)- stages = inputs_by_time(manifest)+ stages = inputs_by_time(manifest) # official only; external ignored last = read_stage(args.data, stages[-1], genes) rng = np.random.default_rng(args.seed)- rows = sample_rows(last.n_obs, target_n_cells(manifest, last.n_obs), rng)+ labels = labels_of(last)+ n_target = target_n_cells(manifest, last.n_obs)++ types = np.unique(labels)+ factors = None+ if args.beta != 0:+ p_cell = proliferation_score(last.X, genes)+ if p_cell is not None:+ t2, _n, dp = type_factors(p_cell, labels)+ factors = np.clip(np.exp(args.beta * dp), *FACTOR_CLIP)+ assert np.array_equal(t2, types)++ if factors is not None:+ rows = weighted_sample(labels, factors, types, n_target, rng)+ else:+ from src.task1_temporal.view_io import sample_rows+ rows = sample_rows(last.n_obs, n_target, rng)+ X = last.X[rows]- if len(stages) >= 2:+ if args.alpha != 0 and len(stages) >= 2: prev = read_stage(args.data, stages[-2], genes)- deltas = type_shift_deltas(prev.X, labels_of(prev), last.X, labels_of(last))+ deltas = type_shift_deltas(prev.X, labels_of(prev), last.X, labels) del prev- X = apply_multiplicative(X, labels_of(last)[rows], deltas, args.alpha)+ X = apply_multiplicative(X, labels[rows], deltas, args.alpha) write_prediction(X, genes, args.out, seed=args.seed)
调研来源?调研员查到并用到的知识条目和文献检索结果(只列标题和编号)。
用到的知识库条目
| 编号 | 标题 | 出处 |
|---|---|---|
| k018 | Damped per-type shift: shrinkage alpha on the observed delta | notes/plan/cards/T1.md |
| k031 | Offline OT toolkit in the sandbox: moscot TemporalProblem, wot OTModel, POT, geomloss | 10.1038/s41586-024-08453-2 (moscot); 10.1016/j.cell.2019.01.006 (Waddington-OT) |
| k041 | Within-stage pseudotime and graph toolkit offline: scanpy DPT/PAGA/Leiden, Palantir, CellRank 2 | 10.1186/s13059-019-1663-x (PAGA); 10.1038/s41587-019-0068-4 (Palantir); 10.1038/s41592-024-02303-9 (CellRank 2) |
分析结果?分析员写的 ANALYSIS.json:改了什么、各组分数怎么变、假设是否成立、经验和下一步建议。
| 改了什么 | 在节点 6(copy_last,α=0)基础上加组成重加权:用最后官方输入阶段的内禀"增殖−凋亡"打分(Tirosh 风格基因集,逐细胞 z-score,类型均值按 n/(n+100) 收缩)计算倍数 f=clip(exp(β·Δp), 0.5, 2),按 n_c·f_c 多项式分配抽样(单细胞最多用 3 次);表达原样复制,proxy2 外部输入完全忽略。查分后选定 β=-4(负号,与 PLAN 预期的正 β 相反)。 |
|---|---|
| 各组分数的变化 | X3:噪声内:51.35 vs 50.00,+1.35 < 2 分噪声线 cell_state:变好:53.83 vs 49.93,+3.90,超噪声 covariation:变好:53.49 vs 50.11,+3.38,超噪声 de_recovery:噪声内:50.36 vs 50.00,+0.36 < 2 分噪声线 direction:变好:56.82 vs 50.11,+6.71,远超噪声 proxy:变好:54.79 vs 50.04,+4.75 proxy2:变好:54.79 vs 50.04,+4.75(与 proxy 输出 md5 相同) |
| 假设是否成立 | 是 |
| 经验 |
|
| 下一步建议 |
|
对话摘要?每个角色和大模型对话的统计:轮数、工具调用、用时、token 数和最后的回答摘录;原始记录只给路径。
只给统计和最后回答的摘录;完整对话请到原始记录位置里列出的文件看。
分析员
| 角色?调研员写计划、工程师改代码、分析员解读分数、审查员检查作弊。 | 分析员 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数?大模型一共回复了几轮(每轮可以调用多个工具)。 | 5 |
| 工具调用?大模型调用读文件、执行命令等工具的次数,按工具名统计。 | 共 4 次:bash 2、read 1、write 1 |
| 用时 | 不到 1 分 |
| token 数?输入 / 输出(含思考)的 token 数,来自接口返回的用量。 | 输入 6,054 · 输出 1,323 · 思考 971 |
| 任务(第一行) | 分析节点 n9 的打分结果,写 ANALYSIS.json |
| 最后的回答(摘录) | ANALYSIS.json written |
| 原始记录位置?完整对话记录在 Spark 上的文件路径;看板不复制原始内容。 | /home/spark-longxinyang/vec/g23_wt/agent/runs/20261001-140531-search-t1-g23-spark/nodes/9/analyst.jsonl 12 KB /home/spark-longxinyang/vec/g23_wt/agent/runs/20261001-140531-search-t1-g23-spark/nodes/9/analyst.stderr |
工程师
| 角色 | 工程师 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数 | 28 |
| 工具调用 | 共 34 次:bash 29、write 2、edit 2、read 1 |
| 用时 | 10 分 |
| token 数 | 输入 48,500 · 输出 10,039 · 思考 6,021 |
| 任务(第一行) | 按计划修改程序:增殖打分驱动的组成重加权(内禀增长率,β 阻尼,β=0 退化为 copy_last) |
| 最后的回答(摘录) | 完成。节点 9 提交总结: **做了什么**:在节点 6(copy_last)基础上加组成重加权——用最后官方输入阶段的内禀"增殖−凋亡"打分(Tirosh 风格通用基因集,逐细胞 z-score,类型均值收缩)计算重加权倍数 f=clip(exp(β·Δp),0.5,2),按 n_c·f_c 分配抽样;表达原样复制,忽略 proxy2 外部输入。意外发现:**正 β 有害、负 β 显著有效**(下调快循环祖细胞、上调相对退出周期的分化群,两尺子同向验证)。 **查分**(13/20 次):β=-4 → proxy 55.24(seed1: 55.48)、proxy2 55.24、X3 51.34,均值 ≈53.9 vs 父节点 50.03;copy_last 实测基线 proxy 50.40。β 网格 ±(1~5) 及 clip 放宽均已扫过。三视图 vec-check 通过、默认参数与查分文件 md5 一致、确定性、~5s/1.3GB。 **下一步最值得试**:(1) 在 β=-4 附近联合调 clip 上限(只放宽上侧如 [0.5,3]);(2) 把重加权与节点 2 的心脏/JCF 先验做正交组合(其 proxy 56.23 略高于本节点);(3) final 视图 1 天间隔下漂移更大,可试按 Δt 缩放 β。 |
| 原始记录位置 | /home/spark-longxinyang/vec/g23_wt/agent/runs/20261001-140531-search-t1-g23-spark/nodes/9/engineer.jsonl 126 KB /home/spark-longxinyang/vec/g23_wt/agent/runs/20261001-140531-search-t1-g23-spark/nodes/9/engineer.stderr |
调研员
| 角色 | 调研员 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数 | 1 |
| 工具调用 | 共 0 次:— |
| 用时 | 1 分 |
| token 数 | 输入 9,332 · 输出 1,244 · 思考 3,500 |
| 任务(第一行) | 为节点 n9(改进,父节点 n6)写改进计划 PLAN.json |
| 最后的回答(摘录) | ```json
{
"name": "增殖打分驱动的组成重加权(内禀增长率,β 阻尼,β=0 退化为 copy_last)",
"motivation": "父节点 6 四组全部 ~50(cell_state 49.93 最弱),其 ANALYSIS 明确指出:节点 2 靠组成调整在 proxy 拿 56.23(vs 节点 6 的 50.04,+6.2),'细胞组成重加权比表达位移更有效';而表达位移在 X3 上被否定(α≥0.1 时 de_score 恒饱和 −0.0857)。节点 2 在 X3 只有 46.85(低于 copy 基线 50.00),提示其组成先验可能是硬编码/心脏特异的,跨视图不稳健。本方案用数据内禀信号(各细胞类型的增殖-凋亡打分差)驱动组成重加权:不碰表达矩阵(保住节点 6 已修复的 covariation 50.11),且同一规则在 proxy(单输入)、X3(心脏)、final(全胚)上都成立,属于 T1-13/T1-03 家族,与节点 2 的先验式重加权机制不同。",
"approach": "在节点 6 的 run.py 上改抽样环节,保留 ALPHA=0 的位移代码不动。步骤:(1) 对最后一个官方输入阶段(proxy 为 E8.5,X3 为 E9.0,final 为 E9.5;proxy2 的外部 Qiu 输入按节点 6 结论完全忽略),计算每细胞的增殖打分 p:取已发表通用细胞周期基因集(Tirosh 2016 风格,如 Mki67, Top2a, Ccna2, Ccnb1, Cdk1, Pcna, Mcm2, Mcm5, Rrm2, Tyms, Birc5, Ube2c, Tpx2, Cenpa, E2f1, Hmgb2, Nusp1, Kif23,与面板取交集;全为已发布阶段的通用知识,不含禁窗信息)与凋亡基因集(Bax, Casp3, Casp9, Bbc3, Tp53, Gadd45a 等),基因先按全样本 z-score,p_cell = mean(增殖) − mean(凋亡)。(2) 每类型均值 p_c,对 n_c<100 的类型按 n_c/(n_c+100) 向全体加权均值收缩;权重 w_c = n_c · exp(β·(p_c − p̄)),单类型重加权倍数 clip 到 [1/2, 2]。(3) 目标细胞数按 w_c 归一化做多项式分配(rng 用 seed),各类型内无放回抽样,超过 n_c 时允许重复抽样但单细胞重复次数 ≤3,超出部分按 w 重新分配给其他类型;细胞表达原样复制(不做任何位移,α 保持 0)。(4) β 网格用 vec-score A 半筛选:先跑 β=0 sanity(应复现 proxy≈50.04、X3≈50.00),再 β∈{0.5,1.0,2.0} 查 proxy(proxy 单输入即可测组成重加权,这是本方案相对表达位移的关键优势——不需要两阶段尺子);取 proxy 上最优的 1–2 个 β 再查 X3 与 proxy2,按节点分公式(三尺子均值)选 β;若最优 β 与 β=0 差距 <2 分(噪声内),用不同程序 seed 各复查 2 次再定,仍无差异则定 β=0 保底(不劣于父节点 50.03)。查询预算约 12/20。(5) 单输入阶段天然可用(打分只用一个快照),两阶段时不引入跨阶段组成差外推(X3 已证明其有害,节点 2 的 46.85 是前车之鉴)——统一只用最后阶段的内禀打分。",
"expected_groups": ["cell_state", "direction"],
"risks": "(1) 增殖打分可能不足以预测 1 天内的相对扩增(组成变化还受迁移、新类型出生驱动),β>0 无增益——Engineer 应在前 4 次查询(β 网格 on proxy)内发现,此时直接落 β=0,分数不劣于父节点。(2) 重加权在 X3(心脏、仅 2174 细胞)上可能像节点 2 一样掉分——必须先查 X3 再定 β,若 X3 掉 >2 分而 proxy 涨 <4 分则弃用(三尺子等权,X3 损失会抵消 proxy 增益)。(3) 重复抽样(单细胞 ×3)可能压低 covariation/de_recovery——分配阶段监控重复率,若某类型重复率 >30% 说明 β 过大。(4) 面板基因与细胞周期基因集交集过小(<5 个)时打分噪声大——此时回退 β=0 并在 METHOD.md 记录。(5) A 半/B 半差异:所有 β 决策只依据 A 半且要求超噪声(>2 分),接近噪声时保守取小 β 或 0。",
"sources": []
}
``` |
| 原始记录位置 | /home/spark-longxinyang/vec/g23_wt/agent/runs/20261001-140531-search-t1-g23-spark/nodes/9/researcher.jsonl 5 KB /home/spark-longxinyang/vec/g23_wt/agent/runs/20261001-140531-search-t1-g23-spark/nodes/9/researcher.stderr |