<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Biohacking on kenji.blog</title><link>http://kenji.blog/zh-tw/tags/biohacking/</link><description>Recent content in Biohacking on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 12:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/zh-tw/tags/biohacking/index.xml" rel="self" type="application/rss+xml"/><item><title>使用'智慧戒指'等進行體能管理的工程師日常（健康駭客）</title><link>http://kenji.blog/zh-tw/p/engineer-health-hacks-wearables/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/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-前言軟體工程師與生物駭客的交會點">1. 前言：軟體工程師與生物駭客的交會點
&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 以資料科學的方法進行相關性分析。此外，也將基於生理時鐘的數學模型，以及根據咖啡因代謝半衰期找出最佳喝咖啡時機等科學根據，為工程師極其詳細地剖析健康駭客技巧。&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 功能完善，能透過 OAuth 2.0 輕鬆匯出 JSON 格式的原始數據，可以說是對工程師而言最具「駭客」潛力的裝置。&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）」的關鍵核心指標（Master Metrics）。&lt;/p>
&lt;h3 id="31-hrv心率變異度heart-rate-variability與自律神經模型化">3.1 HRV（心率變異度：Heart Rate Variability）與自律神經模型化
&lt;/h3>&lt;p>心臟並不是像節拍器那樣以固定的節奏跳動。舉例來說，即使心率是 60 bpm，每一次心跳之間的間隔（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。&lt;/p>
&lt;p>RHR 越低，代表心肌在一次跳動中能送出較多血液（心搏出量大），顯示有氧運動能力較高以及從疲勞中恢復的程度越好。最理想的情況是，在睡眠的前半段，RHR 達到最低值，呈現「吊床型」的曲線，這代表正在進行最高品質的恢復。&lt;/p>
&lt;h2 id="4-睡眠結構的詳細解析">4. 睡眠結構的詳細解析
&lt;/h2>&lt;p>決定工程師大腦表現的，不僅是睡眠的「量」，更重要的是「質」，也就是睡眠結構（Sleep Architecture）。一晚的睡眠通常會經歷 4 到 5 次 90 至 110 分鐘的週期。&lt;/p>
&lt;h3 id="41-nrem-睡眠-階段-12淺眠--light-sleep">4.1 NREM 睡眠 階段 1〜2（淺眠 / Light Sleep）
&lt;/h3>&lt;p>腦波逐漸變慢，是身體準備開始放鬆的階段。約佔整體睡眠的 50%。雖然對認知恢復的貢獻較小，但卻是過渡到下一個深層睡眠階段的重要橋樑。&lt;/p>
&lt;h3 id="42-nrem-睡眠-階段-3深層睡眠--deep-sleep--slow-wave-sleep-sws">4.2 NREM 睡眠 階段 3（深層睡眠 / Deep Sleep / Slow Wave Sleep: SWS）
&lt;/h3>&lt;p>腦波中出現 Delta 波（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）。提升神經可塑性（Neuroplasticity），以及創造性的解決問題能力（例如「洗澡時突然想到 Bug 的解決方案」這類的靈光一閃）也會透過 REM 睡眠得到強化。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）與注意力下降。午餐後「魔鬼的下午兩點」的睡意，很可能不單純是生理時鐘的影響，而是過量攝取拉麵或白飯導致的血糖飆升所引起的。&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;|透過 OAuth2 的 JSON| C[&amp;#34;Python 資料攝取管線&amp;#34;]
B[&amp;#34;WakaTime API (寫程式時間)&amp;#34;] --&amp;gt;|透過 API Key 的 JSON| C
E[&amp;#34;SwitchBot API (室溫 / CO2)&amp;#34;] --&amp;gt;|透過 API Key 的 JSON| C
C --&amp;gt;|擷取與轉換| D[&amp;#34;Pandas DataFrame (記憶體內)&amp;#34;]
D --&amp;gt;|載入| 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 與 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;已攝取 &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"> 天的數據。&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"># 公式：(總睡眠時間 / 躺在床上的時間) * 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;#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;與寫程式時數的相關性：&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 睡眠與寫程式時數: 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$）。特別是，前一天的 REM 睡眠長度，會強烈影響當天的「解決錯誤（除錯）所需時間」與「生產力」，這點在許多工程師的量化自我（Quantified Self）社群中都有被報告。&lt;/p>
&lt;h2 id="10-生理時鐘的數學模型與認知巔峰的最佳化">10. 生理時鐘的數學模型與認知巔峰的最佳化
&lt;/h2>&lt;p>人類具備大約 24 小時為一個週期的體內時鐘，稱為生理時鐘（Circadian Rhythm）。根據這個節奏，體溫、荷爾蒙分泌（早晨的皮質醇飆升與夜間的褪黑激素分泌）以及「認知能力」都會產生變動。&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 Calendar 等工具將行程進行「時間分塊（Time Blocking）」來堅守，這就是最棒的健康駭客技巧。把毫無意義的會議安排在巔峰時段，就好比將效能最強的 CPU 核心分配給閒置處理程序（Idle Process）一樣。&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（超過一杯濃縮咖啡）的咖啡因，這將對睡眠結構帶來直接的負面影響。
從這個藥物動力學模型推導出來的數據驅動結論是：&lt;strong>「為了確保高品質的睡眠，應在起床後 90 分鐘之後（待皮質醇飆升平息後）才開始攝取咖啡因，且最晚在下午 2 點（就寢前 9〜10 小時）就應該完全停止攝取。」&lt;/strong>&lt;/p>
&lt;h2 id="12-環境變數的駭客技巧照度-溫度-co2">12. 環境變數的駭客技巧（照度, 溫度, CO2）
&lt;/h2>&lt;p>不僅是自己身體這個內部系統，對外部的環境變數（Environment Variables）進行最佳化也同樣重要。&lt;/p>
&lt;h3 id="121-光環境照度的程式化">12.1 光環境（照度）的程式化
&lt;/h3>&lt;p>用來重置生理時鐘的最強大「授時因子（Zeitgeber：提示時間的線索）」就是光。早晨，視網膜的感光細胞（ipRGC）接收到約 100,000 Lux 的太陽光後，褪黑激素的分泌就會停止，並重置計時器。相反地，夜間必須阻擋藍光，以免阻礙褪黑激素的分泌。除了使用 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 濃度超過 1000 ppm 時，認知功能（特別是策略性決策能力）會開始顯著下降；若超過 2000 ppm，更會造成嚴重的表現下滑。冬天在門窗緊閉的房間內遠距工作，往往會在不知不覺中降低工作表現。&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 進行智慧室內換氣的偽代碼 (Pseudo-code)&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;警告：CO2 濃度偏高 (&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)。有認知功能下降的風險。&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>