一只腕带记录压力与两种运动 — Empatica E4 库

三十六人压力 / 三十人有氧 / 三十一人无氧

来源 https://physionet.org/content/wearable-device-dataset/1.0.1/发布时间: 2026-10-28最后更新: 2026-10-28 阅读 12
一只腕带记录压力与两种运动 — Empatica E4 库

信息速览

数据集名称一只腕带记录压力与两种运动 — Empatica E4 库
数据类型时序信号,波形,元数据
规模36 人(压力);30 人(有氧);31 人(无氧)
接入方式https://physionet.org/content/wearable-device-dataset/1.0.1/
AI 就绪度

一个实验室里的普通下午:受试者坐在椅子上,手腕上绑一只塑料腕带,被要求连续做心算减法,做错了要重来;几分钟后休息;再被要求讲一段与自己立场相反的观点;再休息;然后换到功率自行车上,按节拍踩到某个转速,最后几组全力冲刺。整场只有一个传感器在记录——不是脑电帽,不是胸带,也不是多导睡眠仪,而是手腕上那一只 Empatica E4。

这份数据集的全部价值与全部局限,都从「只有一只腕带」这句话里长出来。它的强项是同一批人在三种被严格脚本化的身体状态下留下了可比的四路信号;它的弱项是没有任何第二台设备在旁边做参照,因此所有「真值」都只能靠协议结构和主观评分来间接定义。

如果你要把腕上信号分成「紧张」「在慢骑」「在冲刺」,它是一个起点明确、许可宽松、结构简单到可以半小时摸清的库;如果你需要逐秒的压力曲线、需要心电金标准去做心率误差评估、或者需要跨人群泛化,它给不了,勉强用会得到经不起追问的结论。一屏速览见下表。

维度 内容
官方全名 Wearable Device Dataset from Induced Stress and Structured Exercise Sessions
版本与发布 v1.0.1,2025-06-24(v1.0.0 更早,1.0.1 仅补论文引用)
数据寄存 PhysioNet,RRID:SCR_007345
采集设备 Empatica E4 腕带,单只,戴于非优势手
佩戴部位 腕部一处,无其他部位、无其他设备
受试者 36 人(压力)/30 人(有氧)/31 人(无氧),健康志愿者
状态类别 诱发压力、有氧骑行、无氧冲刺,共三类
原始通道 BVP 64 Hz、ACC 三轴 32 Hz、TEMP 4 Hz、EDA 4 Hz
派生通道 HR 1 Hz、IBI 事件式、tags 按键标记
目录层级 状态/受试者/传感器,三级,每叶七个 CSV
顶层附加文件 人口学表、两版压力自评表、约束说明、字典、校验清单、笔记本
标签形态 阶段级主观评分(零到十)+按键时刻,无逐秒真值
参考设备 无。没有心电、没有呼吸带、没有代谢测量
许可 ODC-BY 1.0,可商用,需署名
访问门槛 无需申请,直接下载
一句话定位 单设备、三状态、受试者内可配对的腕部生理小库

§1 它要解决的具体麻烦

1.1 三类身体状态在同一只腕带上留下的痕迹并不相同

可穿戴算法最常见的失败不是模型不够深,而是训练数据里「紧张」和「运动」混在同一个池子里,模型学到的是「心率升高」,于是把爬楼梯判成焦虑发作。要拆开这两类,最干净的办法是在实验室里人为制造两种升高:一种来自交感神经的心理应激,一种来自骨骼肌的代谢需求。这两条路径都能让心率上去,但皮肤电、皮温与加速度的走向不一样。

这份数据集就是照这个思路搭的。压力段用数学任务与情绪任务诱发,运动段用功率自行车分两档强度:一档是可长时间维持的节律性踩踏,另一档是依靠肌肉内储能的短时全力输出。三类状态被放在同一个人、同一只腕带、同一套采样参数下,等于把「混淆变量」压到了最小可操作的程度。

所以它真正要解决的问题是:给「区分心理应激与运动应激」这件事提供一份受控的、开放的、可复现的最小样本。它不打算解决「压力有多大」这种连续量问题,也不打算解决「在真实生活里怎么判」这种自然场景问题。

1.2 三条常见的错误期待

第一条,以为它是「多设备交叉验证」的数据。看到「可穿戴」和「多模态」两个词,很容易想象成腕表加胸带加指环同时记录。实际情况是只有一只腕带,四个通道全部长在同一个壳体里,走同一块时钟。多模态在这里指通道多,不指设备多。

第二条,以为压力有连续标注。它的压力信息只有两种形态:一是阶段名,二是受试者在每段结束后报出的一个数字。没有逐秒的打分,没有实验者在一旁连续编码,也没有录像可以让后来的人重新标。任何需要「第 137 秒压力值是多少」的任务,在这份数据上都无从训练。

第三条,以为可以直接喂进深度网络。它的文件是厂商导出的原始 CSV,两行非标准表头,采样率从 1 Hz 到 64 Hz 不等,各通道长度不齐,事件标记在另一个文件里,且部分会话被拆成两段。不写几十行胶水代码,连把一路信号对齐到一条时间轴上都做不到。

1.3 它能给到的与给不到的

下面这张表按「你带着什么需求来」组织,而不是按数据集有什么组织。同一份数据,对不同需求的满足度差别很大。

你的需求 它给的 够不够
训练一个区分压力与静息的三分类器 36 人、每人一段压力会话,含多个挑战段与休息段 够,且是它的主用途
区分有氧与无氧强度 30 人与 31 人的自行车方案,含转速与冲刺结构 够,但只有一种运动形式
做受试者内配对分析 30 人同时具备压力与有氧,31 人具备压力与无氧 够,这是它最被低估的优点
评估心率算法误差 只有设备自算的 HR 与 IBI,无参考 不够,必须换库
做逐秒压力回归 阶段级单值评分 不够,粒度差两个数量级
做自由生活场景识别 全为实验室脚本化流程 不够,域差距极大
研究情绪与皮肤电的耦合 有真实/相反观点两段情绪任务 部分够,但情绪类别粗
研究睡眠或昼夜节律 无夜间记录 完全不够
做跨设备泛化 只有 E4 一种硬件 不够
教学演示信号处理全流程 结构简单、有官方笔记本、有校验清单 很够,适合当教材

最后一行值得多说一句。它的教学价值恰恰来自结构上的「土」:两行表头、事件文件、拆分会话、缺陷清单,把真实工程里的脏活压缩进了一个几十分钟就能下载完的包里。

1.4 你的处境与它能帮到的事

你的处境 它能帮你什么 下一步该做什么
手上只有腕表项目,老板要「情绪识别」的原型 给出压力段与非压力段的可分性下限 先用它验证特征,再找带自然场景标注的库扩域
在做人工胰腺或糖尿病管理的前置研究 提供压力与运动两类干扰源的受控样本 注意它没有血糖,需另配连续血糖监测数据
需要证明「皮肤电对心理应激敏感」 同人同设备的压力段与休息段对照 用受试者内检验,不要跨人比较绝对值
想复现某篇论文的分类结果 论文对应的正是这份数据 先确认划分方式,再决定是否可比
要设计自己的压力诱发实验 可直接借用它的阶段脚本与自评量表 参照它的缺陷清单避开同样的坑
在教一门生理信号处理课 完整的小型真实数据,含已知错误 把缺陷文件当作课堂练习素材
需要多设备同步数据做融合 无法满足 转向含胸带或多设备的腕部库
要做运动强度处方的算法 只有两种强度档,且是自行车 补跑步、抗阻、间歇等其他形式

1.5 一句话判断

它是一份「把混淆变量关进笼子里」的小数据:受控到可以放心做因果式对照,也窄到只能回答「实验室里这三种状态能不能分开」这一个问题。

这句话里有两层意思需要同时成立才有用:受控,所以差异只来自生理本身;窄,所以问法一变,受控性立刻变成局限性。

1.6 不适合谁:四条边界

第一条边界,不适合任何需要心电参考的任务。心率变异性、房颤筛查、心率误差评估,这三类工作在方法学上都要求有一个独立的、可信度更高的测量作为对照。这份数据一个都没有,它的 IBI 是从光电容积信号里由厂商算法推出来的,本身就是被评估对象。

第二条边界,不适合需要人群多样性的任务。受试者年龄集中在青年段,全部为健康志愿者,没有慢病人群,没有老年人,没有服药记录。把在这里训练的模型直接推到慢病或老年人群,属于没有依据的外推。

第三条边界,不适合需要自然情境的任务。全部数据在实验室内、在实验者监督下、在明确的时间脚本中采集。真实生活里的压力是弥散的、伴随移动的、持续数小时的,与这里的十分钟任务段不是同一个分布。

§2 数据构成与规格

2.1 三层目录与十个顶层项

