总览 · ← 返回运行 20261003-043412-search-t2-heart-interp-g24-D-s1
节点 n6
相关加权Procrustes+PCA规范化+残差剔除+z网格均衡:PLAN机制全部实现并对照,加权/剔除/z均衡均有害,提交=父节点对齐+PCA规范化(中性)
| 运行?一次完整的自动搜索或 Agent 会话,有自己的锁定配置和证据包。 | 20261003-043412-search-t2-heart-interp-g24-D-s1 |
|---|---|
| 父节点 | n4 |
| 子节点 | — |
| 操作?种子:人写的起点;改进:在父节点上改;草稿:从头写;修复:修父节点的报错。 | 改进 |
| 状态 | 已打分 |
| 分数 | 搜索目标分 59.89(+0.0) · proxy 59.89(+0.0) |
| 审查 | 未审查 |
| 用时?从运行开始到结束(或到现在)的挂钟时间。 | 17 分 |
| 程序版本 | 10438588b375ed4bd1530faa90d1787ae7a76ef0 (programs.git) |
方法说明?节点程序自带的 METHOD.md:这个程序做了什么、为什么。
来自 programs.git 10438588b3:solution/METHOD.md
相关加权Procrustes+PCA规范化+残差剔除+z网格均衡:PLAN机制全部实现并对照,加权/剔除/z均衡均有害,提交=父节点对齐+PCA规范化(中性)
在父节点4(matched-align mix)上实现 PLAN T2HI-02 的三项坐标机制(r²加权Kabsch、2σ残差剔除、PCA手性规范化),另试 z 切片网格均衡。proxy 查分:加权 59.28、剔除+等权 58.62、count×r² 58.72、z均衡 58.94,全部 ≤ 父节点 59.38;规范化严格刚性、分数不变(59.3757)。按"选择依据是查分结果"提交:加权/剔除/z均衡默认关,规范化默认开。
方法与开关
表达/混合/组成逻辑完全未动(expression_change 63.83、cell_state 65.93 与父节点逐位一致)。只改坐标侧:
- 相关加权 Kabsch(
weighted_align,T2_WEIGHT/T2_WMODE):19 对匹配质心(5 同名 r=1 + 14 相关匹配 r=0.53–0.86),第二轮 Kabsch 用 w=r²(或 count×r²)。诊断:等权残差均值 256.3,r² 加权升到 275.6,旋转差 63°——匹配 r 高不代表质心几何一致(如 V-CM r=0.78 但残差最大,被 2σ 剔除后反而更差)。 - 残差剔除(随
T2_WEIGHT=1生效,T2_WMODE=prune_eq可单独测):第一轮等权后剔除残差 > mean+2σ 的对(本 proxy 剔 1 对 V-CM),最少保 5 对,有效对数 <8 时回退等权(PLAN 风险 2/3 的下限都实现)。 - PCA 规范化(
canonicalize,T2_CANON,默认开):最终坐标减质心→PCA 旋转→det=+1→逐轴按第三矩定向。刚性变换,RMS 346.33 不变,seed 0 分数与父节点逐位相同(59.3757 vs 59.38),确认评分器位姿不变;保留它只固定输出位姿的确定性,不指望分数。 - z 网格均衡(
T2_ZEQ,默认关,PLAN 外补充尝试):两输入 z-std 145/173、切片 38/40,父节点混合输出 77 层交错切片;把两朵云 z 缩到 log 插值公共 std 后 d2_shape 0.0375→0.0398、shape 54.45→53.28,说明交错切片反而更接近真值形状,弃用。 - 机制关闭对照:
T2_WEIGHT=0 T2_CANON=0 T2_ZEQ=0输出与父节点4逐位一致(X、coords allclose=True),得分即父节点 A 半 59.38。单输入退路(copy_last 分支)未动。
查分结果(proxy,seed 0,A 半,8 次/额度 20)
| 配置 | 榜分 | shape | local | expr | state |
|---|---|---|---|---|---|
| 提交:等权+PCA规范化(W0C1) | 59.38 | 54.45 | 53.30 | 63.83 | 65.93 |
| r²加权+剔除+规范化(PLAN 提交案) | 59.28 | 54.06 | 53.29 | 63.83 | 65.93 |
| r²加权+剔除,无规范化 | 59.28 | 54.06 | 53.29 | 63.83 | 65.93 |
| 剔除+等权 | 58.62 | 52.14 | 52.59 | 63.83 | 65.93 |
| count×r²加权+剔除 | 58.72 | 52.62 | 52.49 | 63.83 | 65.93 |
| 等权+规范化+z均衡 | 58.94 | 53.28 | 52.73 | 63.83 | 65.93 |
机制生效证据与对照结论
- 机制确实改变了对齐:加权后旋转与等权差 63.1°,剔除 1 对(V-CM,残差 >2σ),四组分中 shape_scale 54.45→54.06/52.14/52.62、local_spatial 53.30→53.29/52.59/52.49,expr/state 逐位不变(未动表达,符合 PLAN 预期)。
- PLAN 假设被证伪:低 r 匹配不是对齐残差的主要来源——被剔除的恰是高 r 的 V-CM;r² 加权增大而非减小质心拟合残差(256→276)。原因:匹配 r 度量表达谱相似性,与质心几何一致性无关;且 19 对质心的 Procrustes 残差均值 256 ≈ RMS 354 的 73%,两朵云的形状本身对不上,加权微调旋转无增益。
- 规范化对照:W0C1 vs 对照 W0C0 分数逐位相同 → 评分器位姿不变,规范化只去输出位姿歧义,A/B 半都不应有分差。
- 结论:提交配置 = 父节点几何 + 刚性规范化,预期节点分 ≈ 父节点 59.64(rank3),无提升也无损害;本节点的贡献是排除了坐标侧三个方向。
验证过 / 没验证过
- 验证:proxy 6 配置查分;对照输出与父节点逐位一致;seed 0/1 均通过 vec-check、<5s、<1GB;默认开关下
run.py在完整 proxy 视图跑通。 - 没验证:final 视图(真实括号 31 个同名类型、r 大多=1,加权退化为 count 无关的等权,预期与父节点无差别);伪装视图重跑(代码只读 manifest 数据与时间差,无绝对时间/路径/视图名分支,规范化使输出位姿与输入帧无关,预期通过);B 半分数。
知识来源
未引入新的生物学知识;全部计算(类型匹配 r、质心、残差 σ、z-std)由视图输入现场算出。z 为离散切片、心脏插值保 z 的依据来自方法卡。
下一步建议
坐标侧微调(加权/剔除/z 网格)已系统性排除;shape_scale 的大头是 scale_log_ratio 0.467(预测 RMS 346 vs 真值 ~217),但目标阶段尺寸属禁窗信息,不可用先验硬调。剩余空间在表达侧流形内做法(ANALYSIS 建议的同型 OT 重采样代替线性平移)或接受 mix 近最优。
调研员的计划
| 名称 | 加权Procrustes+PCA规范化改善坐标侧两组 |
|---|---|
| 动机 | 父节点4的local_spatial 53.89比node2的54.03还低0.14,shape_scale 55.08虽已改善但仍是次弱组。ANALYSIS指出增益应来自坐标侧(scale_damp/RMS插值、z处理)而非混合比。k026指出形状评分的PCA对齐不固定行列式,手性翻转引入超噪声方差;当前Procrustes对所有匹配质心等权,低相关匹配(如Endo收4个亚型)引入对齐残差,扭曲局部邻域。 |
| 做法 | 三步改进,均只改坐标后处理,不动混合/表达逻辑: 1. PCA规范化(k026):生成最终坐标后,减质心→PCA旋转→强制det=+1→按第三矩符号定向每轴。对所有候选一致执行,仅去方差。实现约10行numpy。 2. 相关加权Kabsch:Procrustes对齐时,每对匹配质心权重 w=r²(r为匹配时的Pearson相关)。低相关匹配(r≈0.3→w=0.09)贡献大幅降低,高相关匹配(r≈0.85→w=0.72)主导。实现:Kabsch的SVD前对质心坐标乘sqrt(w)。 3. 残差离群剔除:第一轮等权Procrustes后计算每对匹配质心残差,剔除残差>2σ的对,用剩余对做第二轮加权Procrustes。预期剔除1-3对(多对一匹配的Endo类)。 参数:无需搜索,全部由数据决定(r来自已有match_types,σ来自残差分布)。若加权后local_spatial仍无改善,尝试在最终坐标上做1轮同型Laplacian平滑(权重0.05-0.1,仅xy),作为备选。 单输入退路:不变,仍走copy_last分支。 vec-score筛选:先跑提交配置(加权+规范化)对比父节点;再单独跑无规范化(只加权)和无加权(只规范化)确认各自贡献;最后跑无加权无规范化(=父节点)作对照。总查分≤8次。 |
| 风险 | 1) PCA规范化若评分器内部已做类似对齐则无额外收益(但不会变差,因为只去手性方差)——Engineer对比有/无规范化的两次查分即可确认。2) 加权后有效质心对减少(若多数r<0.5),对齐自由度下降可能使shape反降——监控:若加权后匹配对<8,退回等权。3) 残差剔除过激(σ估计偏小)导致对齐对过少——设最少保留5对的下限。4) 改善幅度可能<1分噪声——用3次查分(不同seed)确认方向。 |
代码改动?这个节点的程序和父节点程序的逐行差别:绿色是新增,红色是删除。
对比:父节点版本 15bc86a0b1。改动的文件:solution/METHOD.md +29 −24、solution/README.md +2 −2、solution/run.py +127 −7
diff --git a/solution/METHOD.md b/solution/METHOD.mdindex 1a3b213..776a8a7 100644--- a/solution/METHOD.md+++ b/solution/METHOD.md@@ -1,39 +1,44 @@-# 类型匹配混合插值(matched-align mix)+ 类型位移机制(对照显示代理上有害,提交关闭)+# 相关加权Procrustes+PCA规范化+残差剔除+z网格均衡:PLAN机制全部实现并对照,加权/剔除/z均衡均有害,提交=父节点对齐+PCA规范化(中性) -双括号真实细胞按 t 混合(表达+坐标+组成),新增:用类型均值表达的相关性把上括号类型匹配到下括号类型,匹配名用于 Procrustes 坐标对齐,形状分 53.1→54.5;PLAN 指定的类型位移机制已实现并验证,但在本代理上单调降低总分,提交配置 γ=0。+在父节点4(matched-align mix)上实现 PLAN T2HI-02 的三项坐标机制(r²加权Kabsch、2σ残差剔除、PCA手性规范化),另试 z 切片网格均衡。proxy 查分:加权 59.28、剔除+等权 58.62、count×r² 58.72、z均衡 58.94,全部 ≤ 父节点 59.38;规范化严格刚性、分数不变(59.3757)。按"选择依据是查分结果"提交:加权/剔除/z均衡默认关,规范化默认开。 -## 方法+## 方法与开关 -1. `interp_bracket` 取目标两侧输入(proxy: E8.25_late + E9.5 → t=0.4),单输入/无括号时退化为 copy_last(分层抽样到上限)。-2. **类型匹配**(新):两阶段标注词汇几乎不重叠(33 vs 22 型,仅 5 个同名)。对每对 (下括号类型, 上括号类型) 计算类型均值表达(面板 500 基因)的 Pearson 相关,贪心一对一匹配,r ≥ 0.3、每侧 ≥30 细胞。匹配结果(如 A-CM→IFT-CM r=0.81、Foregut→Lateral FG r=0.81、Great Artery Endoth→Endo r=0.86)符合已知谱系关系;只用表达数据现场计算,不硬编码。-3. **坐标对齐**(新):`align_pair(procrustes)` 用匹配后的共享类型质心做 xy Kabsch(5 个同名 → 最多 21 个匹配质心),z 保号。两朵云缩放到 log 线性目标 RMS(scale_damp=1)。-4. **细胞混合**:`mix_indices` 按 (1−t, t) 从两侧分层抽样(用原始标签,不合并匹配名——合并会使 cell_state 65.9→65.9 但组成失真),总数 `interp_count` 夹到 [min, max]。-5. **类型位移机制**(PLAN T2HI-01,已实现):delta[type] = 匹配对的类型均值差;下括号细胞 +γ·t·delta、上括号细胞 −γ·(1−t)·delta,使两侧落到时间插值的类型均值。开关:`T2_SHIFT_GAMMA`(提交默认 0)、`T2_GAMMA_A/B`、`T2_MATCH_R`、`T2_T`(=0 时整体退化为 copy_last 对照)。+表达/混合/组成逻辑完全未动(expression_change 63.83、cell_state 65.93 与父节点逐位一致)。只改坐标侧: -## 查分结果(proxy,seed 0,A 半)+1. **相关加权 Kabsch**(`weighted_align`,`T2_WEIGHT`/`T2_WMODE`):19 对匹配质心(5 同名 r=1 + 14 相关匹配 r=0.53–0.86),第二轮 Kabsch 用 w=r²(或 count×r²)。诊断:等权残差均值 256.3,r² 加权升到 275.6,旋转差 63°——匹配 r 高不代表质心几何一致(如 V-CM r=0.78 但残差最大,被 2σ 剔除后反而更差)。+2. **残差剔除**(随 `T2_WEIGHT=1` 生效,`T2_WMODE=prune_eq` 可单独测):第一轮等权后剔除残差 > mean+2σ 的对(本 proxy 剔 1 对 V-CM),最少保 5 对,有效对数 <8 时回退等权(PLAN 风险 2/3 的下限都实现)。+3. **PCA 规范化**(`canonicalize`,`T2_CANON`,默认开):最终坐标减质心→PCA 旋转→det=+1→逐轴按第三矩定向。刚性变换,RMS 346.33 不变,seed 0 分数与父节点逐位相同(59.3757 vs 59.38),确认评分器位姿不变;保留它只固定输出位姿的确定性,不指望分数。+4. **z 网格均衡**(`T2_ZEQ`,默认关,PLAN 外补充尝试):两输入 z-std 145/173、切片 38/40,父节点混合输出 77 层交错切片;把两朵云 z 缩到 log 插值公共 std 后 d2_shape 0.0375→0.0398、shape 54.45→53.28,说明交错切片反而更接近真值形状,弃用。+5. 机制关闭对照:`T2_WEIGHT=0 T2_CANON=0 T2_ZEQ=0` 输出与父节点4逐位一致(X、coords allclose=True),得分即父节点 A 半 59.38。单输入退路(copy_last 分支)未动。 -| 配置 | 榜分 | expr | state | shape | local |+## 查分结果(proxy,seed 0,A 半,8 次/额度 20)++| 配置 | 榜分 | shape | local | expr | state | |---|---:|---:|---:|---:|---:|-| **提交:matched-align mix, γ=0** | **59.38** | 63.8 | 65.9 | **54.4** | 53.3 |-| 对照 T2_T=0(机制关,=copy_last) | 48.73 | 44.1 | 51.3 | 49.8 | 49.8 |-| exact-name align mix, γ=0(≈seed mix) | 59.07 | 63.8 | 65.9 | 53.1 | 53.5 |-| matched align + γ_a=γ_b=0.5 | 57.47 | 67.1 | 58.0 | 53.7 | 51.1 |-| matched align + γ_b=1(只移上括号) | 57.12 | 69.3 | 54.8 | 53.7 | 50.8 |-| γ=0.25, r≥0.6 | 58.00 | 65.1 | 62.2 | 52.4 | 52.3 |-| matched align + γ_a=0.5 | 58.44 | 63.4 | 64.5 | 54.4 | 51.5 |+| **提交:等权+PCA规范化(W0C1)** | **59.38** | 54.45 | 53.30 | 63.83 | 65.93 |+| r²加权+剔除+规范化(PLAN 提交案) | 59.28 | 54.06 | 53.29 | 63.83 | 65.93 |+| r²加权+剔除,无规范化 | 59.28 | 54.06 | 53.29 | 63.83 | 65.93 |+| 剔除+等权 | 58.62 | 52.14 | 52.59 | 63.83 | 65.93 |+| count×r²加权+剔除 | 58.72 | 52.62 | 52.49 | 63.83 | 65.93 |+| 等权+规范化+z均衡 | 58.94 | 53.28 | 52.73 | 63.83 | 65.93 | ## 机制生效证据与对照结论 -- 对照 T2_T=0(48.73)vs 提交(59.38):插值机制整体有效,expression_change 44.1→63.8 是最大变化项,符合 PLAN 预期。-- **类型位移子机制(γ)在代理上单调有害**:γ 从 0 → 0.25 → 0.5 → 1,expression_change 升(63.8→69.3)但 cell_state 降更多(65.9→54.8),总分单调下降;γ_a、γ_b、匹配阈值多种组合都试过(上表),无一超过 γ=0。原因推测:对 log 表达做类型级平移使细胞离开真实流形(mmd_u 0.033→0.038),且多对一匹配(Endo 收 4 个上括号内皮亚型)使 delta 混入类型身份差而非时间差。**按"选择依据是查分结果"的规则,提交默认 γ=0**;位移代码保留,`T2_SHIFT_GAMMA>0` 可复现。真实榜(E8.25+E8.75,31 个同名类型,词汇一致)上位移可能不再受匹配噪声污染,值得后续节点在 final 语义下重估——但本节点只按 proxy 证据提交。-- matched-align 的收益(shape 53.1→54.4,d2_shape 0.0393→0.0375、occupancy 0.834→0.848)来自更多可靠质心对;r≥0.6 的子集反而更差(51.6),贪心一对一在 r≥0.3 全集上最稳。+- 机制确实改变了对齐:加权后旋转与等权差 63.1°,剔除 1 对(V-CM,残差 >2σ),四组分中 shape_scale 54.45→54.06/52.14/52.62、local_spatial 53.30→53.29/52.59/52.49,expr/state 逐位不变(未动表达,符合 PLAN 预期)。+- **PLAN 假设被证伪**:低 r 匹配不是对齐残差的主要来源——被剔除的恰是高 r 的 V-CM;r² 加权增大而非减小质心拟合残差(256→276)。原因:匹配 r 度量表达谱相似性,与质心几何一致性无关;且 19 对质心的 Procrustes 残差均值 256 ≈ RMS 354 的 73%,两朵云的形状本身对不上,加权微调旋转无增益。+- 规范化对照:W0C1 vs 对照 W0C0 分数逐位相同 → 评分器位姿不变,规范化只去输出位姿歧义,A/B 半都不应有分差。+- 结论:提交配置 = 父节点几何 + 刚性规范化,预期节点分 ≈ 父节点 59.64(rank3),无提升也无损害;本节点的贡献是排除了坐标侧三个方向。 ## 验证过 / 没验证过 -- 验证:proxy 上 8 个配置的 vec-score;格式 vec-check 通过;seed 0/1 运行确定且 <5s、<1GB;单输入退化路径存在(copy_last 分支)。-- 没验证:final 视图(无权限);γ>0 在 31 同名类型真实括号上的行为;伪装视图重跑(代码只读 manifest 数据与时间差,t 由 `interp_bracket` 时间计算,无绝对时间/路径分支,预期通过)。+- 验证:proxy 6 配置查分;对照输出与父节点逐位一致;seed 0/1 均通过 vec-check、<5s、<1GB;默认开关下 `run.py` 在完整 proxy 视图跑通。+- 没验证:final 视图(真实括号 31 个同名类型、r 大多=1,加权退化为 count 无关的等权,预期与父节点无差别);伪装视图重跑(代码只读 manifest 数据与时间差,无绝对时间/路径/视图名分支,规范化使输出位姿与输入帧无关,预期通过);B 半分数。 ## 知识来源 -- 谱系常识仅用于事后核对匹配合理性(心肌 A-CM/OFT-CM/SV-CM↔IFT-CM/V-CM、内皮 BEC/VEC↔Endo、前肠 Foregut↔Lateral FG、肝 Hepatocytes↔Gut Endoderm、PAM 背/侧↔PAM 亚型);匹配本身完全由输入数据的表达相关现场计算,未使用任何保留阶段信息。-- 方法骨架复用 `src.task2_spatial`(frame/sample/shift/methods);坐标 z 为离散切片、保 z 用 procrustes 的依据来自方法卡。+未引入新的生物学知识;全部计算(类型匹配 r、质心、残差 σ、z-std)由视图输入现场算出。z 为离散切片、心脏插值保 z 的依据来自方法卡。++## 下一步建议++坐标侧微调(加权/剔除/z 网格)已系统性排除;shape_scale 的大头是 scale_log_ratio 0.467(预测 RMS 346 vs 真值 ~217),但目标阶段尺寸属禁窗信息,不可用先验硬调。剩余空间在表达侧流形内做法(ANALYSIS 建议的同型 OT 重采样代替线性平移)或接受 mix 近最优。diff --git a/solution/README.md b/solution/README.mdindex a57f019..3aaf3a1 100644--- a/solution/README.md+++ b/solution/README.md@@ -1,3 +1,3 @@-# T2:heart:val_interp — matched-align mix(节点 4,improve over copy_last)+# T2:heart:val_interp — node 6: matched-align mix + PCA canonicalisation -双括号细胞按 t 混合(表达+坐标+组成),类型均值相关匹配扩展 Procrustes 对齐质心。proxy seed 0:59.38(对照 t=0:48.73)。详见 METHOD.md。+PLAN 的加权Procrustes/残差剔除/z均衡实测均有害(58.6-59.3 < 59.4),提交=父节点4几何+刚性PCA规范化。详见 METHOD.md。diff --git a/solution/run.py b/solution/run.pyindex 8ecb1a5..b54e657 100644--- a/solution/run.py+++ b/solution/run.py@@ -17,10 +17,19 @@ cells per side). Matched names are used both for the displacement and for the Procrustes coordinate alignment, which otherwise has almost no shared centroids to align on. +Coordinate-side refinements (family T2HI-02): the Procrustes alignment of the+matched type centroids is made correlation-weighted (w = r^2, r from the type+matching) with a residual outlier pruning pass (drop pairs whose first-round+residual exceeds mean + 2 sigma, keep at least 5), and the final mixed+coordinate cloud is PCA-canonicalised (rotation with det = +1, per-axis sign+fixed by the third moment) to remove chirality/pose variance.+ Controls (env, mechanism must stay ON in the submitted run): T2_SHIFT_GAMMA=0 -> plain seed-mix behaviour (displacement off) T2_T=0 -> copy of the lower bracket (interpolation off) T2_MATCH_R=1.1 -> disable correlation matching (exact names only)+ T2_WEIGHT=0 -> equal-weight Procrustes (node-4 behaviour)+ T2_CANON=0 -> skip PCA canonicalisation of the output cloud """ from __future__ import annotations@@ -30,7 +39,15 @@ import os import numpy as np -from src.task2_spatial.frame import align_pair, log_interp, rms_radius, scale_to_rms+from src.task2_spatial.frame import (+ align_pair,+ center,+ kabsch,+ log_interp,+ rms_radius,+ scale_to_rms,+ shared_centroids,+) from src.task2_spatial.methods import _jitter, _pack_expr from src.task2_spatial.sample import interp_count, mix_indices, take from src.task2_spatial.shift import apply_type_delta, type_means@@ -46,17 +63,23 @@ from src.task2_spatial.view_io import ( MIN_TYPE = 30 # minimum cells per side for a type to take part in matching/delta -def match_types(A, B, match_r: float) -> dict[str, str]:- """Map B type names onto A type names: exact match, then greedy correlation."""+def match_types(A, B, match_r: float) -> tuple[dict[str, str], dict[str, float]]:+ """Map B type names onto A type names: exact match, then greedy correlation.++ Returns (mapping, rmap): rmap gives the Pearson r behind each *correlation*+ match, keyed by the A-side name (exact-name matches carry no entry, treated+ as r = 1.0 downstream).+ """ la = np.asarray(A.labels).astype(str) lb = np.asarray(B.labels).astype(str) ca = {k: int(v) for k, v in zip(*np.unique(la, return_counts=True))} cb = {k: int(v) for k, v in zip(*np.unique(lb, return_counts=True))} mapping = {k: k for k in cb if k in ca}+ rmap: dict[str, float] = {} rest = [k for k in cb if k not in ca and cb[k] >= MIN_TYPE] cand = [k for k in ca if ca[k] >= MIN_TYPE] if not rest or not cand or match_r > 1.0:- return mapping+ return mapping, rmap ma = type_means(A.X, la) mb = type_means(B.X, lb) P = np.vstack([ma[k] for k in cand]).astype(np.float64)@@ -78,9 +101,88 @@ def match_types(A, B, match_r: float) -> dict[str, str]: used_b.add(i) used_a.add(j) mapping[rest[i]] = cand[j]+ rmap[cand[j]] = r if len(used_b) == len(rest): break- return mapping+ return mapping, rmap+++MIN_KEEP = 5 # never prune below this many centroid pairs+MIN_EFF = 8 # fall back to equal weights if effective pair count drops below this+++def weighted_align(coords_a, coords_b, labels_a, labels_b, rmap: dict[str, float],+ min_count: int = 30, wmode: str = "r2"):+ """z-held Procrustes like align_pair('procrustes'), but the second-round+ Kabsch uses w = r^2 per matched centroid pair and prunes first-round+ residual outliers (> mean + 2 sigma). Falls back to align_pair when there+ are too few pairs or the weighting degenerates."""+ a = center(np.asarray(coords_a, dtype=np.float64))+ b = center(np.asarray(coords_b, dtype=np.float64))+ ca, cb, w, keys = shared_centroids(a, labels_a, b, labels_b, min_count)+ if len(keys) < 3:+ return align_pair(coords_a, coords_b, labels_a, labels_b, "pca")+ rvals = np.array([rmap.get(k, 1.0) for k in keys], dtype=np.float64)+ p, q = cb[:, :2], ca[:, :2]+ # first round: parent behaviour (equal/count weights)+ r1, _, _ = kabsch(p, q, w, allow_reflection=True)+ keep = np.ones(len(keys), dtype=bool)+ if len(keys) >= MIN_EFF:+ res = np.linalg.norm(p @ r1 - q, axis=1)+ thr = res.mean() + 2.0 * res.std()+ k2 = res <= thr+ if k2.sum() < MIN_KEEP:+ k2 = np.zeros_like(k2)+ k2[np.argsort(res)[: max(MIN_KEEP, len(keys) // 2)]] = True+ keep = k2+ if wmode == "count_r2":+ ww = w[keep].astype(np.float64) * rvals[keep] ** 2+ elif wmode == "prune_eq":+ ww = w[keep].astype(np.float64)+ else:+ ww = rvals[keep] ** 2+ n_eff = float(ww.sum() ** 2 / max((ww ** 2).sum(), 1e-12))+ if n_eff < MIN_EFF and keep.sum() >= MIN_EFF:+ ww = w[keep].astype(np.float64) # weighting degenerate: keep equal weights+ r2, _, _ = kabsch(p[keep], q[keep], ww, allow_reflection=True)+ by = b[:, :2] @ r2+ za = ca[keep][:, 2] - np.average(ca[keep][:, 2], weights=ww)+ zb = cb[keep][:, 2] - np.average(cb[keep][:, 2], weights=ww)+ bz = b[:, 2].copy()+ z_flipped = False+ if float(np.dot(za, zb)) < 0:+ bz = -bz+ z_flipped = True+ out_a = np.column_stack([a[:, :2], a[:, 2]])+ out_b = np.column_stack([by, bz])+ info = {+ "align": "procrustes_r2w",+ "n_shared_types": int(len(keys)),+ "n_kept": int(keep.sum()),+ "n_eff": n_eff,+ "dropped": [str(k) for k, kp in zip(keys, keep) if not kp],+ "det": float(np.linalg.det(r2)),+ "z_flipped": bool(z_flipped),+ "z_sign_source": "centroids",+ }+ return center(out_a), center(out_b), info+++def canonicalize(coords: np.ndarray) -> np.ndarray:+ """PCA-canonical pose: centred, rotated onto principal axes with det = +1,+ each axis signed by its third moment. Rigid, so RMS radius is preserved."""+ x = np.asarray(coords, dtype=np.float64)+ x = x - x.mean(axis=0)+ _, _, vt = np.linalg.svd(x, full_matrices=False)+ rot = vt.T+ if float(np.linalg.det(rot)) < 0:+ rot = rot.copy()+ rot[:, -1] *= -1.0+ y = x @ rot+ for ax in range(y.shape[1]):+ if float((y[:, ax] ** 3).mean()) < 0:+ y[:, ax] *= -1.0+ return y - y.mean(axis=0) def main() -> None:@@ -95,6 +197,10 @@ def main() -> None: gamma_b = float(os.environ.get("T2_GAMMA_B", str(gamma))) match_r = float(os.environ.get("T2_MATCH_R", "0.3")) align = os.environ.get("T2_ALIGN", "procrustes")+ weighted = os.environ.get("T2_WEIGHT", "0") not in {"0", "", "false", "False"}+ wmode = os.environ.get("T2_WMODE", "r2")+ canon = os.environ.get("T2_CANON", "1") not in {"0", "", "false", "False"}+ zeq = os.environ.get("T2_ZEQ", "0") not in {"0", "", "false", "False"} t_override = os.environ.get("T2_T") manifest = load_manifest(args.data)@@ -119,15 +225,27 @@ def main() -> None: A = read_stage(args.data, a_entry, genes) B = read_stage(args.data, b_entry, genes) - mapping = match_types(A, B, match_r) # B name -> A name+ mapping, rmap = match_types(A, B, match_r) # B name -> A name lb = np.array([mapping.get(str(x), str(x)) for x in B.labels]) lb_orig = np.asarray(B.labels).astype(str) - aligned_a, aligned_b, _info = align_pair(A.coords, B.coords, A.labels, lb, align)+ if weighted:+ aligned_a, aligned_b, _info = weighted_align(A.coords, B.coords, A.labels, lb, rmap, wmode=wmode)+ else:+ aligned_a, aligned_b, _info = align_pair(A.coords, B.coords, A.labels, lb, align) rms_a, rms_b = rms_radius(A.coords), rms_radius(B.coords) target_rms = log_interp(rms_a, rms_b, t, 1.0) ca = scale_to_rms(aligned_a, target_rms) cb = scale_to_rms(aligned_b, target_rms)+ if zeq:+ # The two stages have different z spreads (slice grids), so mixing them+ # raw interleaves ~2x the slices. Rescale each cloud's z to the common+ # log-interpolated z-std computed from the two inputs only.+ sa, sb = float(ca[:, 2].std()), float(cb[:, 2].std())+ if sa > 1e-8 and sb > 1e-8:+ st = log_interp(sa, sb, t, 1.0)+ ca[:, 2] *= st / sa+ cb[:, 2] *= st / sb n = interp_count(A.n, B.n, t, lo, hi, 1.0) ia, ib = mix_indices(A.labels, lb_orig, t, n, rng)@@ -151,6 +269,8 @@ def main() -> None: cparts.append(cb[ib]) expr = _pack_expr(parts) coords = scale_to_rms(_jitter(np.vstack(cparts), rng), target_rms)+ if canon:+ coords = canonicalize(coords) write_t2(args.out, expr, coords.astype(np.float32), genes, seed=args.seed)
调研来源?调研员查到并用到的知识条目和文献检索结果(只列标题和编号)。
用到的知识库条目
| 编号 | 标题 | 出处 |
|---|---|---|
| k007 | Interval staging and held-out-window filtering of external data | notes/official/来件/virtualembryo.ai/rules.md |
| k024 | World-model evaluation dimensions for state-transition predictors | notes/competition/07_biomedical_world_models.md |
| k026 | Canonicalise predicted 3D coordinates before submission | notes/pitfalls/04_scorer_invariance.md |
分析结果?分析员写的 ANALYSIS.json:改了什么、各组分数怎么变、假设是否成立、经验和下一步建议。
| 改了什么 | 实现了 PLAN 的三项坐标机制(r²加权Kabsch、2σ残差剔除、PCA手性规范化)并加 z 网格均衡,proxy 查分后前三项中加权/剔除/z均衡均有害而默认关闭;提交配置 = 父节点4的等权对齐几何 + 刚性PCA规范化,输出与父节点实质相同,故榜分逐位不变(59.89)。 |
|---|---|
| 各组分数的变化 | cell_state:噪声内(+0.00,66.70) expression_change:噪声内(+0.00,63.90,未动表达逻辑,与父节点逐位一致) local_spatial:噪声内(+0.00,53.89) shape_scale:噪声内(+0.00,55.08;预期由加权/剔除带来的改善被证伪后已关闭) |
| family_id | T2HI-02 |
| 假设是否成立 | 否 |
| 经验 |
|
| mechanism_active | 否 |
| 下一步建议 |
|
对话摘要?每个角色和大模型对话的统计:轮数、工具调用、用时、token 数和最后的回答摘录;原始记录只给路径。
只给统计和最后回答的摘录;完整对话请到原始记录位置里列出的文件看。
分析员
| 角色?调研员写计划、工程师改代码、分析员解读分数、审查员检查作弊。 | 分析员 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数?大模型一共回复了几轮(每轮可以调用多个工具)。 | 2 |
| 工具调用?大模型调用读文件、执行命令等工具的次数,按工具名统计。 | 共 1 次:write 1 |
| 用时 | 不到 1 分 |
| token 数?输入 / 输出(含思考)的 token 数,来自接口返回的用量。 | 输入 12,101 · 输出 936 · 思考 726 |
| 任务(第一行) | 分析节点 n6 的打分结果,写 ANALYSIS.json |
| 最后的回答(摘录) | ANALYSIS.json written |
| 原始记录位置?完整对话记录在 Spark 上的文件路径;看板不复制原始内容。 | /home/spark-longxinyang/vec/runs/formal/20261003-043412-search-t2-heart-interp-g24-D-s1/nodes/6/analyst.jsonl 5 KB /home/spark-longxinyang/vec/runs/formal/20261003-043412-search-t2-heart-interp-g24-D-s1/nodes/6/analyst.stderr |
工程师
| 角色 | 工程师 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数 | 33 |
| 工具调用 | 共 34 次:bash 20、edit 12、read 1、write 1 |
| 用时 | 15 分 |
| token 数 | 输入 63,894 · 输出 13,615 · 思考 14,958 |
| 任务(第一行) | 按计划修改程序:加权Procrustes+PCA规范化改善坐标侧两组 |
| 最后的回答(摘录) | 完成。节点 6 提交内容: **做了什么**:实现 PLAN T2HI-02 全部三项坐标机制(r²加权Kabsch+2σ残差剔除、PCA手性规范化,均带环境开关),另补试 z 切片网格均衡;对照 `T2_WEIGHT=0 T2_CANON=0` 输出与父节点4逐位一致。 **查分结果**(proxy A半,6次/额度20):加权+剔除 59.28、剔除等权 58.62、count×r² 58.72、z均衡 58.94,全部 ≤ 父节点 59.38;PCA规范化严格刚性、分数逐位不变(59.3757)。PLAN 假设被证伪——被剔除的是高 r 的 V-CM,r² 加权反而增大质心残差(256→276)。提交=父节点几何+规范化(默认 WEIGHT=0, CANON=1, ZEQ=0),预期 ≈ 父节点 rank3 59.64,无损害;贡献是排除坐标侧三个方向。 **下一步最值得试**:表达侧流形内位移(同型 OT 重采样代替线性平移,只对高 r 同名类型、小 γ);shape_scale 的主要失分是 scale_log_ratio 0.467(目标尺寸属禁窗信息,不可硬调),坐标微调空间已系统性排除。 |
| 原始记录位置 | /home/spark-longxinyang/vec/runs/formal/20261003-043412-search-t2-heart-interp-g24-D-s1/nodes/6/engineer.jsonl 177 KB /home/spark-longxinyang/vec/runs/formal/20261003-043412-search-t2-heart-interp-g24-D-s1/nodes/6/engineer.stderr |
调研员
| 角色 | 调研员 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数 | 1 |
| 工具调用 | 共 0 次:— |
| 用时 | 1 分 |
| token 数 | 输入 9,880 · 输出 1,005 · 思考 2,119 |
| 任务(第一行) | 为节点 n6(改进,父节点 n4)写改进计划 PLAN.json |
| 最后的回答(摘录) | ```json
{
"name": "加权Procrustes+PCA规范化改善坐标侧两组",
"motivation": "父节点4的local_spatial 53.89比node2的54.03还低0.14,shape_scale 55.08虽已改善但仍是次弱组。ANALYSIS指出增益应来自坐标侧(scale_damp/RMS插值、z处理)而非混合比。k026指出形状评分的PCA对齐不固定行列式,手性翻转引入超噪声方差;当前Procrustes对所有匹配质心等权,低相关匹配(如Endo收4个亚型)引入对齐残差,扭曲局部邻域。",
"approach": "三步改进,均只改坐标后处理,不动混合/表达逻辑:\n1. **PCA规范化**(k026):生成最终坐标后,减质心→PCA旋转→强制det=+1→按第三矩符号定向每轴。对所有候选一致执行,仅去方差。实现约10行numpy。\n2. **相关加权Kabsch**:Procrustes对齐时,每对匹配质心权重 w=r²(r为匹配时的Pearson相关)。低相关匹配(r≈0.3→w=0.09)贡献大幅降低,高相关匹配(r≈0.85→w=0.72)主导。实现:Kabsch的SVD前对质心坐标乘sqrt(w)。\n3. **残差离群剔除**:第一轮等权Procrustes后计算每对匹配质心残差,剔除残差>2σ的对,用剩余对做第二轮加权Procrustes。预期剔除1-3对(多对一匹配的Endo类)。\n\n参数:无需搜索,全部由数据决定(r来自已有match_types,σ来自残差分布)。若加权后local_spatial仍无改善,尝试在最终坐标上做1轮同型Laplacian平滑(权重0.05-0.1,仅xy),作为备选。\n\n单输入退路:不变,仍走copy_last分支。\n\nvec-score筛选:先跑提交配置(加权+规范化)对比父节点;再单独跑无规范化(只加权)和无加权(只规范化)确认各自贡献;最后跑无加权无规范化(=父节点)作对照。总查分≤8次。",
"expected_groups": ["local_spatial", "shape_scale"],
"risks": "1) PCA规范化若评分器内部已做类似对齐则无额外收益(但不会变差,因为只去手性方差)——Engineer对比有/无规范化的两次查分即可确认。2) 加权后有效质心对减少(若多数r<0.5),对齐自由度下降可能使shape反降——监控:若加权后匹配对<8,退回等权。3) 残差剔除过激(σ估计偏小)导致对齐对过少——设最少保留5对的下限。4) 改善幅度可能<1分噪声——用3次查分(不同seed)确认方向。",
"family_id": "T2HI-02",
"mechanism": "用匹配相关系数加权Procrustes对齐(减少低质量匹配的扭曲)+残差离群剔除+PCA手性规范化,改善全局对齐质量的同时保护局部邻域结构。",
"vs_constant_shift": "不移动任何细胞的表达值,不做类型级平移;只改变坐标对齐的权重和后处理规范化。每型常数位移是对表达矩阵加向量,本方案完全不碰表达矩阵。",
"mechanism_evidence": "1) 对比等权vs加权Procrustes后的Procrustes残差均值(预期加权后降低);2) 对比有/无PCA规范化的shape_score方差(多次seed);3) 四组分分别对比:预期shape_scale和local_spatial各+0.5-1.5,cell_state和expression_change不变(因为没动表达和混合);4) 输出被剔除的匹配对名称和残差值,确认是低质量匹配。",
"mechanism_off_control": "设环境变量T2_WEIGHT=0(等权,即父节点行为)且T2_CANON=0(跳过PCA规范化),程序退化为父节点4的提交配置。预期差别:shape_scale和local_spatial回到55.08/53.89附近,总分差≈0。",
"sources": []
}
``` |
| 原始记录位置 | /home/spark-longxinyang/vec/runs/formal/20261003-043412-search-t2-heart-interp-g24-D-s1/nodes/6/researcher.jsonl 4 KB /home/spark-longxinyang/vec/runs/formal/20261003-043412-search-t2-heart-interp-g24-D-s1/nodes/6/researcher.stderr |