个人基线:为什么你的「正常」不是人群均值

人群均值是一个没有你参与的平均数。个人基线是你自己最近这段时间写下的尺子——它一开始很钝,用得久才准。

两个人,同一个数字

两个人,一个平时的读数高出一大截,一个平时的读数低一大截。某天下午,两个人的读数停在了同一个数上。

一把人群尺子会这么说:第二位没事,第一位状态糟糕。可那天真正发生的是——第一位掉了一大截,第二位涨了一大截。

当我们还没有你的基线时,用的就是这么一把尺子:一个来自人群统计的中心,配上同样来自人群的宽度。它只是最初几天的兜底,不是我们认为正确的做法。用得越久越明显:它衡量的不是你,是你和一群陌生人之间的距离。

人和人的差距,比一个人每天的波动大得多

HRV 受年龄、性别、基础心率、用药、训练水平、自主神经张力影响。人和人之间能差出好几倍;而同一个人,日与日之间只在一个很窄的范围里晃。

所以人群尺子是两头都错:对基线高的人,他正常的低端会被判成糟糕;对基线低的人,他真正糟糕的一天还落在人群的正常区间里,尺子一声不响。

还有个更安静的问题:它奖励天生 HRV 高的人。同样的生活方式,起点不同,分数就不同。而我们想衡量的不是你站在人群的哪个位置,是你离你自己有多远。

这把尺子是怎么造出来的

先让样本等权。 Apple Watch 有些天写得密,有些天写得稀。要是直接把样本丢进统计,写得多的时段就会拿到更大权重——基线不是被你的身体推动,而是被采样率推动。所以进入基线计算之前,HRV 先按本地时间归入一个个等长的时间桶,每桶只留中位数。图表、详情、当次算分仍然用原始样本,只有造尺子这一步用桶。

再选窗口。 上限大约一个月。最近这段时间里 HRV 桶、静息心率样本和覆盖的自然日都够多,就用完整窗口;达不到,就用真实的数据跨度。为什么不把窗口定得更短——太短,一个糟心的夜晚就能把基线拽走。为什么不再拉长——太长,换季、训练周期、作息改变会混进来。

中心取中位数。 先丢掉物理上不合理的值,样本够多时两端各裁掉一小截,然后取中位数。中位数对偶发的极端值不敏感:一次没戴稳测出的离谱高值,不该抬高你一整周的中心。

把中心钉在当下这个小时。 HRV 有昼夜节律,多数人睡眠时最高、下午最低(形状因人而异)。一个静止的中心不够用。我们从最近这段时间的几个粗时段的中位数算节律因子——每个时段都要有足够样本,且要有足够多的时段算得上可靠;缺的时段按环形插值补上,展开到每个小时之后做一次轻度平滑,最后钳在一个合理的范围内。某一时刻的动态中心 = 全天中心 × 那个小时的因子。

为什么是几个粗时段,而不是一小时一格:手表上的 HRV 稀疏又不均匀,多数小时只有一两条样本,按小时取中位数基本是在给噪声画曲线。粗时段 + 插值 + 平滑,比精细但空着的桶更接近真实节律。

区间不用标准差。 这是最关键的一步。HRV 的变化是乘性的:从高位掉同样的比例,和从低位掉同样的比例,是同一件事,可绝对差一个是另一个的好几倍。所以对每个样本,我们算的是它相对那一刻动态中心的对数残差。

在对数尺度上,基线不同的人可以放进同一张图里比较;换回毫秒时,区间天然为正。然后在这堆残差上取三个分位——偏下的一侧、偏上的一侧,以及更靠外的一档:

  • 状态正常的下沿 = 中心 × exp(偏下那一档的残差)

  • 元气满满的入口 = 中心 × exp(偏上那一档的残差)

  • 状态糟糕的入口 = 中心 × exp(更靠外那一档的残差)

选这一组而不是常见的四分位是有意的:让「状态正常」覆盖你日常波动的中间一段,并且整体向高的一侧偏移——偏低时更早被注意到,只有进入你个人最好的一小段才算元气满满。健康产品不该靠发夸奖来维持存在感。