顶层一共十项:一个主目录,九个文件。主目录下按状态分三支,状态目录下按受试者分叶,叶子目录里放七个传感器 CSV。这个结构简单到可以用一句话说清,但也正因为简单,所有元信息都散落在顶层那几个小文件里。

层级 名称 内容 规模
第 0 层 项目根 一个目录加九个文件 十项
第 1 层 Wearable_Dataset 三个状态目录 三支
第 2 层 STRESS/AEROBIC/ANAEROBIC 受试者目录 37/30/31 个叶子
第 3 层 S01…S18、f01…f18 七个传感器 CSV 每叶七个
旁挂 Data_Dictionary.csv 七个通道的码表 七行
旁挂 subject-info.csv 人口学与完成情况 36 行
旁挂 Stress_Level_v1.csv/v2.csv 两版协议的主观评分 18 行各一
旁挂 data_constraints.txt 采集异常逐条说明 三段
旁挂 README.txt 文件用途与阅读顺序 纯文本
旁挂 LICENSE.txt 许可全文 约两万字节
旁挂 SHA256SUMS.txt 逐文件校验值 七万余字节
旁挂 Wearable_Dataset.ipynb 可视化演示笔记本 约 34 MB

叶子数的差异值得留意。压力目录下有 37 个叶子而不是 36 个,原因是 f14 的会话因蓝牙中断被拆成 f14_a 与 f14_b 两个目录。同理,有氧目录里 S11 被拆成两段,无氧目录里 S16 被拆成两段。所以「叶子数」不等于「会话数」,更不等于「人数」。任何按目录计数写的脚本,都会在这三处多算。

主目录用下划线加驼峰,叶子用大写状态名,编号用小写前缀加两位数字。混排意味着大小写敏感的文件系统上必须原样保留路径,不能靠模糊匹配。

2.2 字段与文件的完整字典

官方给的 Data_Dictionary.csv 只有七行,覆盖七个传感器文件。它没有覆盖顶层的九个辅助文件,这部分信息要从 README 与正文说明里拼。下表把两部分合在一起。

文件名 通道含义 采样率 单位 文件形态
BVP.csv 血容量脉搏,光电容积原始波形 64 Hz 无 两行表头+单列
ACC.csv 三轴加速度 32 Hz 1/64 g 两行表头+三列
EDA.csv 皮肤电活动 4 Hz 微西门子 两行表头+单列
TEMP.csv 外周皮温 4 Hz 摄氏度 两行表头+单列
HR.csv 由 BVP 派生的平均心率 1 Hz 次每分 两行表头+单列
IBI.csv 逐搏间期 事件式 秒 单行表头+两列
tags.csv 按键事件时刻 事件式 UTC 时刻 单行表头+两列
Data_Dictionary.csv 上述七项的码表 不适用 不适用 七行表
subject-info.csv 性别、年龄、身高、体重、是否规律运动、协议版本、三项完成情况 不适用 厘米/千克 36 行表
Stress_Level_v1.csv 第一版协议八阶段自评 不适用 零到十 18 行宽表
Stress_Level_v2.csv 第二版协议七阶段自评 不适用 零到十 18 行宽表
data_constraints.txt 采集异常说明 不适用 不适用 分段文本
README.txt 文件清单与阅读建议 不适用 不适用 纯文本
LICENSE.txt ODC-BY 1.0 全文 不适用 不适用 纯文本
SHA256SUMS.txt 逐文件哈希 不适用 不适用 两列文本
Wearable_Dataset.ipynb 信号可视化与读取示例 不适用 不适用 笔记本

七个传感器文件里,只有 ACC 是三列,只有 IBI 与 tags 是事件式,只有 IBI 没有采样率行。这些不整齐是厂商导出格式的原样,不是整理者的疏忽,但也意味着通用的读取函数必须按文件分支。

加速度的单位是最容易出错的一处。文件里的整数以 1/64 g 为刻度,量程为负二到正二 g,也就是说原始整数除以 64 才得到以 g 为单位的加速度值。直接把整数当 g 用,会让后续所有基于加速度幅值的阈值判断失效,而且错得很安静——数值仍在合理区间内,只是差了六十四倍。

通道 原始整数范围(约) 物理量换算 常见误用
ACC 负一百二十八至正一百二十八 除以 64 得 g 未换算即算模长,阈值全错
EDA 取决于皮肤电导水平 微西门子,无需换算 与温度通道混淆列序
TEMP 二十至四十 摄氏度,无需换算 当作核心体温使用
BVP 有符号整数,幅度随灌注变化 无物理单位,仅用于形态与时序 当作血压或血氧
HR 四十至二百 次每分,无需换算 当作逐搏真值而非滑动平均
IBI 零点三至两秒 秒,已是物理量 与 HR 混用导致重复计权

2.3 一条记录的完整解剖

一个叶子目录里的七个文件共享同一个起点:会话开始时的 UTC 时刻。前两行是元信息,第三行起才是数据。这个设计让文件自带时间基准,不需要额外的会话清单,但也让所有标准读取函数默认的第一行表头行为失效。

以血容量脉搏为例,文件开头大致是下面的样子。第一行是会话起点,第二行是采样率,第三行起是逐个采样点的原始值。

1,700,000,000.000000
64.000000
-13
-12
-12
-14
-15
#-- 其余略:自第三行起为逐采样点整数,长度约为会话秒数乘以 64

理解这三行就理解了整套数据的读取约定。第一行那个数是 Unix 时间戳的浮点形式,虽然后缀带小数,但精度只到秒级;第二行是该文件的采样率,除 IBI 与 tags 外都存在;第三行起没有列名,靠文件名的通道含义与列序区分。

事件文件是例外。它没有采样率行,只有表头加若干行事件,每行两列:第一列是相对于会话起点的秒数,第二列是事件码。这里的「事件」在物理上就是受试者按了一下腕带上的按钮,同时设备的状态指示灯会亮一下。官方说明里明确写了这一点,所以 tags 的含义不是「实验者标注的阶段标签」,而是「按钮被按下的时刻」。

对齐七路信号只需三步:读首行拿绝对起点,读次行拿采样率,用「索引除以采样率」得相对秒数。稳妥做法是以 BVP 的首行为基准,其余文件按各自起点差平移。

2.4 两版协议与阶段结构

受试者被分成两批,对应两版协议。这个分组不是随机的,也不是并行的,而是先后两期:第一期的十八人编号以大写的 S 开头,第二期的十八人编号以小写 f 开头。两期的协议阶段集合与顺序都不同。

阶段 第一版顺序 第二版顺序 任务性质
基线 第 1 段 第 1 段 静坐,建立个体基线
Stroop 色词干扰 第 2 段 无 认知冲突
第一次休息 第 3 段 第 3 段 恢复
心算任务 第 4 段 第 2 段 社会评价性心算
第二次休息 第 5 段 第 6 段 恢复
真实观点陈述 第 6 段 第 4 段 情绪表达
相反观点陈述 第 7 段 第 5 段 情绪诱发核心
连续减法 第 8 段 第 7 段 持续认知负荷

第一版是八段,第二版是七段。第二版删掉了 Stroop,并把心算任务提到休息之前,把两次休息的位置重新排列。这意味着「第几段」这个索引在两版之间不可比,必须按阶段名对齐,不能按序号对齐。

阶段名在文件里的写法也不统一:有的带空格,有的用词不同。读取时应以列位置为准再显式映射到统一阶段码,不要依赖字符串匹配。

对齐维度 第一版 第二版 能否直接合并
阶段数 8 7 否,缺 Stroop
阶段顺序 Stroop 在心算前 无 Stroop 否
休息位置 第 3、第 5 第 3、第 6 否
情绪段位置 第 6、第 7 第 4、第 5 否
心算位置 第 4 第 2 否
减法位置 第 8 第 7 否
自评表文件 v1 v2 否,列数不同
性别构成 全男 十七女一男 否,与版本重合

这张表是整份数据里最该先看的一张。任何跨版本的分析,只要涉及「第 N 段」,都会同时引入协议差异与性别差异,而这两者在数据里完全共线,无法用统计手段拆开。可行的做法只有两种:要么只在单一版本内做分析,要么把版本当成固定效应显式建模并承认残余混淆。

2.5 与同类腕部资源的字段差异

把这份数据和常见的腕部信号库放在一张表里,差异立刻清楚:它没有心电,没有呼吸,没有血氧,没有血糖,也没有视频或问卷量表这类辅助模态。它换来的是三状态受控对照与受试者内配对。

资源 设备数 佩戴部位 参考设备 状态类别 主观标签
本库 1 腕 无 压力/有氧/无氧 阶段级零到十
非脑电五路库 1 腕 无 放松/体力/认知/情绪 分段自评
腕部光电容积运动库 多传感器 腕+胸 有胸带心电 步行/跑步/骑行 无
腕部睡眠库 1 腕 有夜间多导睡眠 睡眠分期 由多导判读给出
消费级穿戴认知负荷库 3 腕+头 无 认知负荷/静息 任务条件即标签
智能手表心率配对库 6 腕 有心电贴片 静息/深呼吸/步行/打字 条件标签
可穿戴第一人称视频库 1 头戴 无 日常活动 自报告问答

