<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Data Science on kenji.blog</title><link>http://kenji.blog/zh-cn/categories/data-science/</link><description>Recent content in Data Science on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 12:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/zh-cn/categories/data-science/index.xml" rel="self" type="application/rss+xml"/><item><title>使用智能戒指等管理身体状况的工程师日常（健康黑客）</title><link>http://kenji.blog/zh-cn/p/engineer-health-hacks-wearables/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/zh-cn/p/engineer-health-hacks-wearables/</guid><description>&lt;img src="http://kenji.blog/p/engineer-health-hacks-wearables/img/eyecatch.jpg" alt="Featured image of post 使用智能戒指等管理身体状况的工程师日常（健康黑客）" />&lt;h2 id="1-简介软件工程师与生物黑客biohacking的交汇点">1. 简介：软件工程师与生物黑客（Biohacking）的交汇点
&lt;/h2>&lt;p>现代的软件工程是一项伴随着极度认知负荷和长时间久坐（Sedentary Lifestyle）的严酷智力劳动。我们需要不断跟进不断变化的技术栈，在复杂的分布式系统中寻找Bug，以及承受交付期限的压力。为了克服这些困难，仅仅依靠“干劲”和“毅力”是行不通的，我们必须像调试系统一样去调试自己的身体这个“硬件”，这种方法即“生物黑客（Biohacking）”，是必不可少的。&lt;/p>
&lt;p>过去，我们依赖于“今天感觉状态好/不好”这种主观感觉（启发式判断）；而在现代，得益于Oura Ring、Apple Watch、Garmin等高性能可穿戴设备的普及，我们能够24小时365天无创地获取生理数据。本文将详细讲解如何通过API获取生理数据（HRV、RHR、睡眠架构）与生产力数据（通过WakaTime等获取的编程指标），并利用Python和Pandas以数据科学的方法进行相关性分析。此外，本文还将极具细节地探讨基于科学依据的工程师健康黑客技术，如昼夜节律（Circadian Rhythm）的数学模型、基于咖啡因代谢半衰期的最佳咖啡摄入时机等。&lt;/p>
&lt;h2 id="2-无法测量就无法管理获取生理数据的硬件">2. 无法测量就无法管理：获取生理数据的硬件
&lt;/h2>&lt;p>用于获取生理数据的传感器（可穿戴设备）各有其擅长的领域。在数据驱动的健康管理中，根据目标选择最合适的设备是第一步。&lt;/p>
&lt;h3 id="21-oura-ring-generation-3--4">2.1 Oura Ring (Generation 3 / 4)
&lt;/h3>&lt;p>因为直接从手指动脉获取数据，与在手腕处进行测量的智能手表相比，其睡眠时的心率、心率变异性（HRV）以及体表温度变化的测量精度非常高，这是它的特点。手指上密布毛细血管，通过光学心率传感器（PPG: Photoplethysmography）可以获取低噪声的数据。此外，其REST API非常完善，能够通过OAuth2.0轻松导出JSON格式的原始数据，可以说是对工程师而言最具“黑客友好度（Hackable）”的设备。&lt;/p>
&lt;h3 id="22-apple-watch-series--ultra">2.2 Apple Watch Series / Ultra
&lt;/h3>&lt;p>它在活动追踪、血氧饱和度（SpO2）以及心电图（ECG）的测量方面表现出色。在白天的活动量记录以及通过正念App（呼吸App）进行按需HRV测量方面，它是最强的设备。然而，在导出数据时必须经过HealthKit，若想用Python等进行直接访问，则需要通过iOS App（如AutoSleep或HealthFit）导出CSV，中间多了一个步骤。&lt;/p>
&lt;h3 id="23-garmin-fenix--forerunner">2.3 Garmin (Fenix / Forerunner)
&lt;/h3>&lt;p>除了GPS追踪的精度外，被称为“身体电量（Body Battery）”的独家剩余能量指标也非常优秀。该指标是基于HRV和压力水平计算得出的。Garmin的数据可以通过Garmin Connect API获取，但因为存在面向企业的API壁垒，对于个人开发者来说，需要使用开源库或者利用爱好者编写的爬虫工具。&lt;/p>
&lt;p>本文将以在睡眠与恢复追踪方面达到顶峰、并且极易通过API提取数据的 &lt;strong>Oura Ring&lt;/strong> 数据，以及作为IDE（VS Code或IntelliJ等）插件用于测量编程时间的 &lt;strong>WakaTime&lt;/strong> 数据为主线进行讲解。&lt;/p>
&lt;h2 id="3-生理数据的基础理论hrv与rhr的数据科学">3. 生理数据的基础理论：HRV与RHR的数据科学
&lt;/h2>&lt;p>我们不能简单地使用“睡眠时间长就好”这种粗糙的指标。从数据科学的角度来看，以下两个指标才是“恢复（Recovery）”的核心指标。&lt;/p>
&lt;h3 id="31-hrv心率变异性heart-rate-variability与自主神经建模">3.1 HRV（心率变异性：Heart Rate Variability）与自主神经建模
&lt;/h3>&lt;p>心脏并不是像节拍器那样以固定的节奏跳动的。例如，即便心率为60bpm，每一次心跳之间的间隔（R-R间期）也是不断波动的，比如“0.92秒”、“1.05秒”、“0.98秒”。将这种波动的大小数值化后，即为HRV（心率变异性）。&lt;/p>
&lt;p>HRV直接反映了自主神经系统，即“交感神经（油门）”和“副交感神经（刹车）”之间的平衡。在压力状态、过度疲劳或饮酒后，交感神经处于优势状态，心脏的跳动趋于规律，HRV会下降。相反，在充分放松并恢复的状态下，副交感神经（迷走神经）处于优势，心跳会随着呼吸进行动态变化，HRV则会升高。&lt;/p>
&lt;p>HRV的计算分为时域（Time-domain）和频域（Frequency-domain）两种方法。在时域分析中最常使用的、并且被Oura Ring和Apple Watch采用的是 &lt;strong>RMSSD (Root Mean Square of Successive Differences)&lt;/strong>。它用于计算相邻心跳间隔（RR间期）差值的均方根。&lt;/p>
&lt;p>用数学公式严格表示如下：&lt;/p>
$$ RMSSD = \sqrt{\frac{1}{N-1} \sum_{i=1}^{N-1} (RR_{i+1} - RR_i)^2} $$&lt;p>其中，&lt;/p>
&lt;ul>
&lt;li>$N$ 为测量到的总心跳数&lt;/li>
&lt;li>$RR_i$ 为第 $i$ 个RR间期（毫秒）&lt;/li>
&lt;/ul>
&lt;p>对于工程师来说，如果早晨醒来时的HRV（RMSSD）相较于个人基线（过去几周的移动平均值）出现了大幅下降，就可以做出数据驱动的决策：“今天应该避免进行高认知负荷的架构设计或是向生产环境部署，而应把时间用在扩充测试代码和编写文档上”。&lt;/p>
&lt;h3 id="32-静态心率rhrresting-heart-rate与恢复信号">3.2 静态心率（RHR：Resting Heart Rate）与恢复信号
&lt;/h3>&lt;p>RHR是指身体处于完全放松状态（通常是睡眠期间）下每分钟的心跳次数。在饮酒后、深夜暴食或疾病（如感染症）的初期阶段，由于身体正在将能量分配给体内代谢或免疫反应，RHR会比基线升高几bpm到十几bpm。&lt;/p>
&lt;p>RHR越低，意味着心肌在一次跳动中能泵出更多的血液（每搏输出量大），这表明有氧运动能力较强或疲劳恢复程度较好。理想情况下，如果在睡眠的前半段RHR达到最低值，呈现出一个“吊床型（Hammock）”曲线，说明你获得了最高质量的恢复。&lt;/p>
&lt;h2 id="4-睡眠架构详细解析">4. 睡眠架构详细解析
&lt;/h2>&lt;p>决定工程师大脑表现的不仅是睡眠的“量”，更重要的是“质”，即睡眠架构（Sleep Architecture）。一晚的睡眠通常会重复4到5次周期，每个周期为90到110分钟。&lt;/p>
&lt;h3 id="41-非快速眼动睡眠-阶段12浅睡--light-sleep">4.1 非快速眼动睡眠 阶段1〜2（浅睡 / Light Sleep）
&lt;/h3>&lt;p>脑电波逐渐变慢，是身体开始放松的准备阶段。它占整体睡眠的50%左右。虽然对认知恢复的贡献较小，但它是向下一个深度睡眠阶段过渡的重要桥梁。&lt;/p>
&lt;h3 id="42-非快速眼动睡眠-阶段3深睡--deep-sleep--slow-wave-sleep-sws">4.2 非快速眼动睡眠 阶段3（深睡 / Deep Sleep / Slow Wave Sleep: SWS）
&lt;/h3>&lt;p>脑电波中出现德尔塔波（0.5〜2Hz的低频波），是身体进行物理恢复的核心时间段。此时会分泌大量生长激素，进行细胞修复。它对于强化免疫系统也是不可或缺的，不仅关系到运动员的肌肉疲劳恢复，也直接关系到工程师的视疲劳以及颈肩肌肉的修复。深度睡眠通常集中在睡眠周期的前半段。&lt;/p>
&lt;h3 id="43-快速眼动睡眠rem睡眠rapid-eye-movement">4.3 快速眼动睡眠（REM睡眠：Rapid Eye Movement）
&lt;/h3>&lt;p>大脑的活动与清醒时一样活跃，但身体肌肉处于麻痹状态。对工程师来说，极其重要的是这种REM睡眠，它负责在脑内整理白天学到的新编程语言语法或复杂算法概念，并将其巩固为长期记忆（Memory Consolidation）。REM睡眠能够提高神经可塑性（Neuroplasticity），并增强创造性解决问题的能力（例如“在洗澡时突然灵光一闪找到Bug的解决办法”）。REM睡眠通常在睡眠的后半段（清晨）变得更长。&lt;/p>
&lt;p>也就是说，“用闹钟强行早起从而削减睡眠时间”，意味着大幅削减了与记忆巩固和创造力相关的REM睡眠，这无异于引入了一个会显著降低工程师表现的严重Bug。&lt;/p>
&lt;h2 id="5-连续血糖监测cgm与血糖峰值防御">5. 连续血糖监测（CGM）与血糖峰值防御
&lt;/h2>&lt;p>近年来，在生物黑客圈子中，引入CGM（Continuous Glucose Monitor：连续动态血糖监测仪）已成为必备项。代表性的设备有FreeStyle Libre和Dexcom。
进食（特别是碳水化合物或糖分）后，血液中的葡萄糖浓度会急剧上升（血糖峰值），随后因为大量分泌胰岛素而出现急剧下降（崩溃）。在“崩溃”的阶段，会引发强烈的困意（脑雾，Brain Fog）以及注意力下降。午餐后“魔鬼般的下午2点”所产生的困意，很可能不仅仅是因为生物钟的影响，更可能是由于过量摄入拉面或白米饭导致的血糖峰值。&lt;/p>
&lt;p>血糖值的响应曲线 $G(t)$ 可以近似表示为以下阻尼振荡模型，即摄入糖分的吸收速度与胰岛素清除作用之间的差值：&lt;/p>
$$ G(t) = G_{base} + \Delta G \cdot e^{-\alpha t} \sin(\beta t) $$&lt;p>其中，&lt;/p>
&lt;ul>
&lt;li>$G_{base}$: 空腹血糖值（基线）&lt;/li>
&lt;li>$\Delta G$: 进食引起的血糖上升幅度&lt;/li>
&lt;li>$\alpha$: 基于胰岛素敏感性和代谢速度的衰减系数&lt;/li>
&lt;li>$\beta$: 振荡频率成分&lt;/li>
&lt;li>$t$: 餐后经过的时间&lt;/li>
&lt;/ul>
&lt;p>为了保持工程师的表现，将 $\Delta G$（振幅）降至最低是非常重要的。具体来说，诸如“先吃蔬菜（膳食纤维）”、“避免精制碳水化合物”、“饭后进行15分钟的散步（以激活GLUT4转运蛋白，使肌肉以非胰岛素依赖的方式摄取血糖）”等黑客技巧非常有效。&lt;/p>
&lt;h2 id="6-架构设计构建本地数据流管道">6. 架构设计：构建本地数据流管道
&lt;/h2>&lt;p>我们将构建一个本地数据流管道，以综合分析生理数据和生产力数据。
以下的Mermaid图表（流程图）展示了从通过API获取数据到在仪表盘上可视化的完整流程。&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Oura Ring API（生理数据）&amp;#34;] --&amp;gt;|JSON via OAuth2| C[&amp;#34;Python 数据摄取管道&amp;#34;]
B[&amp;#34;WakaTime API（编程时间）&amp;#34;] --&amp;gt;|JSON via API Key| C
E[&amp;#34;SwitchBot API（室温 / CO2）&amp;#34;] --&amp;gt;|JSON via API Key| C
C --&amp;gt;|Extract &amp;amp; Transform| D[&amp;#34;Pandas DataFrame（内存）&amp;#34;]
D --&amp;gt;|Load| F[&amp;#34;TimescaleDB / PostgreSQL&amp;#34;]
F --&amp;gt; G[&amp;#34;Jupyter Notebook（即席分析）&amp;#34;]
F --&amp;gt; H[&amp;#34;Streamlit Web App（日常监控）&amp;#34;]
&lt;/pre>
&lt;p>通过这种架构，我们可以每天自动监控自身身体状况（输入）与编程表现（输出）之间的相关性。&lt;/p>
&lt;p>此外，让我们详细看看系统之间的时序。&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant U as &amp;#34;用户（工程师）&amp;#34;
participant W as &amp;#34;WakaTime 插件（VS Code）&amp;#34;
participant O as &amp;#34;Oura Ring &amp;amp; API&amp;#34;
participant S as &amp;#34;Python ETL 批处理&amp;#34;
participant DB as &amp;#34;TimescaleDB&amp;#34;
U-&amp;gt;&amp;gt;W: &amp;#34;编写代码（键盘输入）&amp;#34;
W--&amp;gt;&amp;gt;W: &amp;#34;记录精确的编程心跳活动&amp;#34;
U-&amp;gt;&amp;gt;O: &amp;#34;睡眠（佩戴智能戒指）&amp;#34;
O--&amp;gt;&amp;gt;O: &amp;#34;记录 HRV、RHR、体温和睡眠阶段&amp;#34;
S-&amp;gt;&amp;gt;W: &amp;#34;GET /api/v1/users/current/summaries&amp;#34;
S-&amp;gt;&amp;gt;O: &amp;#34;GET /v2/usercollection/sleep&amp;#34;
S-&amp;gt;&amp;gt;S: &amp;#34;清洗并合并数据（Pandas）&amp;#34;
S-&amp;gt;&amp;gt;DB: &amp;#34;INSERT INTO daily_metrics&amp;#34;
Note over S,DB: &amp;#34;通过 Cron / Airflow 进行调度&amp;#34;
&lt;/pre>
&lt;h2 id="7-使用python和pandas进行数据摄取">7. 使用Python和Pandas进行数据摄取
&lt;/h2>&lt;p>让我们实际看看如何使用Python脚本从Oura Ring和WakaTime的API中获取数据，并将其集成为Pandas DataFrame的过程。我们将构建能够承受实际生产环境运行的健壮代码。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pandas&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">pd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datetime&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">timedelta&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 环境变量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">OURA_TOKEN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getenv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;OURA_ACCESS_TOKEN&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">WAKATIME_API_KEY&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getenv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;WAKATIME_API_KEY&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_oura_sleep_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">start_date&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">end_date&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;从 Oura Ring API v2 获取每日睡眠摘要。&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://api.ouraring.com/v2/usercollection/sleep&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;start_date&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">start_date&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;end_date&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">end_date&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">headers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;Authorization&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Bearer &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">OURA_TOKEN&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">headers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">headers&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">params&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">raise_for_status&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># 对 4xx/5xx 错误抛出异常&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;data&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json_normalize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 提取深度嵌套的值或选择必要的列&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[[&lt;/span>&lt;span class="s1">&amp;#39;day&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;score&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;time_in_bed&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;total_sleep_duration&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;average_hrv&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;lowest_heart_rate&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;deep_sleep_duration&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;rem_sleep_duration&amp;#39;&lt;/span>&lt;span class="p">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 将日期转换为 datetime 对象并设为索引&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;day&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_datetime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;day&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">set_index&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;day&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">inplace&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">df&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_wakatime_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">start_date&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">end_date&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;从 WakaTime API 获取编程时间摘要。&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://wakatime.com/api/v1/users/current/summaries&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;start&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">start_date&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;end&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">end_date&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;api_key&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">WAKATIME_API_KEY&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">params&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">raise_for_status&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;data&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">records&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">day_data&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">date_str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">day_data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;range&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="s1">&amp;#39;date&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 提取编程花费的总秒数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_seconds&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">day_data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;grand_total&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="s1">&amp;#39;total_seconds&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">records&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s1">&amp;#39;day&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">date_str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;coding_hours&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">total_seconds&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mf">3600.0&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">records&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">empty&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;day&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_datetime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;day&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">set_index&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;day&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">inplace&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">df&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 获取过去 60 天的数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">end&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">timedelta&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">days&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">oura_df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">fetch_oura_sleep_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">start&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">end&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">waka_df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">fetch_wakatime_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">start&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">end&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 使用 inner join 在 &amp;#39;day&amp;#39; 索引上合并数据集&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">merged_df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">merge&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">oura_df&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">waka_df&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">left_index&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">right_index&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">how&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;inner&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 将原始数据保存为 CSV/DB&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">merged_df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_csv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;health_productivity_raw.csv&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Ingested &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">merged_df&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> days of data.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="8-数据预处理与特征工程">8. 数据预处理与特征工程
&lt;/h2>&lt;p>将获取到的原始数据直接用于分析是危险的。我们需要处理因设备忘记充电而导致的缺失值（Missing Values），并生成有意义的新指标（特征工程：Feature Engineering）。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">engineer_features&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;对合并后的 dataframe 应用特征工程和数据清理。&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">copy&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. 处理缺失值（例如向前填充）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">fillna&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">method&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;ffill&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">inplace&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. 计算睡眠效率&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 公式：(Total Sleep Time / Time in Bed) * 100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;sleep_efficiency_pct&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;total_sleep_duration&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;time_in_bed&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. 计算睡眠阶段比例&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;rem_ratio&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;rem_sleep_duration&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;total_sleep_duration&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;deep_ratio&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;deep_sleep_duration&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;total_sleep_duration&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. 计算 7 天移动平均（Rolling Mean）以平滑日常噪声&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;hrv_7d_ma&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;average_hrv&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">rolling&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">window&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">7&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">mean&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;rhr_7d_ma&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;lowest_heart_rate&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">rolling&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">window&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">7&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">mean&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. 计算每天偏离基线的程度&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;hrv_deviation&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;average_hrv&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;hrv_7d_ma&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 6. 为机器学习归一化目标变量（可选）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kn">from&lt;/span> &lt;span class="nn">sklearn.preprocessing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">MinMaxScaler&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scaler&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">MinMaxScaler&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="p">[[&lt;/span>&lt;span class="s1">&amp;#39;hrv_scaled&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;coding_scaled&amp;#39;&lt;/span>&lt;span class="p">]]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">scaler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">fit_transform&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[[&lt;/span>&lt;span class="s1">&amp;#39;average_hrv&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;coding_hours&amp;#39;&lt;/span>&lt;span class="p">]])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 删除由滑动窗口生成的包含 NaN 的行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">dropna&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">inplace&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">df&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">processed_df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">engineer_features&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">merged_df&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="9-相关性分析生产力与健康指标的交汇点">9. 相关性分析：生产力与健康指标的交汇点
&lt;/h2>&lt;p>基于预处理后的数据，我们将分析健康指标与编程生产力之间的关系。作为一个假设，我们可以认为“HRV越高（自主神经平衡且恢复良好）的日子，注意力持续的时间就越长，编程时间也会增加，或者能够处理更加复杂的任务”。&lt;/p>
&lt;pre class="mermaid">
xychart-beta
title HRV 与日常编程时间的对比（归一化）
x-axis [&amp;#34;周一&amp;#34;, &amp;#34;周二&amp;#34;, &amp;#34;周三&amp;#34;, &amp;#34;周四&amp;#34;, &amp;#34;周五&amp;#34;, &amp;#34;周六&amp;#34;, &amp;#34;周日&amp;#34;]
y-axis &amp;#34;HRV &amp;amp; 编程产出&amp;#34; 10 --&amp;gt; 100
line [45, 52, 65, 75, 70, 58, 48]
bar [35, 42, 58, 65, 60, 20, 15]
&lt;/pre>
&lt;p>&lt;em>(注：折线图表示的是归一化后HRV偏离基线的程度，柱状图表示的是WakaTime记录的编程时间。可以看出，在得到充分恢复的周三至周五期间，编程产出被最大化的相关性十分明显)&lt;/em>&lt;/p>
&lt;p>我们使用Pandas计算相关系数（皮尔逊积矩相关系数 $r$），并利用SciPy进行统计显著性（p值）检验。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">scipy.stats&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">stats&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 为相关性矩阵选择数值列&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cols_of_interest&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;average_hrv&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;score&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;deep_sleep_duration&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;rem_sleep_duration&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;coding_hours&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">correlation_matrix&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">processed_df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">cols_of_interest&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">corr&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Correlation with Coding Hours:&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">correlation_matrix&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;coding_hours&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort_values&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ascending&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 计算快速眼动（REM）睡眠和编程时间的皮尔逊相关系数和 p 值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">r&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p_value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">stats&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pearsonr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">processed_df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;rem_sleep_duration&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">processed_df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;coding_hours&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;REM Sleep vs Coding Hours: r = &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">r&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.3f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, p-value = &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">p_value&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.4f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>在许多情况下，可以观察到 &lt;code>average_hrv&lt;/code> 或 &lt;code>rem_sleep_duration&lt;/code> 与 &lt;code>coding_hours&lt;/code> 之间存在显著的正相关（$p &lt; 0.05$）。特别是在许多工程师的量化自我（Quantified Self）社区中，也有报告指出，前一天的REM睡眠时长会强烈影响当天的“解决错误（调试）所需时间”和“生产力”。&lt;/p>
&lt;h2 id="10-昼夜节律的数学模型与认知高峰优化">10. 昼夜节律的数学模型与认知高峰优化
&lt;/h2>&lt;p>人类拥有一种被称为昼夜节律（Circadian Rhythm）的、周期约为24小时的生物钟。受这一节律的影响，体温、激素分泌（如早晨的皮质醇激增和夜间的褪黑素分泌）以及“认知能力”都会产生波动。&lt;/p>
&lt;p>昼夜节律的波动通常用基于余弦曲线的数学模型（Cosinor模型）来近似表达，生理指标的变化可以公式化为：&lt;/p>
$$ y(t) = M + A \cos\left(\frac{2\pi}{24}(t - \phi)\right) + e(t) $$&lt;ul>
&lt;li>$y(t)$: 在时间 $t$ 时的生理指标（例如：核心体温或清醒度）&lt;/li>
&lt;li>$M$: MESOR (Midline Estimating Statistic of Rhythm) - 节律的中心值（平均水平）&lt;/li>
&lt;li>$A$: 振幅（Amplitude） - 波动的大小&lt;/li>
&lt;li>$\phi$: 相位（Acrophase） - 达到高峰的相位（时间）&lt;/li>
&lt;li>$e(t)$: 由环境等因素引起的误差项&lt;/li>
&lt;/ul>
&lt;p>在工程实践中，这个公式意味着：“一天中表现（清醒度）达到高峰的时间段（$\phi$）是由生物学决定的，我们应该把认知负荷最高的工作（如棘手的Bug修复、新架构设计）分配在那个时间段”。&lt;/p>
&lt;p>对于一般的早睡早起型（Morning Lark）作息模式，起床后2到4小时（例如上午9点至11点）会迎来第一个认知高峰。随后，在下午2点左右会出现昼夜节律的低谷（餐后困倦，Post-lunch dip），到了傍晚会再次出现一个小高峰。通过可穿戴设备的数据或主观专注度来确定自己的高峰时间（$\phi$），并使用Google日历等工具通过“时间块（Time Blocking）”来保护这段时间，是绝佳的健康黑客技巧。如果在高峰时间安排毫无意义的会议，就如同将性能最好的CPU核心分配给空闲进程一样。&lt;/p>
&lt;h2 id="11-咖啡因的药代动力学与最佳摄入时机">11. 咖啡因的药代动力学与最佳摄入时机
&lt;/h2>&lt;p>工程师和咖啡之间有着密不可分的关系，但咖啡因过量摄入或在太晚的时间摄入，会阻断大脑中的腺苷受体，破坏夜间的“深度睡眠（Deep Sleep）”。即使主观上觉得自己睡着了，但查看Oura Ring的数据就会发现心率并未下降，而且深度睡眠的比例急剧减少。&lt;/p>
&lt;p>咖啡因从体内的排出遵循一级反应动力学（First-order kinetics）。也就是说，其血液浓度呈指数级衰减。&lt;/p>
$$ C(t) = C_0 e^{-k t} $$&lt;p>其中，&lt;/p>
&lt;ul>
&lt;li>$C(t)$: 经过时间 $t$ 后的血液咖啡因浓度&lt;/li>
&lt;li>$C_0$: 初始浓度（摄入后的最大浓度）&lt;/li>
&lt;li>$k$: 消除速率常数&lt;/li>
&lt;li>$t$: 距离摄入后经过的时间（小时）&lt;/li>
&lt;/ul>
&lt;p>消除速率常数 $k$ 可以使用咖啡因的半衰期（$t_{1/2}$）表示如下：&lt;/p>
$$ k = \frac{\ln(2)}{t_{1/2}} $$&lt;p>对于健康的成年人，虽然也会因个人基因（CYP1A2基因）而异，但咖啡因的半衰期 $t_{1/2}$ 大约在 &lt;strong>5到6小时&lt;/strong> 之间。
例如，假设在下午3点喝了一杯滴漏咖啡（约含150mg咖啡因）（即 $C_0 = 150$）。假设半衰期为5.5小时，则 $k \approx 0.126$。
计算在就寝时间晚上11点（8小时后）时体内的残留咖啡因浓度：&lt;/p>
$$ C(8) = 150 \times e^{-0.126 \times 8} = 150 \times e^{-1.008} \approx 150 \times 0.365 = 54.75 \text{ mg} $$&lt;p>也就是说，到了睡觉的时间，体内仍然残留有54mg（相当于略多于1杯意式浓缩咖啡）的咖啡因，这将直接对睡眠架构产生不良影响。
从这个药代动力学模型推导出的数据驱动结论是：&lt;strong>“为了确保高质量的睡眠，咖啡因的摄入应在起床90分钟后（皮质醇激增平息后）开始，并且最迟在下午2点（睡前9到10小时）之前彻底停止摄入。”&lt;/strong>&lt;/p>
&lt;h2 id="12-环境变量的黑客技术lux温度co2">12. 环境变量的黑客技术（Lux、温度、CO2）
&lt;/h2>&lt;p>不仅要优化我们身体这个内部系统，优化外部的环境变量（Environment Variables）同样重要。&lt;/p>
&lt;h3 id="121-光照环境lux的编程化">12.1 光照环境（Lux）的编程化
&lt;/h3>&lt;p>能够重置昼夜节律的最强大的“授时因子（Zeitgeber：提示时间的线索）”是光。早晨，当大约100,000 Lux（勒克斯）的阳光进入视网膜的光感受器细胞（ipRGC）时，褪黑素的分泌就会停止，从而重置生物钟计时器。相反，在夜间必须屏蔽蓝光，以免阻碍褪黑素的分泌。除了使用f.lux等软件降低显示器的色温，更有效的方法是通过API控制智能照明（如Philips Hue等），编写脚本使其在日落时自动降低房间的照度和色温。&lt;/p>
&lt;h3 id="122-卧室温度控制与入睡潜伏期sleep-latency">12.2 卧室温度控制与入睡潜伏期（Sleep Latency）
&lt;/h3>&lt;p>人类是通过核心体温（Core Body Temperature）下降来进入睡眠的。将卧室的温度保持在18到19度这种凉爽的状态，并在睡前90分钟洗个热水澡，短暂提高核心体温；然后算准核心体温急剧下降的时机钻进被窝，这样可以大幅缩短入睡潜伏期（Sleep Latency：从躺下到睡着的时间），并最大限度地增加深度睡眠。&lt;/p>
&lt;h3 id="123-co2浓度与认知能力下降">12.3 CO2浓度与认知能力下降
&lt;/h3>&lt;p>如果将SwitchBot Hub或Netatmo气象站的API添加到数据管道中，我们会发现室内的二氧化碳（CO2）浓度与生产力之间存在明显的负相关。
正如哈佛大学等机构的研究所示，当CO2浓度超过1000ppm时，认知能力（特别是战略决策能力）开始显著下降；一旦超过2000ppm，就会引起严重的性能衰减。在冬天门窗紧闭的房间里进行远程办公，会在不知不觉中降低你的工作表现。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用 Home Assistant / SwitchBot API 进行智能房间通风的伪代码&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">check_and_ventilate&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 从 Netatmo/SwitchBot API 获取当前的 CO2 水平&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">co2_ppm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_sensor_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;co2_sensor_id&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">co2_ppm&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Warning: CO2 level high (&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">co2_ppm&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> ppm). Cognitive decline risk.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 触发智能插座开启排气扇&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">turn_on_smart_plug&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;ventilation_fan_id&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 发送通知到 Slack/Discord&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">send_notification&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;已启动排气扇。当前 CO2 浓度偏高。&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">elif&lt;/span> &lt;span class="n">co2_ppm&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">600&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">turn_off_smart_plug&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;ventilation_fan_id&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>通过使用Cron定期执行这样的脚本，就可以打造一个始终维持最佳氧气浓度的自主环境控制系统。&lt;/p>
&lt;h2 id="13-结论人体系统的cicd">13. 结论：人体系统的CI/CD
&lt;/h2>&lt;p>请试着将你自己的身体视为一个复杂的分布式系统。可穿戴设备（Oura Ring）是用于监控的指标导出器（Prometheus），Python/Pandas脚本是日志分析管道（Logstash/Fluentd），而每天身体状态的变化和表现则是展示在仪表盘（Grafana/Streamlit）上的系统健康度。&lt;/p>
&lt;p>“削减睡眠时间来工作”就像是无视技术债务（Technical Debt）强行增加新功能。短期内或许能赶上发布，但长期来看，必定会导致系统崩溃（职业倦怠、严重的健康损害或抑郁症）。&lt;/p>
&lt;p>监控HRV、检查RHR趋势，并优化睡眠架构。同时结合WakaTime生产力数据的相关性，每天微调饮食、运动、睡眠、环境等“超参数（Hyperparameters）”。这正是一个针对人体的 &lt;strong>CI/CD（持续集成·持续交付）&lt;/strong> 过程。&lt;/p>
&lt;p>让我们充分利用数据科学和API，运用工程化的思维来打造能发挥出最高性能的健康状态吧。因为你写出的代码质量，与你自己生理系统的健康程度是直接相关的。&lt;/p>
&lt;hr>
&lt;p>&lt;em>Disclaimer: 本文是对作者个人实验和数据科学方法的总结，不提供医疗建议。如果持续出现身体不适或睡眠障碍，请咨询专业医疗机构。&lt;/em>&lt;/p></description></item></channel></rss>