上面还压了三道安全阀:

  • 半宽有下限。天生波动很小的人,分位会窄到离谱,单次读数的噪声就够让他在一天里反复跨档。

  • 上半宽最多是下半宽的一个固定倍数。HRV 右侧那条长尾会一直把「状态正常」的上沿往上顶,顶到最后变成「只要你不是特别低就算正常」。

  • 状态糟糕的入口还要再往外推:取分位与「中心减去若干个有效下半宽」里更靠外的那个。同样是防抖——宁可让这条线更靠外,也不让它卡在噪声里。

残差模型自己也有准入门槛:归一化样本要够多、覆盖的自然日要够多、可靠的时段要够多。达不到就整体回退到稳健半宽——用中位数的绝对偏差和四分位差里更稳的那个,宽度再封一道顶。也就是说,你看到的区间要么来自你自己的分位分布,要么来自一把很钝但很稳的尺子,不会来自一个凑出来的分位数。

档位的单位是「半宽」,不是标准差。 算分看的是当前值离中心偏了几个半宽(低于中心用下半宽,高于用上半宽),不是几个标准差。这样每个档位在所有人身上语义一致:偏离在一个半宽以内是状态正常,往低的一侧越过就是元气满满,再往外是有些疲惫,跌破状态糟糕的入口就是最后一档。人和人的差别只体现在「半宽有多宽」,不体现在「多少分算正常」。

还有两根护栏。心率是辅助项,只在 HRV 已经偏离中心时才加重权重(偏得越远,权重越高),而且它比的是你自己的静息心率。另一根是绝对极低 HRV 的保护,它完全不看个人基线——生理上的极低就是极低,不需要「相对你的基线」来开脱。

数据还不够的时候

头几天,个性化分数会和人群兜底分数按天数线性混合;这时基线标记为冷启动,只作参考,不承担档位边界。再往后是一段「学习中」。用到足够多天、且残差模型质量过关,才算成熟。

可靠性是另一套门槛:已有的数据越少,要求的样本越多。它决定这条基线有没有资格参与算分;成熟度决定它在选择策略里的优先级,以及界面上该怎么表达信心。

评估某一天时,只使用严格早于那天的基线。当天现算出来的基线不参与当天的判断——否则 HealthKit 一条条把数据同步进来,今天的结论会来回跳。

基线自己也会漂,所以留了第二根锚

滚动窗口有个副作用:一个人如果连续几个月处在低 HRV,这个低水平会慢慢变成「他的正常」,长期变化就看不见了。

所以我们保留最近一段时间里的基线快照,把当前快照和大约一个月前的那一份配对。要凑够足够的配对、且大部分方向一致,才输出「持续偏低 / 偏高」。给用户的说法是三态:比上个月好一些、差一些、差不多。凑不齐就留白——不把「不知道」写成「没变」。

另外还有一条慢锚,每天最多向快基线挪很小一步,遇到持续漂移时步长再缩小。它只在持续偏低时对分数做很轻微的上调,而且不回刷历史记录。这个不对称是故意的:长期偏低值得被更认真地对待,长期偏高不需要奖励。

还没解决的部分

采样密度在基线一侧被这套分桶隔离了,但日汇总仍然按压力点等权,高频设备上白天的权重会偏大。这是已知偏置,改法(按时间桶等权)在需求池里,这一轮没动。

混淆因素也清不完。咖啡因、饮酒、时差、生理周期、生病都会让 HRV 动,我们显式处理的只有运动和最主要的一小批来源。

最后说清楚:基线不是诊断。它是一把相对尺子,描述的是你和你自己的关系,不做任何医学判断。

一句话收尾——人群均值是一个没有你参与的平均数;个人基线是你自己最近这段时间写下的尺子。它一开始很钝,用得久才准,这件事没法加速。

继续阅读

在 Stress HRV 里体验这些想法

App Store 下载

这些笔记分享个人健康工具的产品思考,不构成医疗建议。