这张表的读法是看「参考设备」那一列:写着「有」的能回答「测得准不准」,这一列空着的只能回答「分不分得开」。两类问题评价方法不同。

§3 它是谁的数据

3.1 版本、标识与寄存关系

这份数据在 PhysioNet 上以项目形式寄存,带独立 DOI 与 RRID。版本号到小数点后两位,当前是一点零点一。一点零点零是首次发布,一点零点一只做了一件事:把配套论文的引用补进发现区。官方发布说明原文的意思很明确——除引用外没有改动任何内容。

这一点对使用者的实际意义是:如果你在一点零点零时下载过,一点零点一不必重新下载全部数据,数据内容一致。但如果你要引用,应当引用你实际使用的那个版本的 DOI,因为两个版本的 DOI 后缀不同。

标识项 值 用途
项目短名 wearable-device-dataset URL 路径
当前版本 1.0.1 引用与校验
发布日 2025-06-24 时间定位
数据 DOI 10.13026/he0v-tf17 版本级引用
资源编号 RRID:SCR_007345 平台级标识
论文 DOI 10.1038/s41597-025-04845-9 方法学引用
论文期刊 Scientific Data 同行评议出处
许可 ODC-BY 1.0 使用条件

两个 DOI 各管一头:数据 DOI 锁定版本,论文 DOI 指向方法与结果,引用时应同时给出。

3.2 作者与采集背景

作者共四位,按官方页面的署名顺序是 Andrea Hongn、Facundo Bosch、Lara Prado、Paula Bonomini。团队位于阿根廷布宜诺斯艾利斯,这一点可以从论文署名与作者既往会议论文的出处交叉确认,官方项目页本身没有单列机构行。

采集动机写在背景部分,而且写得相当直白:目标不是做通用的压力识别,而是为人工胰腺的控制算法服务。逻辑链条是——一型糖尿病患者的血糖控制依赖外源胰岛素,而急性压力会通过激素途径升高血糖,运动则会按强度不同分别降低或升高血糖;如果闭环系统能提前知道「用户此刻在应激」还是「在运动」,胰岛素给量的策略就能相应调整。

这条动机链解释了很多设计选择。为什么一定要有有氧与无氧两档?因为两者的血糖走向相反。为什么一定要有压力段?因为压力的血糖效应与运动不同,却同样通过心率等通道干扰算法。为什么受试者是健康人而不是患者?因为第一步只需要验证「三态可分」,患者数据涉及更多伦理与安全问题。

最后一条值得称赞。多数小数据集遇事故会静默删掉问题会话,使用者在建模时才发现异常却查不到原因;这里全部保留并附文本说明。代价是必须先读那份文本。

3.3 编号体系里的信息

受试者编号不是随机的。S 开头的是第一期,f 开头的是第二期;数字从一到十八连续。这个编号体系里至少藏了三条信息:期次、协议版本、以及性别的大致分布。

第一期的十八人全为男性,第二期的十八人中有十七名女性、一名男性。这个构成不是设计出来的平衡,而是招募结果。它在数据里造成的后果是:性别与协议版本完全共线。任何声称「发现性别差异」的分析,在这份数据上都无法与「协议差异」区分开。

另外,编号不等于完成情况。有人在某状态上标短横线(没做),有人标星号(做了但有特定问题),这些标记在人口学表的完成列里,必须逐行读。

3.4 论文与数据的分工

论文发表在 Scientific Data,摘要给出的核心信息有三层:数据构成、采集方式、以及一组验证性分类结果。验证用的是若干机器学习算法,其中梯度提升树在三项任务上分别达到九成三、九成一、八成四。

这三个数字在本站语境里要小心使用。它们是作者用自己数据做的可行性验证,证明「三态可分」这个命题成立,不是给后来者的性能基线。原因有二:其一,摘要层面没有交代划分是按受试者还是按片段;其二,特征工程与超参数没有在摘要中给出。按片段随机划分时,同一受试者的相邻窗口高度相关,指标会显著偏高。

正确的用法是把它当「这份数据能支撑什么任务」的说明书,而不是「该达到多少分」的排行榜。要建可比基线,得自己定义留一受试者划分,并写清窗口长度、重叠率与特征集。

论文给出的 用途 不该当作
三态人数 规模核对 独立队列数
设备与采样率 结构核对 性能相关参数
压力对静息 93% 可行性证据 跨研究基线
有氧对无氧 91% 可行性证据 跨研究基线
四分类 84% 可行性证据 跨研究基线
公开可用声明 访问依据 许可条款本身

3.5 版本演进与稳定性判断

从一点零点零到一点零点一,只增加了引用信息。这个动作很小,但透露了一个判断:维护者不打算频繁改动数据内容。对一个体量不大、采集已经结束的数据集来说,这是合理的姿态——原始信号一旦采集完成就不会再变,后续版本只应修文档。

对使用者的影响是稳定性预期较高,不必担心半年后重跑脚本发现文件变了;同时也要接受文档层面的小问题大概率不会被修。

§4 质量与特色

4.1 唯一性来自「同一批人」而不是「更多数据」

这份数据在规模上毫无优势。三十几个人、每人几十分钟、四路信号,放在任何一个大模型时代的数据清单里都排不上号。它真正的稀缺性在于构造:同一批人在受控条件下经历三种状态,且三种状态在生理上有明确的分野。

这种构造带来的直接好处是可以用受试者内设计。传统做法是「压力组对对照组」,两组人不同,个体差异(基础心率、皮肤电导水平、体温基线)全部变成噪声,需要靠更大的样本量去平均掉。受试者内设计把个体差异变成固定效应,每个人自己当自己的对照,同样的样本量能换来高得多的统计效率。

第二个好处是设备与佩戴位置固定。跨设备比较时,硬件差异、佩戴松紧、采样时钟都会污染结论。这里全部相同,唯一的变量是状态与时间。

第三个好处是协议脚本固定。每个受试者经历的任务序列一致(同版本内),时长由脚本控制,「第几分钟在做什么」是可推的。

构造特征 带来的能力 代价
同一批人多状态 受试者内配对,效率高 样本绝对量小
单设备单部位 排除硬件与位置差异 无法做跨设备泛化
固定脚本 阶段边界可推 任务顺序效应无法排除
实验室环境 变量可控 生态效度低
原始格式保留 无整理偏倚 清洗成本转嫁给使用者
异常全记录 可追溯 需要人工甄别

4.2 标签的真实层级

初学者最容易犯的错,是把目录名当标签、把 tags 当标注、把自评当连续真值。这三件事在层级上完全不同,必须分开说。

目录名给出的是会话级标签,粒度最粗:这个叶子属于压力、有氧还是无氧。它不告诉你会话内部哪一段是什么。

tags 给出的是事件时刻,粒度最细,但语义最弱:它只说明按钮被按了一下,不说明那一刻发生了什么。要知道具体是什么事件,必须回到协议脚本,按事件顺序推断。

自评表给出的是阶段级标签,粒度居中,语义最强:它明确说「这个阶段受试者报了几分」。但它只存在于压力会话,运动会话没有对应的主观量表。

标签来源 粒度 语义强度 覆盖范围
目录名 会话 弱(只分三类) 全部会话
tags.csv 事件时刻 很弱(仅按键) 部分会话,取决于是否按键
Stress_Level_v1/v2 阶段 强(零到十) 仅压力会话
subject-info 的完成列 会话 中(做了/没做/有异常) 全部受试者
data_constraints.txt 会话或子段 强(具体问题) 仅异常项

三层标签叠起来的实际可用粒度是「阶段」。也就是说,这份数据天然适合做阶段级分类:给一段窗口,判断它属于基线、休息、挑战还是运动。它不适合做逐秒定位,因为最强的那层标签本身就只有一个值覆盖整段。

4.3 已记录的缺陷清单

官方在约束文件里逐条写了七处问题,分三个状态列出。这份清单的完整度是这份数据的一个加分项,但也意味着使用者必须先读它再动手,否则会在莫名其妙的数值上浪费几个小时。

状态 受试者 问题 后果
压力 S02 厂商导出文件含重复段 某一时刻之后所有信号重复,须截断
压力 f07 腕带保护盖未拆 只有皮肤电与加速度有效
压力 f14 蓝牙中断 基线在 a,其余在 b,须拼接
有氧 S03 提前结束 只到九十转,方案不完整
有氧 S07 提前结束 只到九十五转,方案不完整
有氧 S11 蓝牙中断 前段在 a,末段一百一十转在 b
有氧 S12 未做 该状态无数据
无氧 S01 心搏间期文件为空 该会话无法用 IBI
无氧 S06 提前结束 缺最后一个冲刺段
无氧 S16 蓝牙中断 两段各含两个冲刺

