换设备后指标下滑,先别急着归因于传感器精度差或人群生理分布不同,这两件事在平均值里是混在一起的。可行的做法是用受控划分把设备变量和人群变量拆开:固定人和佩戴流程,只换设备;固定设备和采集流程,只换人群。只有当通道口径(采样率、量程、佩戴位置、上报字段)逐项核对一致之后,剩余的掉点才有必要往人群差异上想;如果通道本身不一致,那这次比较的其实是两个不同的观测通道,而不是同一套特征在迁移。
先建三组受控划分:同人同设备、同人换设备、换人同设备,让设备变量与人群变量分开变化,再按组看指标,不要只看总体平均值。查设备侧先落到采样率、量程、佩戴位置、上报字段四项逐条对比,来源写清楚是配置文件、采集日志还是标定记录。若通道口径不一致,先做通道级消融,只保留两组共有的通道重跑并冻结同一份切分。能断言的只有这些可核对项,人群生理差异在没有同设备换人对照前只能作为假设。
建三组划分并写清人员与设备构成
三组划分的目的不是把数据凑多,而是让同一份报告里同时有“设备变了”和“人变了”两个方向的对照。建议三组共用同一套标签口径、同一套切分规则(按受试者切,不按片段随机切),并且把每组实际用到的样本量写成具体数值,不要只写“若干”。样本量按你实际采集填,下面表格是记录模板,空着的地方必须补齐后才算可比较。
| 组名 | 人员构成 | 设备构成 | 训练集构成 | 验证集构成 | 分组样本量 | 能回答什么问题 |
|---|---|---|---|---|---|---|
| 同人同设备 | 固定受试者集合 A,佩戴流程与会话时段固定 | 固定设备 X,固件与采集配置不变 | A 中的训练受试者,设备 X | A 中的留出受试者,设备 X | 填训练/验证各自人数与片段数 | 这套通道和流程下的基线水平 |
| 同人换设备 | 与第一组同一批受试者 A | 换成设备 Y,或 X 的同一型号另一台 | A 中的训练受试者,设备 Y | A 中的留出受试者,设备 Y | 填与第一组是否完全同人 | 人员不变时,设备侧差异带来多少变化 |
| 换人同设备 | 新增受试者集合 B,与 A 不重叠 | 与第一组同一台设备 X、同一配置 | B 中的训练受试者,设备 X | B 中的留出受试者,设备 X | 填 B 的人数与片段数 | 设备不变时,人群差异带来多少变化 |
写完这三行还要补两条元信息:一是“同一设备”的判定依据,建议用设备序列号或固件版本号,而不是型号名;二是“同一佩戴流程”的判定依据,建议用采集时的操作记录或现场记录表。这两条不写清楚,第三组和第一组之间的差异就无法排除流程差异。
列出设备侧的可观测差异
设备侧差异要挑能被配置、日志或记录核对的项,不要靠感觉描述“感觉采样更抖”。逐项填下面这张表,每一行都要写明数据来源;来源查不到的项直接标“未确认”,不要猜。
| 对比项 | 设备 X(基线) | 设备 Y | 差异是否需要处理 | 数据来源 |
|---|---|---|---|---|
| 采样率 | 填标称值与实测值 | 填标称值与实测值 | 不一致时需重采样或对齐时间轴 | 采集配置文件、首帧日志时间戳 |
| 量程 | 填单位与上下限 | 填单位与上下限 | 不一致时需确认是否发生削顶/截断 | 设备参数页、标定记录 |
| 佩戴位置 | 填佩戴点、左右侧、松紧描述 | 填同样几项 | 不一致时建议固定后再采一轮 | 现场采集记录、照片或操作表 |
| 上报字段 | 填字段名、单位、有无插值 | 填字段名、单位、有无插值 | 缺字段或单位不同需映射后再比 | 原始日志字段清单、解析脚本输出 |
原始日志通常能直接回答字段层面的问题。可以先用一段通用骨架把两边的通道清单和首帧参数打印出来,字段名按你自己的采集程序替换,不要照抄:
# 通用骨架:打印两台设备的通道清单与首帧参数,用于比对单位与采样率
for dev in dev_a dev_b; do
echo "== $dev =="
python tools/dump_channels.py `--device` $dev `--n` 1 # 输出通道名、单位、采样率、时间戳
done
# 核对要点:通道名能否一一对应、单位是否一致、时间戳间隔是否一致
如果佩戴位置或量程这一步就没对齐,先暂停跨设备比较,把采集流程固定下来重采一批;此时得到的指标差异,说明的是流程差异,不是模型或人群差异。
按设备与人群分组看指标
总体平均值最容易掩盖某一组的崩塌。建议按“人员组 × 设备 × 使用的通道集合”三个维度分组出报告,每个格子同时给样本量和指标分布,不要只给一个均值。
| 人员组 | 设备 | 通道集合 | 样本量 | 指标均值 | 指标分位数(如 P10/P50/P90) | 通道完整率 | 备注 |
|---|---|---|---|---|---|---|---|
| A | X | 全通道 | 基线 | ||||
| A | Y | 全通道 | 同人换设备 | ||||
| B | X | 全通道 | 换人同设备 |
报告生成时把最小样本量当成一个门槛,低于门槛的格子只标注样本量,不参与横向比较,也不写进结论。下面的骨架只是说明分组维度,指标计算和置信区间按你的评估脚本替换:
# 通用骨架:按人员组、设备、通道集合分组出报告
for subject_group in A B:
for device in X Y:
for chans in full_set, common_set:
n = count(subject_group, device, chans)
if n < MIN_N: # MIN_N 按你的验证集规模设门槛,不要跨门槛比大小
report(subject_group, device, chans, n=n, metric=None, note="样本不足")
else:
report(subject_group, device, chans, n=n, metric=eval(...), dist=quantiles(...))
看报告时先看方向再看幅度:同人换设备这一行掉得多,问题更可能在设备侧或通道映射;换人同设备这一行掉得多,问题更可能在人群分布或标签口径。两行都掉,说明两边都要处理,不能只改一个。
做通道级消融排除传感器因素
通道级消融的目的一句话说清:如果只保留两台设备共有的通道、并保持划分不变,指标就回到基线附近,那么此前掉的点很可能来自设备特有通道,而不是人群。做法分三步。
- 求交集定通道:把设备 X 与设备 Y 的通道清单取交集,只保留通道名、单位、采样率都对得上的那些。单位不一致的通道先做单位换算再纳入,换算规则写进配置文件,不要写在临时脚本里。
- 冻结切分:三组共用同一份按受试者划分的文件,记录文件名与内容摘要;重跑时禁止重新随机切分,否则指标变化里混进了切分噪声。
- 重跑并对照:至少跑三种组合——基线(X、全通道)、Y 全通道、Y 共有通道。对照看方向,而不是看小数点后几位。
# 通用骨架:共有通道 + 冻结切分,配置项按你的训练框架替换
channels_common = sorted(set(cfg_x["channels"]) & set(cfg_y["channels"])) # 交集需人工核对单位
split_file = "splits/subject_split_v1.json" # 三组共用,禁止重随机
train(channels=channels_common, split_file=split_file, tag="y_common")
# 对照关系:y_common 应与基线接近;若 y_common 仍明显低于基线,设备特有通道不是主因
结果解释上留一点余地:共有通道重跑后指标恢复,只能说明“设备特有通道是当前可疑来源之一”,还需要确认是通道本身不可用,还是映射或预处理环节出的问题;共有通道重跑后指标依旧下滑,则人群分布、标签口径或采集流程更值得先查。
写清这次能定位到哪一步
排查记录的价值在于把可核对的结论和还没验证的猜测分开写。建议按下面三段落笔,每条都要能指向具体的文件、日志或命令输出。
- 可以断言的结论:两台设备的采样率、量程、上报字段是否一致;佩戴位置是否有现场记录支持;三组划分的人员与设备构成是什么;共有通道集合包含哪些通道;这三组在冻结切分下各自的分组指标与样本量。
- 只能作为假设的部分:掉点主要来自传感器硬件精度差异;人群生理分布导致特征偏移;佩戴松紧或位置变化带来的信号变化——这些在没有同设备换人对照或重复佩戴实验之前,只能写成假设,不能写成结论。
- 需要补数据才能继续验证的环节:同一批人在同一设备上重复佩戴的稳定性数据;设备 Y 上补齐现场佩戴记录与标定记录;把设备特有通道逐个加入/移除的消融结果;样本量不足组补采到门槛以上后再比较。
最后收口一句判断:先分清通道差异还是人群差异,靠的不是换设备后跑一次就下结论,而是三组受控划分加上通道口径逐项核对;只要通道口径还没对齐,任何“精度掉点”的解释都还停留在假设层面。