4.4 案例:f07 那顶没拆的保护盖

这是整份数据里最有教学价值的一个事故,值得单独拆开看。

f07 是一位二十出头的女性受试者,第二版协议,三项状态全部完成。她的人口学完成列在压力一项上标了单星,星号对应的脚注是「腕带佩戴位置错误」。约束文件的描述更具体:保护盖始终没有被取下,罩住了光电容积与温度两个传感器,因此只有皮肤电与加速度两路数据有效。

这个事故的形态很典型:数据文件一个不少,七个 CSV 全在,文件长度正常,表头正常,甚至数值也不是全零——光电容积传感器在遮罩下仍会输出随环境光与轻微漏光变化的波形,温度传感器仍会输出壳体附近的温度。如果不看约束文件,这段数据看起来完全可用。

真正的信号在数值的分布形态里:脉搏波失去了搏动性的周期性,温度曲线几乎是一条随室温缓慢漂移的直线。这是一种「安静地错」的失败模式,比全零或文件缺失更难发现,因为它不会触发任何自动化检查。

§4.4 的案例说明了一个通用原则:在这类厂商导出的原始数据上,文件存在性与数值非空都不能作为可用性的判据。必须建立基于生理合理性的检查——脉搏信号要有可检测的搏动周期,皮肤电要有可辨识的应激响应,温度要落在人体外周温度的合理带内。任何一项越界,都要回到约束文件里找对应解释。

§4.4 的案例还有第二层含义:它揭示了「异常记录」这份文档的使用方式。文档不是免责声明,而是一份先验知识清单,读它花十分钟,能省掉后面几小时的困惑。当你发现某个受试者的特征在所有模型里都表现为离群点时,第一反应应该是翻这份清单,而不是怀疑代码。

在预处理脚本里,最稳的做法是把这份清单编码成显式的排除规则,而不是靠人记住。§4.4 的案例里,f07 的压力会话应当只保留皮肤电与加速度两路,其余两路在读取时就置为不可用,并在结果里记录这个决定。

4.5 特色之二:压力段的情绪设计

压力协议不是单一任务,而是一串任务加间歇。基线之后是认知冲突(第一版)或直接的限时心算,中间穿插两次休息,最后两段是情绪表达任务:先说真实观点,再被要求说相反观点。

两次休息的插入同样有讲究。它给同一个体提供了恢复基线,使「挑战段相对相邻休息段的增量」成为比绝对值更稳健的指标。这对皮肤电尤其重要:绝对水平个体间差异极大,跨人比较几乎无意义。

§5 取数与接入

5.1 访问与许可的实际含义

访问政策写得很干脆:任何人都可以访问,只要遵守许可条款。没有申请流程,没有数据使用协议弹窗,没有机构邮箱限制。这一点比很多同类资源友好。

许可为开放数据共享署名一点零版。它的核心义务只有一条:署名。可以商用、可以修改、可以再分发,只要保留归属声明。这与常见的非商业许可不同,后者会直接堵死产品化路径。

许可维度 本库的规定 实践含义
商用 允许 可用于商业模型训练
修改 允许 可重采样、可衍生特征
再分发 允许 可镜像,需保留署名
署名 必须 需给数据 DOI 与论文
相同方式共享 不要求 衍生库可用其他许可
专利授权 未涉及 不构成专利许可

需要提醒的是,开放数据许可覆盖的是数据库权利,不覆盖受试者的人格权与隐私权。数据虽已按去标识规范处理,但在产品化场景里仍应做合规评估,这一步不能因为许可宽松就跳过。

5.2 把整包取下来

文件托管在 PhysioNet 的受保护路径下,但访问不设门槛,普通的递归抓取即可。抓之前先看一眼体积:主数据不大,真正占空间的是那个三十多兆的笔记本,它内嵌了可视化输出。

#-- 建立工作目录并进入
mkdir -p ~/data/e4-stress && cd ~/data/e4-stress

#-- 递归抓取整个版本目录,保留相对路径
wget --recursive --no-parent --no-host-directories --cut-dirs=3 \
  https://physionet.org/files/wearable-device-dataset/1.0.1/

#-- 校验:逐文件比对哈希,输出中不应出现 FAILED
sha256sum --check SHA256SUMS.txt --quiet && echo "ALL OK"

第二步的路径裁剪参数很关键。 PhysioNet 的目录层级较深,直接递归会得到一长串无意义的中间目录,用裁剪参数把前缀去掉之后,本地结构与远端一致,后续脚本里的相对路径才好写。

5.3 解码两行表头

标准的表格读取函数默认第一行是列名。这份数据的每个传感器文件第一行是会话起点、第二行是采样率,直接读会把两行元信息当成数据的第一行,或者在类型推断时报错。

import io
from pathlib import Path
import numpy as np
import pandas as pd

def read_e4_csv(path: Path, ncols: int = 1):
    """读取 Empatica E4 导出的单通道或多通道 CSV。

    返回 (起始 UTC 秒, 采样率 Hz, 形状为 (n, ncols) 的浮点数组)。
    IBI 与 tags 不走这里,它们没有采样率行。
    """
    with path.open("r", encoding="utf-8", errors="replace") as fh:
        start_utc = float(fh.readline().strip())
        fs = float(fh.readline().strip())
    arr = pd.read_csv(path, skiprows=2, header=None).to_numpy(dtype=float)
    if arr.shape[1] != ncols:
        raise ValueError(f"{path.name}: 期望 {ncols} 列,实际 {arr.shape[1]} 列")
    return start_utc, fs, arr

root = Path("wearable-device-dataset/1.0.1/Wearable_Dataset")
leaf = root / "STRESS" / "S01"
t0, fs_bvp, bvp = read_e4_csv(leaf / "BVP.csv", 1)
_, fs_acc, acc = read_e4_csv(leaf / "ACC.csv", 3)
_, fs_eda, eda = read_e4_csv(leaf / "EDA.csv", 1)

#-- 换算:加速度原始整数以 1/64 g 为刻度
acc_g = acc / 64.0
print(t0, fs_bvp, fs_acc, fs_eda, bvp.shape, acc_g.shape, eda.shape)

这段代码里没有做重采样,也没有做滤波,是刻意的。重采样的目标频率取决于下游用什么特征,滤波的截止频率取决于信号类型,两者都不该由读取函数替使用者决定。读取只负责把「厂商格式」变成「内存里的数组」,其余交给特征层。

5.4 用事件标记切段

事件文件只有两列,第一列是相对秒数,第二列是事件码。切段的做法是把相邻两个事件之间的区间当作一个阶段,再按协议脚本给它命名。

def load_events(path: Path):
    df = pd.read_csv(path, header=0)
    df.columns = ["offset_s", "code"]
    df = df.sort_values("offset_s").reset_index(drop=True)
    return df

STAGES_V1 = ["baseline", "stroop", "rest1", "mental_math",
             "rest2", "real_opinion", "opposite_opinion", "subtract"]
STAGES_V2 = ["baseline", "mental_math", "rest1",
             "real_opinion", "opposite_opinion", "rest2", "subtract"]

def segments(events: pd.DataFrame, protocol: str):
    names = STAGES_V1 if protocol == "V1" else STAGES_V2
    bounds = list(events["offset_s"]) + [np.inf]
    out = []
    for i in range(min(len(names), len(bounds) - 1)):
        out.append((names[i], bounds[i], bounds[i + 1]))
    return out

ev = load_events(leaf / "tags.csv")
for name, a, b in segments(ev, "V1"):
    print(f"{name:18s} {a:8.2f} -> {b if np.isfinite(b) else -1:8.2f}")

这里有两个隐含假设必须写明。其一,事件个数与阶段个数相等,且第一个事件就是第一阶段的开始。其二,事件的排列顺序与协议顺序一致。这两个假设在多数会话上成立,但在漏按或多按的会话上会失效,因此切完之后应当打印每段时长,用生理上的合理区间去人工核对一遍。

事件个数与阶段数不符的情况,处理策略取决于研究问题。如果只是需要一个粗粒度的「挑战段对休息段」划分,可以合并;如果要精确到「第几段是第几段」,就必须逐会话核对,不能自动兜底。

5.5 把主观评分接回去

压力评分放在两个宽表里,行是受试者,列是阶段名,值是零到十的整数或半整数。宽表的好处是一眼能看全,坏处是要转成长表才能和信号连接。

def load_stress_level(path: Path, protocol: str) -> pd.DataFrame:
    df = pd.read_csv(path, index_col=0)
    df.index = df.index.astype(str).str.strip()
    long = df.reset_index().melt(id_vars="index",
                                 var_name="stage_raw",
                                 value_name="stress_0_10")
    long = long.rename(columns={"index": "subject"})
    long["stage"] = (long["stage_raw"].str.strip().str.lower()
                     .str.replace(" ", "_"))
    long["protocol"] = protocol
    return long.dropna(subset=["stress_0_10"])

lv1 = load_stress_level(Path("wearable-device-dataset/1.0.1/Stress_Level_v1.csv"), "V1")
lv2 = load_stress_level(Path("wearable-device-dataset/1.0.1/Stress_Level_v2.csv"), "V2")
levels = pd.concat([lv1, lv2], ignore_index=True)
print(levels.groupby(["protocol", "stage"])["stress_0_10"].size().unstack(fill_value=0))

连接时最需要注意的是阶段名的规范化。两版表格的列名不完全一致,有的带空格,有的用词不同(例如两次休息的列名相同、需要靠位置区分)。稳妥做法是先按位置重命名,再合并,而不是依赖字符串清洗。

另一个注意点是缺失。第二期的后五名受试者只有压力会话,因此他们的有氧与无氧在人口学表里是短横线;在评分表里他们仍有完整一行,因为压力是做了的。这两处的「缺失」含义不同,不能统一处理。

5.6 构造一个最小可用的窗口表

把四路信号归一到同一时间网格,再切成固定长度的窗口,得到一张可以直接喂给分类器的表。下面的做法以一秒为网格,取皮肤电与温度的均值、加速度的模长统计、脉搏波的斜率统计。

GRID_HZ = 1.0

def to_grid(arr: np.ndarray, fs: float, grid_hz: float = GRID_HZ) -> pd.DataFrame:
    n = arr.shape[0]
    t = np.arange(n) / fs
    idx = np.floor(t * grid_hz).astype(int)
    df = pd.DataFrame(arr)
    df["_bin"] = idx
    return df.groupby("_bin").mean()

def window_features(leaf: Path) -> pd.DataFrame:
    _, fs_bvp, bvp = read_e4_csv(leaf / "BVP.csv", 1)
    _, fs_acc, acc = read_e4_csv(leaf / "ACC.csv", 3)
    _, fs_eda, eda = read_e4_csv(leaf / "EDA.csv", 1)
    _, fs_tmp, tmp = read_e4_csv(leaf / "TEMP.csv", 1)

    g_eda = to_grid(eda, fs_eda).rename(columns={0: "eda"})
    g_tmp = to_grid(tmp, fs_tmp).rename(columns={0: "temp"})
    acc_g = acc / 64.0
    mag = np.linalg.norm(acc_g, axis=1, keepdims=True)
    g_acc = to_grid(mag, fs_acc).rename(columns={0: "acc_mag"})
    g_bvp = to_grid(bvp, fs_bvp).rename(columns={0: "bvp"})

    feat = pd.concat([g_eda, g_tmp, g_acc, g_bvp], axis=1).interpolate(limit_direction="both")
    feat["eda_diff"] = feat["eda"].diff().fillna(0.0)
    feat["bvp_absdiff"] = feat["bvp"].diff().abs().fillna(0.0)
    feat["acc_std_5s"] = feat["acc_mag"].rolling(5, min_periods=1).std().fillna(0.0)
    return feat

table = window_features(root / "AEROBIC" / "S01")
print(table.head())

这段特征工程是刻意粗糙的,只用来演示管线通不通。真正的建模里,皮肤电应当先做相位成分分解,把 tonic 与 phasic 分开;脉搏波应当先做峰值检测,再算逐搏间期;加速度应当先分离重力分量,再算活动强度。这三步都是标准流程,笔记本里有可视化,但没有给出可直接复用的实现。

必须强调的一点:窗口切分必须在「受试者」这一层做隔离。同一受试者的相邻窗口相关性极高,若随机划分,测试集信息会泄漏进训练集,指标会虚高。正确做法是留一受试者或按受试者分组做交叉验证。

§6 与库内词条的关系

6.1 关系图谱

库内与可穿戴相关的词条已经形成一个不小的簇,但彼此的分工是清楚的:有的按设备分,有的按佩戴部位分,有的按任务分,有的按模态分。本文对象的坐标是「单设备、腕部、三状态、含主观评分」。

把它放进这个簇里,最容易被误认成两个对象:一是同样使用 Empatica E4 的那份认知负荷数据,二是同样以腕部多路信号刻画神经状态的那份非脑电数据。这两者与本文对象的关系最近,也最需要在选型时区分。

关系类型 库内词条 关系强度 区分要点
同设备 消费级穿戴认知负荷库 强 设备重叠,任务与设备数不同
同部位同思路 非脑电五路腕上信号库 强 都是腕部多路+分段协议
同任务域 腕部光电容积运动库 中 都做运动,一个有参考设备
同部位 腕部睡眠库 弱 一个做夜间,一个做白天
同对象不同模态 智能手表心电库 弱 一个有单导联心电,一个完全没有
同对象不同问题 智能手表心率配对库 弱 一个评误差,一个分状态
同属可穿戴 第一人称健康视频库 很弱 一个是视频,一个是波形

6.2 逐项区隔

下表按库内七个相邻词条逐一说明差异,判断依据是各自的标题与副标题所述对象,不含对内容的猜测。

词条 它的对象 与本文的重叠 实质差异 是否重合
noneeg 二十人、腕上五路、八段协议的非脑电神经状态库 都是腕部多路、都用分段协议、都关注应激 它把放松、体力、认知、情绪做成并列类别,用于神经状态划分;本文只做压力与两种运动强度,且运动是功率自行车上的结构化方案,另含逐搏间期与按键事件 否
sleep-accel 三十一人、一人一夜、手表加速度配多导睡眠判读 同为腕戴、同样用加速度 它是夜间睡眠分期,标签来自多导睡眠判读这一独立金标准;本文全为日间清醒状态,且无任何参考设备 否
wrist 八人、十九条记录、腕部光电容积配胸带心电的运动会话 都做运动中的腕部脉搏 它有胸部心电作参考、采样率高出数倍、以波形质量与心率误差为核心;本文无参考设备、以三态分类为核心、并多出皮肤电与皮温 否
ecg-capable-smartwatches 具备单导联心电能力的智能手表 同为腕部可穿戴 它以手表采集的心电为核心模态;本文完全没有心电通道,心律失常类任务不适用 否
consumer-grade-wearables 三台设备(含 E4)同步采集的认知负荷数据 设备重叠、都用 Stroop、都做实验室任务 它是多设备横向比较,目标是「消费级能不能测认知负荷」,仅一个任务族;本文单设备,目标是压力与运动三态,含功率自行车方案与逐阶段自评 否
bigideaslab-step-hr-smartwatch 六款设备与心电贴片的配对心率误差 都是腕部心率 它的核心是肤色与误差的配对比较,有心电贴片作参考;本文无参考设备,且不涉及肤色 否
ego-wear-bench 可穿戴第一人称相机与健康问答 同属可穿戴范畴 它是一人称视频加自报告问答,模态是图像与文本;本文全部为数值波形 否

七项逐一核对之后,没有一项与本文对象构成实质重合。最接近的是消费级穿戴认知负荷库:两者都用了 Empatica E4,都在实验室里用 Stroop 类任务诱发负荷。但差异是结构性的——那份额外引入两台设备做横向比较,任务族只有认知负荷一类;本文只有一台设备,任务族扩展到压力诱发与两种运动强度,并提供了逐阶段的主观评分与两种协议的完整脚本。前者回答「设备之间是否一致」,后者回答「状态之间是否可分」。这两个问题的数据设计要求不同,不能互相替代。

最容易被误判为重合的是非脑电五路库。两者都是腕部多路加分段协议,初看像一个东西的两次采集。分开看有三处硬差异:它的类别体系是放松、体力、认知、情绪四类并列,目标是神经状态划分;本文的类别是压力、有氧、无氧,目标是应激源类型与运动强度的区分。它有五路信号(含血氧),本文是四路(无血氧)。它的协议是单次八段,本文是两次采集、两版协议、每人三次会话。三者叠加,构成的是不同的实验设计,不是同一对象的重复收录。

6.3 检索路径

从本站的标签体系出发,到达本文对象有三条路径。第一条是设备路径:可穿戴与行为 → 生理信号 → 单设备腕部。第二条是任务路径:压力检测 → 诱发应激 → 实验室协议。第三条是模态路径:时序信号 → 光电容积脉搏波 → 腕部。

入口 路径 到达后如何确认
按设备 可穿戴与行为 → 腕部 看设备数是否为 1
按任务 生理信号 → 应激诱发 看是否有运动对照
按模态 时序信号 → 脉搏波 看是否有心电参考
按许可 开放许可 → 可商用 看是否 ODC-BY
按规模 小样本 → 数十人 看是否受试者内设计

§7 质量评估与局限性

7.0 阅读本节前的一个前置校正

在给分之前必须先校正一个常见的错位:很多人会拿「大规模公开基准」的评分框架来套这份数据,然后因为样本量小、标注粗、格式不规范而给它低分。这个套法本身是误判。

原因在于两类数据的用途不同。大规模基准的目标是「训练一个能泛化的模型」,规模与标注密度直接决定上限;这份数据的目标是「验证一个受控假设是否成立」,它的价值在设计的干净程度,不在体量。用前者的尺子量后者,等于用体检报告的页数评价一次外科手术。

所以下面的评分按「作为受控实验数据」的标准给,六个维度分别是身份与可追溯、访问与许可、结构与格式、语义与字典、质量与已知缺陷、版本与治理。同一份数据如果按「大规模训练集」的标准评,结构与质量两项会显著更低,那是另一套尺子,不在这里混用。

7.1 五维评分与量表对照

先给一个粗粒度的五维判断,再给细项。

维度 分数(五分制) 理由 主要扣分处
设计干净度 4.5 同人同设备三状态,受试者内可配对 性别与协议版本共线
结构规范性 3.0 目录清晰,但表头非标准、通道不齐 需自写读取层
标注可用性 2.5 只有阶段级评分,无逐秒真值 运动段无主观标签
文档透明度 4.5 异常逐条记录,版本说明清楚 单位与列序散落
复用门槛 4.0 开放许可、无申请、结构简单 需自行清洗与切窗

按站内 DAIMS 二十四项量表(六域各四项)逐项对照,结果如下。这个量表评的是「作为 AI-ready 数据集」的成熟度,与上面的五维视角互补。

DAIMS 域 得分 判定依据
身份与可追溯 4/4 版本号、数据 DOI、论文 DOI、资源编号齐全
访问与许可 4/4 无门槛访问,许可明确到版本,允许商用
结构与格式 2/4 格式统一为 CSV,但表头非标准、无统一模式文件
语义与字典 3/4 有通道字典,但单位与列序说明分散,无阶段码表
质量与已知缺陷 4/4 异常逐条记录,含具体行号与影响范围
版本与治理 3/4 有版本与变更说明,但无更新政策与问题反馈渠道
合计 20/24 强在治理透明,弱在结构规范

7.2 逐维展开

五个维度的扣分点其实同源:凡涉及「厂商原样」的地方,标准工具都要特判;凡涉及标签的地方,粒度都受阶段级设计封顶。设计干净度拿高分是因为受试者内对照已经做到这个体量能做的最好,剩下半分扣在性别与协议共线,那是采集时无法挽回的结构问题,不是整理疏忽。反过来,文档透明度一项说明信息齐全与信息易得是两件事——这份数据做到了前者,把后者留给了使用者。

7.3 已知的、可枚举的偏差

偏差分三类:采样偏差、测量偏差、标注偏差。三类都可以逐条枚举,不需要靠推测。

采样偏差指受试者构成与目标人群的偏离。这份数据的受试者是青年健康志愿者,年龄集中在二十岁上下,无慢病、无用药记录。第一期全男,第二期几乎全女。这些构成决定了它的结论不能外推到老年、儿童、慢病人群。

偏差类别 具体项 影响 能否校正
采样 青年健康志愿者 不能外推到老年与慢病 否
采样 第一期全男、第二期近全女 性别与版本共线 否
采样 单中心、单一批次 无法评估中心效应 否
测量 腕部脉搏运动伪影 高转速段波形失真 部分,靠信号质量指标剔除
测量 皮温受环境温度影响 跨会话绝对值不可比 部分,用相对变化
测量 加速度量程正负二 g 冲刺峰值可能饱和 否
测量 单设备无参考 无法估计测量误差 否
标注 单题零到十分自评 分辨率粗、受社会赞许影响 否
标注 按键标记阶段边界 存在秒级系统延迟 部分,按时长核对
标注 两版任务顺序不同 顺序效应与版本效应混杂 否

这张表读下来会得到一个略显悲观的结论:绝大多数偏差不可校正。这是小规模实验数据的常态。正确的应对不是试图校正,而是在报告里显式声明适用范围,并把「不可校正」本身作为结论的一部分。

7.4 外部验证矩阵

判断一份数据是否可信,一个实用的办法是看它能不能被外部证据交叉确认。下面按四类外部证据列出确认情况。

外部证据类型 本库的情况 确认程度
独立发表的同行评议论文 有,Scientific Data 高,方法描述可核
平台级质量审核 有,PhysioNet 项目页含发布说明 中,平台不做内容审计
第三方复现报告 未见公开的独立复现 低,需自行验证
与其他库的交叉样本 无重叠受试者 不适用
数据完整性校验 有逐文件哈希 高,可验证传输完整性
与厂商参考算法的对照 无 不适用

7.5 它为何能持续:一个明确的科学问题加上一个宽松的许可

一份小数据集能否长期被使用,通常不取决于它有多大,而取决于两件事:它回答的问题是否还会有人问,以及别人用它的成本是否足够低。

第一个条件它满足得很好。「心理应激与运动应激在腕部信号上能否分开」这个问题不会因为模型变大而消失,反而随着可穿戴设备普及变得越来越实际。只要还有人在做腕上情绪识别,就需要一份受控的对照数据来验证特征是否有生理依据。

第二个条件也满足。开放许可允许商用,无申请流程,结构简单到可以半小时摸清,还附了一份可视化笔记本。这些加起来把首次使用的门槛压得很低。

持续因素 现状 风险
问题仍然有人问 腕上应激识别持续有需求 若消费级设备转向多模态融合,单设备数据价值下降
使用成本低 开放许可、无申请、结构简单 无
未过度加工 保留原始格式 使用者需自建管线,可能转向更现成的库
有同行评议背书 有期刊论文 无独立复现,说服力受限
版本稳定 只做过文档级更新 无更新政策,长期可能失联

§8 生态位与历史

8.1 从实验室应激范式到公开数据

用实验室任务诱发应激并同步记录生理信号,这套做法在心理生理学里已有几十年历史:心算、公众演讲、冷压、色词干扰,各对应不同应激路径。这些范式长期停留在小样本论文里,数据不公开,方法难复现。

转折出现在可穿戴普及之后:设备便宜、佩戴方便、采样率够用,采集门槛下降,公开数据集开始出现。早期一批多集中在单一状态,规模在十几到几十人之间,设备以胸带和腕带为主。本文对象处在这条线的中段——比单状态数据多一层对照,比大规模多设备数据少很多规模。

8.2 与胸带参考类数据的分工

在腕部信号这个领域里,有一条清晰的分水岭:有没有独立的参考设备。有参考的库可以回答「测得准不准」,没有参考的库只能回答「分不分得开」。

8.3 从血糖动机反推的设计约束

这份数据的采集动机是为人工胰腺服务,这条链解释了三个乍看奇怪的选择。必须有运动段,否则无法回答「这个心率升高是紧张还是刚爬了楼」;运动要分两档,因为有氧倾向降血糖、无氧因儿茶酚胺释放倾向升血糖,处置方向相反,只做一档等于抹平最关键的分歧;保留原始波形而非只给特征,则是因为下游特征集未定,只给特征会锁死选择空间。

动机 对应的设计 若缺少会怎样
区分应激源 压力段与运动段并列 无法归因心率升高
血糖方向相反 有氧与无氧分档 两类运动被合并
下游特征未定 保留原始波形 锁死特征空间
医学场景需可追溯 保留并记录异常 异常无法解释
需要个体基线 每段前后插休息 无法算相对增量

8.4 生态位判断

把这份数据放在整个可穿戴数据生态里,它的位置是「小而干净的三态对照」。它不是任何任务上最好的选择,但在「验证腕部信号能否区分心理与代谢两类应激」这个具体问题上,它目前是最直接的选择之一。

§9 使用指引

9.1 三种角色的路径

不同角色进入这份数据的目的不同,最短路径也不同。下面按角色给出建议,避免所有人从「下载全量再探索」开始。

角色 首要目标 建议路径 预计卡点
算法研究者 建立三态分类基线 先读约束文件 → 写读取层 → 留一受试者划分 窗口泄漏
产品工程师 判断腕上能否做应激识别 先看笔记本 → 抽三人验证 → 再全量 误把实验室结论当产品结论
教学设计者 讲清信号处理全流程 直接用缺陷案例做课堂素材 数据量小,需自行扩展示例
临床研究者 寻找应激与代谢的客观指标 需另配血糖数据,本库只作对照 无临床终点
数据工程师 建可复用的读取管线 从两行表头与事件文件入手 通道不齐、分段缺失

对算法研究者来说,最重要的纪律是先定划分再调模型。受试者只有三十余人,留一交叉的每折只有三十个左右样本,指标方差很大,报告时应给每折结果与区间,而不是只给均值。

对产品工程师来说,最重要的是别把实验室可分性当成产品可用性。实验室里的三类状态干净、分段、有明确起止;产品里的状态连续、混合、边界模糊。中间还差一个自然场景验证。

9.2 一条最短的可用流程

下面的流程把前面几节的做法串起来,从下载到得到一个可评估的基线,全程只用标准库加 pandas 与 scikit-learn。

from pathlib import Path
import numpy as np
import pandas as pd
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.model_selection import LeaveOneGroupOut
from sklearn.metrics import balanced_accuracy_score

ROOT = Path("wearable-device-dataset/1.0.1/Wearable_Dataset")
EXCLUDE = {("STRESS", "f07"), ("AEROBIC", "S12")}  #-- 依约束文件排除

def session_table(state: str, subject: str) -> pd.DataFrame:
    leaf = ROOT / state / subject
    if not leaf.is_dir():
        return pd.DataFrame()
    feat = window_features(leaf)
    feat["state"] = state
    feat["subject"] = subject
    return feat

rows = []
for state_dir in sorted(ROOT.iterdir()):
    if not state_dir.is_dir():
        continue
    for leaf in sorted(state_dir.iterdir()):
        if (state_dir.name, leaf.name) in EXCLUDE:
            continue
        rows.append(session_table(state_dir.name, leaf.name))

data = pd.concat([r for r in rows if not r.empty], ignore_index=True)
data = data.dropna()
X = data[["eda", "eda_diff", "temp", "acc_mag", "acc_std_5s", "bvp_absdiff"]].to_numpy()
y = data["state"].to_numpy()
groups = data["subject"].to_numpy()

logo = LeaveOneGroupOut()
scores = []
for tr, te in logo.split(X, y, groups):
    clf = HistGradientBoostingClassifier(max_depth=3, random_state=0)
    clf.fit(X[tr], y[tr])
    scores.append(balanced_accuracy_score(y[te], clf.predict(X[te])))
print(len(scores), float(np.mean(scores)), float(np.std(scores)))

三点说明。第一,排除名单来自约束文件,不是凭经验删的。第二,特征只有六个,是演示用的最小集合,不是为了刷分。第三,评估用留一受试者加平衡准确率,因为三类的窗口数量不均衡,普通准确率会被最多的那一类主导。

跑出来的数字大概不会高。这是正常的:一秒粒度的六个粗糙特征,加上三十余人的样本量,能到七成上下已经说明信号里有信息。要提升,方向是特征而不是模型——皮肤电的相位分解、脉搏波的形态学特征、加速度的频域能量,这三类都比换更强的分类器更有用。

9.3 引用方式

引用要覆盖两件事:数据本身与产生数据的方法。数据引用用版本化 DOI,方法引用用论文 DOI。两者都不可或缺。

#-- 数据引用(APA 风格,官方给出)
Hongn, A., Bosch, F., Prado, L., & Bonomini, P. (2025).
Wearable Device Dataset from Induced Stress and Structured Exercise Sessions
(version 1.0.1). PhysioNet. RRID:SCR_007345.
https://doi.org/10.13026/he0v-tf17

#-- 方法引用
Hongn, A., Bosch, F., Prado, L., & Bonomini, P. (2025).
Wearable physiological signals under acute stress and exercise conditions.
Scientific Data. https://doi.org/10.1038/s41597-025-04845-9

如果衍生作品要再分发,需在显著位置保留归属声明,并注明是否修改。ODC-BY 允许修改,但要求说明修改内容。实践中建议附一个变更说明,写明做了哪些重采样、滤波或重标注。

§10 AI 使用声明

项目 说明
数据来源 PhysioNet 公开项目页与其文件目录,2026 年 10 月访问
核实方式 逐页读取官方项目页、文件清单、许可页与随包辅助文件
数字口径 仅采用官方页面与论文摘要给出的规模、结构、边界三类数字
未做之事 未下载全量数据,未做任何分布统计或字段级审计
推断标注 协议阶段性质、运动方案细节等由官方措辞推出的内容已注明推断
已知不确定 论文摘要未交代划分方式,相关性能数字不作基线使用
内容性质 本篇为数据集说明性整理,不构成医学建议或合规意见
更新责任 官方版本变化后,本篇需按新版本复核数字与引用

常见误读

说法 实际 证据
它是多设备同步采集 只有一只腕带,四路通道同壳体 官方方法节只列 E4 一台设备
有胸带心电作参考 没有任何参考设备 项目页与论文摘要均无第二设备
36 人是三个队列之和 36 人是压力人数,有氧 30、无氧 31 均为其子集 人口学表三项完成列
压力有逐秒标注 每阶段一个零到十的分数 两版评分表均为宽表
tags 是实验者标注的阶段标签 是受试者按下按钮的时刻 数据说明明确写为按键事件
采样率统一 从 1 Hz 到 64 Hz 不等 通道字典逐项列出
可以直接用读取函数读入 前两行是时间与采样率 数据说明第一段
加速度单位是 g 原始整数以 1/64 g 为刻度 数据说明与字典
三个状态目录就是三个独立数据集 三十人是同一批人,可做受试者内配对 人口学表交叉
论文的九成准确率是跨人基线 摘要未交代划分方式 论文摘要原文

FAQ

它是「可穿戴设备多模态信号」的合集吗?
不是合集。设备只有 Empatica E4 一种,戴在非优势手手腕上,四个通道全部长在同一壳体里。多模态指的是同一设备内部的四类传感原理(光电容积、皮肤电、热电堆、加速度),不是多台设备、多个部位。

有没有同步的参考设备?
没有。官方页面与论文都没有提到第二台设备。心率与心搏间期是设备固件从血容量脉搏推算的,等于用算法结果验证算法本身。需要心电金标准的任务必须换库。

三个数字是三个独立队列吗?
不是。三组人数是同一批三十六人中完成各状态的人数。第一版十八人三项全做,第二版有十三人三项全做、五人只做压力,因此有三十人具备压力加有氧的配对、三十一人具备压力加无氧的配对。

主观评分能当连续标签用吗?
不能。每阶段结束后采集一个数值,附着在阶段上而非时间点上,一段只有一个值。适合做阶段级分类目标,不能插值成逐秒曲线,也不能当密集回归标签。

为什么有 S 和 f 两套编号?
代表两期采集。S 开头是第一期,用第一版协议,全为男性;f 开头是第二期,用第二版协议,十七女一男。两期的阶段集合与顺序不同,跨期分析必须按阶段名对齐而非按序号。

第二版为什么少了 Stroop 段?
官方未说明原因。可以确认的是第二版从八段变为七段,删去了 Stroop,并把心算提到第一次休息之前。因此「第二段」在两版里指的不是同一件事。

f07 那条数据为什么不能用全部通道?
她的腕带保护盖没有取下,罩住了光电容积与温度两个传感器。约束文件明确写明只有皮肤电与加速度有效。文件仍在、长度正常,但脉搏波形失去搏动性,必须按约束文件排除。

会话被拆成 a 和 b 怎么办?
按时间顺序拼接,注意两段各自有独立的首行起点,拼接时要用首行差值对齐相对时间,不能直接纵向堆叠。涉及拆分的三处分别是压力目录的 f14、有氧目录的 S11、无氧目录的 S16。

能不能直接复现论文里的准确率?
要谨慎。摘要给出了三个任务的数字,但没交代划分是按受试者还是按片段随机。按片段随机会让同一人的相邻窗口同时进训练与测试,指标显著偏高。复现时应自行做留一受试者并报告方差。

许可允许商用吗?
允许。ODC-BY 1.0 只要求署名,不限制商用、修改与再分发,也不要求衍生作品沿用同一许可。但许可覆盖的是数据库权利,不覆盖人格权,产品化仍需自行合规评估。

需要注册或申请吗?
不需要。访问政策写明任何人都可以访问,只要遵守许可。文件可直接下载,无申请表单、无机构限制。

术语表

术语 含义 在本库中的位置
E4 Empatica 公司的研究级腕带型号 唯一采集设备
BVP 血容量脉搏,光电容积描记的原始波形 64 Hz 单列文件
PPG 光电容积描记术,BVP 的测量原理 设备内部传感
EDA 皮肤电活动,反映交感汗腺活动 4 Hz 单列文件
TEMP 外周皮温 4 Hz 单列文件
ACC 三轴加速度 32 Hz 三列文件
1/64 g 加速度的原始整数刻度 需除以 64 换算
HR 由 BVP 派生的平均心率 1 Hz 单列文件
IBI 逐搏间期,相邻心搏的时间差 事件式两列文件
tags 按键事件时刻 事件式两列文件
协议版本 第一版或第二版任务脚本 人口学表的列
无氧冲刺 短时全力输出,依赖肌内储能 无氧会话的末段
有氧稳态 可长时间维持的节律性运动 有氧会话的主体
受试者内设计 同一人接受多种条件的设计 本库的核心优势
ODC-BY 开放数据共享署名许可 本库许可
DOI 数字对象标识 数据与论文各一个

附录 A:核心数字核对表

项 值 来源 来源层级
压力受试者 36 官方摘要 官方页面
有氧受试者 30 官方摘要 官方页面
无氧受试者 31 官方摘要 官方页面
受试者总数 36 人口学表行数 官方文件
第一期人数 18 人口学表 官方文件
第二期人数 18 人口学表 官方文件
压力叶子目录 37 目录清单 官方文件
有氧叶子目录 30 目录清单 官方文件
无氧叶子目录 31 目录清单 官方文件
每叶传感器文件 7 文件说明 官方页面
顶层项数 10 目录清单 官方文件
脉搏采样率 64 Hz 通道字典 官方文件
加速度采样率 32 Hz 通道字典 官方文件
皮温采样率 4 Hz 通道字典 官方文件
皮肤电采样率 4 Hz 通道字典 官方文件
心率采样率 1 Hz 通道字典 官方文件
第一版阶段数 8 评分表列数 官方文件
第二版阶段数 7 评分表列数 官方文件
自评量表范围 零到十 评分表取值 官方文件
当前版本 1.0.1 项目页 官方页面

附录 B:数字的来源分层

层级 含义 本篇中的例子
一级:官方页面 项目页、说明页、目录清单直接给出 三类人数、采样率、文件数、许可
二级:官方随包文件 下载包内的字典、人口学表、约束文件 每叶七文件、异常清单、完成情况
三级:论文摘要 同行评议论文的摘要文本 三项分类指标、设备描述
四级:据官方措辞推断 由原文表述合理推出,非明文 运动方案的分级转速结构、阶段任务性质
未核实 官方未给、也未做外部取证 采集年份的精确区间、场地条件

第四级的两项需要特别标注。运动方案的分级结构是从约束文件里「只到九十转」「只到九十五转」「最后一个一百一十转区块」这类措辞推出来的,官方没有给出完整的方案表。阶段任务的性质(例如把心算理解为社会评价性任务)是从参考文献与范式常识推出,官方只给了阶段名。

第五级的采集年份,只能确定在论文投稿之前,项目页与摘要都没有给出精确起止。本篇写作时按「早于 2025 年」处理,不写具体年份。

附录 C:完整参考文献

编号 文献 用途
1 Hongn A, Bosch F, Prado L, Bonomini P. Wearable Device Dataset from Induced Stress and Structured Exercise Sessions (version 1.0.1). PhysioNet. 2025. doi:10.13026/he0v-tf17 数据本体引用
2 Hongn A, Bosch F, Prado L, Bonomini P. Wearable physiological signals under acute stress and exercise conditions. Scientific Data. 2025. doi:10.1038/s41597-025-04845-9 方法学与结果
3 Hongn A, Prado LE, Bosch F, Bonomini MP. Wearable device dataset for stress detection. 2024. doi:10.1007/978-3-031-61137-7_49 前期可行性结果
4 Hongn A, Bosch F, Prado LE, Ferrández JM, Bonomini MP. Non-invasive recording of physiological variables under stress conditions and aerobic and anaerobic physical activity. 2024. doi:10.1007/978-3-031-61973-1_4 采集方案描述
5 Stroop JR. Studies of interference in serial verbal reactions. J Exp Psychol. 1935;18:643-62 色词干扰范式来源
6 Pruessner JC, Hellhammer DH, Kirschbaum C. Low self-esteem, induced failure and the adrenocortical stress response. Pers Individ Dif. 1999;27:477-89 社会评价应激范式
7 Inbar O, Bar-Or O, Skinner JS. The Wingate Anaerobic Test. Human Kinetics; 1996 无氧冲刺方案来源
8 Empatica. E4 wristband data. 厂商技术文档 通道定义与采样率
9 Pollard T, Moody BE, Lehman L, et al. PhysioNet as a global platform for biomedical research. Nature Health. 2026 平台引用规范

附录 D:任务代码

把三态分类的最小实验固化成脚本,便于重复。脚本默认按受试者分组、按会话聚合,输出每折结果与汇总。

from pathlib import Path
import json
import numpy as np
import pandas as pd
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.model_selection import LeaveOneGroupOut
from sklearn.metrics import balanced_accuracy_score, confusion_matrix

ROOT = Path("wearable-device-dataset/1.0.1/Wearable_Dataset")
EXCLUDE = {("STRESS", "f07"), ("AEROBIC", "S12")}
FEATS = ["eda", "eda_diff", "temp", "acc_mag", "acc_std_5s", "bvp_absdiff"]

def build() -> pd.DataFrame:
    frames = []
    for state_dir in sorted(p for p in ROOT.iterdir() if p.is_dir()):
        for leaf in sorted(p for p in state_dir.iterdir() if p.is_dir()):
            if (state_dir.name, leaf.name) in EXCLUDE:
                continue
            feat = window_features(leaf)
            if feat.empty:
                continue
            feat = feat.assign(state=state_dir.name, subject=leaf.name)
            frames.append(feat)
    if not frames:
        raise RuntimeError("没有读到任何会话,请检查 ROOT 路径")
    return pd.concat(frames, ignore_index=True).dropna()

def run(data: pd.DataFrame) -> dict:
    X = data[FEATS].to_numpy(dtype=float)
    y = data["state"].to_numpy()
    g = data["subject"].to_numpy()
    folds = []
    for tr, te in LeaveOneGroupOut().split(X, y, g):
        clf = HistGradientBoostingClassifier(max_depth=3, random_state=0)
        clf.fit(X[tr], y[tr])
        pred = clf.predict(X[te])
        folds.append({
            "held_out": str(g[te][0]),
            "n_test": int(len(te)),
            "balanced_acc": float(balanced_accuracy_score(y[te], pred)),
        })
    scores = np.array([f["balanced_acc"] for f in folds])
    return {
        "n_windows": int(len(data)),
        "n_subjects": int(len(np.unique(g))),
        "mean_balanced_acc": float(scores.mean()),
        "std_balanced_acc": float(scores.std()),
        "folds": folds,
    }

if __name__ == "__main__":
    result = run(build())
    Path("e4_baseline.json").write_text(
        json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
    print(result["n_subjects"], result["mean_balanced_acc"], result["std_balanced_acc"])

脚本里刻意没做的事有三件:没有做超参数搜索、没有做类别加权、没有做通道级质量筛选。这三件事都会显著改变结果,但都会引入额外的自由度,让「基线」变得不可比。第一版应当尽量朴素。

输出的每折结果应当保留,因为三十余人的留一交叉里,单折方差很大,只报均值会掩盖分布。若多数折在七成附近、少数折明显偏低,那些低折对应的受试者值得回查约束文件。

附录 E:如果只记五件事

第一,它只有一只腕带。Empatica E4 戴在非优势手,四路原始通道全部同壳体,没有任何参考设备。

第二,它是三种状态而不是三份数据。压力、有氧、无氧在同一批三十六人身上采集,三十人与三十一人分别具备与压力的配对。

第三,它的标签只到阶段级。压力有零到十的自评,运动没有主观量表,逐秒真值不存在。

第四,它的格式是厂商原样。两行表头、通道不齐、事件单列、三处会话被拆分,读取层必须自己写。

第五,它的边界是实验室与青年健康人。可商用、可修改、需署名,但不能外推到老年、慢病与自然场景。

编辑说明

本篇按数据集说明性文本处理,不承担审计职能。所有数字取自官方项目页、官方随包文件与论文摘要三处,凡属推断均在正文或附录 B 中标注。文中的评分是编辑侧的量表判断,用于横向比较,不构成对原研究的方法学评价。

若官方发布新版本,本篇的版本号、文件清单与阶段结构三处需优先复核。协议阶段的英文列名以随包评分表为准,正文中的中文阶段名是译名,不具规范效力。


相关数据集导航

以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:

  • ppg-dalia — 共享标签:生理信号 / 可穿戴传感 / 步态与运动
  • culm — 共享标签:生理信号 / 可穿戴传感 / 步态与运动
  • nesfdb — 共享标签:生理信号 / 可穿戴传感 / 步态与运动
  • plantar — 共享标签:生理信号 / 可穿戴传感 / 步态与运动
  • semg-gait-31subjects — 共享标签:生理信号 / 可穿戴传感 / 步态与运动
  • pamap2 — 共享标签:生理信号 / 可穿戴传感 / 步态与运动
  • mhealth — 共享标签:生理信号 / 可穿戴传感 / 步态与运动
  • uci-har — 共享标签:生理信号 / 可穿戴传感 / 步态与运动
  • wearable-exercise-frailty — 共享标签:生理信号 / 可穿戴传感 / 步态与运动
  • body-sway-music-vr — 共享标签:生理信号 / 可穿戴传感 / 步态与运动

导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

返回 AI-Ready 数据集