<?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/fr/categories/data-science/</link><description>Recent content in Data Science on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 12:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/categories/data-science/index.xml" rel="self" type="application/rss+xml"/><item><title>Le quotidien d'un ingénieur gérant sa santé avec un anneau intelligent etc. (Health Hack)</title><link>http://kenji.blog/fr/p/engineer-health-hacks-wearables/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/fr/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 Le quotidien d'un ingénieur gérant sa santé avec un anneau intelligent etc. (Health Hack)" />&lt;h2 id="1-introduction--lintersection-entre-lingénierie-logicielle-et-le-biohacking">1. Introduction : L&amp;rsquo;intersection entre l&amp;rsquo;ingénierie logicielle et le biohacking
&lt;/h2>&lt;p>L&amp;rsquo;ingénierie logicielle moderne est un travail intellectuel exigeant qui implique une charge cognitive extrême et un mode de vie sédentaire (Sedentary Lifestyle). Rattraper constamment les piles technologiques en évolution, chasser les bugs dans des systèmes distribués complexes et la pression des délais. Pour surmonter tout cela, au lieu de compter simplement sur la &amp;ldquo;volonté&amp;rdquo; ou le &amp;ldquo;courage&amp;rdquo;, une approche consistant à ajuster son propre corps, c&amp;rsquo;est-à-dire le matériel, comme si on déboguait un système — en d&amp;rsquo;autres termes, le &amp;ldquo;Biohacking&amp;rdquo; — est indispensable.&lt;/p>
&lt;p>Autrefois, nous nous fiions à des sensations subjectives (heuristiques) du type &amp;ldquo;Aujourd&amp;rsquo;hui, je me sens plutôt bien ou mal&amp;rdquo;, mais aujourd&amp;rsquo;hui, avec la popularisation de dispositifs portables performants tels que l&amp;rsquo;Oura Ring, l&amp;rsquo;Apple Watch ou Garmin, il est devenu possible d&amp;rsquo;obtenir des données biométriques 24 heures sur 24, 365 jours par an, de manière non invasive. Dans cet article, nous expliquerons comment récupérer les données biométriques (VFC, FCR, architecture du sommeil) et les données de productivité (métriques de codage via WakaTime, etc.) via des API, et effectuer une analyse de corrélation avec une approche de science des données en utilisant Python et Pandas. De plus, nous décortiquerons en détail les hacks de santé pour ingénieurs basés sur des preuves scientifiques, comme un modèle mathématique du rythme circadien et le moment optimal pour consommer du café en fonction de la demi-vie métabolique de la caféine.&lt;/p>
&lt;h2 id="2-on-ne-peut-pas-gérer-ce-quon-ne-peut-pas-mesurer--matériel-de-collecte-de-données-biométriques">2. On ne peut pas gérer ce qu&amp;rsquo;on ne peut pas mesurer : Matériel de collecte de données biométriques
&lt;/h2>&lt;p>Les capteurs (appareils portables) pour collecter les données biométriques ont chacun leurs domaines de spécialité. Dans la gestion de la santé axée sur les données, la première étape consiste à sélectionner l&amp;rsquo;appareil optimal en fonction de l&amp;rsquo;objectif.&lt;/p>
&lt;h3 id="21-oura-ring-generation-3--4">2.1 Oura Ring (Generation 3 / 4)
&lt;/h3>&lt;p>Puisqu&amp;rsquo;il récupère les données directement depuis l&amp;rsquo;artère du doigt, par rapport aux montres connectées qui mesurent au poignet, il se caractérise par une précision extrêmement élevée de mesure de la fréquence cardiaque pendant le sommeil, de la variabilité de la fréquence cardiaque (VFC) et des changements de température corporelle en surface. Les capillaires sanguins sont denses dans les doigts, ce qui permet d&amp;rsquo;obtenir des données peu bruitées grâce à un capteur de fréquence cardiaque optique (PPG : Photoplethysmography). De plus, l&amp;rsquo;API REST est bien fournie et il est facile d&amp;rsquo;exporter des données brutes au format JSON via OAuth2.0, ce qui en fait l&amp;rsquo;appareil le plus bidouillable pour un ingénieur.&lt;/p>
&lt;h3 id="22-apple-watch-series--ultra">2.2 Apple Watch Series / Ultra
&lt;/h3>&lt;p>Elle excelle dans le suivi pendant l&amp;rsquo;activité, et dans la mesure de la saturation en oxygène dans le sang (SpO2) et des électrocardiogrammes (ECG). C&amp;rsquo;est l&amp;rsquo;appareil ultime pour mesurer le volume d&amp;rsquo;activité en journée et la VFC à la demande via des applications de pleine conscience (applications de respiration). Cependant, l&amp;rsquo;exportation des données nécessite de passer par HealthKit, et un accès direct depuis Python ou autre nécessitera une étape intermédiaire, comme l&amp;rsquo;exportation CSV via une application iOS (telle qu&amp;rsquo;AutoSleep ou HealthFit).&lt;/p>
&lt;h3 id="23-garmin-fenix--forerunner">2.3 Garmin (Fenix / Forerunner)
&lt;/h3>&lt;p>En plus de la précision du suivi GPS, son indicateur unique d&amp;rsquo;énergie restante appelé &amp;ldquo;Body Battery&amp;rdquo; est excellent. Celui-ci est calculé sur la base de la VFC et du niveau de stress. Chez Garmin, on peut obtenir des données via l&amp;rsquo;API Garmin Connect, mais à cause de la barrière de l&amp;rsquo;API pour les entreprises, en tant que développeur individuel, il faut utiliser des bibliothèques open source ou des outils de web scraping créés par des bénévoles.&lt;/p>
&lt;p>Dans cet article, nous concentrerons nos explications sur les données de l&amp;rsquo;&lt;strong>Oura Ring&lt;/strong>, qui est le summum en matière de suivi du sommeil et de la récupération, et dont l&amp;rsquo;extraction de données via l&amp;rsquo;API est extrêmement facile, ainsi que sur les données de &lt;strong>WakaTime&lt;/strong>, un plugin d&amp;rsquo;IDE (tel que VS Code ou IntelliJ) qui mesure le temps de codage.&lt;/p>
&lt;h2 id="3-théorie-de-base-des-données-biométriques--science-des-données-de-la-vfc-et-de-la-fcr">3. Théorie de base des données biométriques : Science des données de la VFC et de la FCR
&lt;/h2>&lt;p>Plutôt qu&amp;rsquo;un simple indicateur tel que &amp;ldquo;c&amp;rsquo;est bien parce que le temps de sommeil est long&amp;rdquo;, du point de vue de la science des données, les deux indicateurs suivants deviennent les métriques maîtresses de la &amp;ldquo;Récupération (Recovery)&amp;rdquo;.&lt;/p>
&lt;h3 id="31-vfc-variabilité-de-la-fréquence-cardiaque--heart-rate-variability-et-modélisation-du-système-nerveux-autonome">3.1 VFC (Variabilité de la Fréquence Cardiaque : Heart Rate Variability) et modélisation du système nerveux autonome
&lt;/h3>&lt;p>Le cœur ne bat pas à un rythme constant comme un métronome. Par exemple, même si la fréquence cardiaque est de 60 bpm, l&amp;rsquo;intervalle entre chaque battement (intervalle R-R) fluctue constamment, comme &amp;ldquo;0,92 seconde&amp;rdquo;, &amp;ldquo;1,05 seconde&amp;rdquo;, &amp;ldquo;0,98 seconde&amp;rdquo;. Cette ampleur de fluctuation quantifiée est la VFC (variabilité de la fréquence cardiaque).&lt;/p>
&lt;p>La VFC reflète directement l&amp;rsquo;équilibre du système nerveux autonome, c&amp;rsquo;est-à-dire le système &amp;ldquo;sympathique (accélérateur)&amp;rdquo; et le système &amp;ldquo;parasympathique (frein)&amp;rdquo;. En cas de stress, de surmenage, ou après la consommation d&amp;rsquo;alcool, le système nerveux sympathique devient dominant, les battements du cœur se rapprochent de la constance et la VFC diminue. Inversement, dans un état suffisamment détendu et en cours de récupération, le système nerveux parasympathique (nerf vague) devient dominant, et le cœur fluctue de manière dynamique avec la respiration, ce qui augmente la VFC.&lt;/p>
&lt;p>Il existe deux approches pour calculer la VFC : le domaine temporel (Time-domain) et le domaine fréquentiel (Frequency-domain). Dans l&amp;rsquo;analyse du domaine temporel, la méthode la plus couramment utilisée, adoptée par l&amp;rsquo;Oura Ring et l&amp;rsquo;Apple Watch, est le &lt;strong>RMSSD (Root Mean Square of Successive Differences)&lt;/strong>. Il calcule la moyenne quadratique des différences successives entre les intervalles de battement cardiaque consécutifs (intervalles RR).&lt;/p>
&lt;p>Exprimé strictement par une formule mathématique, cela donne :&lt;/p>
$$ RMSSD = \sqrt{\frac{1}{N-1} \sum_{i=1}^{N-1} (RR_{i+1} - RR_i)^2} $$&lt;p>Où,&lt;/p>
&lt;ul>
&lt;li>$N$ est le nombre total de battements cardiaques mesurés&lt;/li>
&lt;li>$RR_i$ est le $i$-ème intervalle RR (en millisecondes)&lt;/li>
&lt;/ul>
&lt;p>Pour un ingénieur, si la VFC (RMSSD) au réveil le matin est significativement inférieure à sa ligne de base personnelle (moyenne mobile des dernières semaines), il est possible de prendre une décision basée sur les données : &amp;ldquo;Aujourd&amp;rsquo;hui est un jour où je devrais éviter les conceptions d&amp;rsquo;architecture à forte charge cognitive ou les déploiements en environnement de production, et me consacrer plutôt à l&amp;rsquo;enrichissement du code de test et à la rédaction de documentation.&amp;rdquo;&lt;/p>
&lt;h3 id="32-fréquence-cardiaque-au-repos-fcr--resting-heart-rate-et-signaux-de-récupération">3.2 Fréquence Cardiaque au Repos (FCR : Resting Heart Rate) et signaux de récupération
&lt;/h3>&lt;p>La FCR est le nombre de battements de cœur par minute lorsque le corps est dans un état de relaxation complète (généralement pendant le sommeil). Après la consommation d&amp;rsquo;alcool, une suralimentation tardive, ou en tant que premier symptôme d&amp;rsquo;une maladie (comme une infection), lorsque le corps alloue de l&amp;rsquo;énergie à son métabolisme interne ou à des réactions immunitaires, la FCR augmente de quelques bpm à plus d&amp;rsquo;une dizaine de bpm par rapport à la ligne de base.&lt;/p>
&lt;p>Plus la FCR est basse, plus cela signifie que le muscle cardiaque peut pomper beaucoup de sang à chaque battement (volume d&amp;rsquo;éjection systolique important), ce qui indique une grande capacité aérobie et le degré de récupération de la fatigue. Idéalement, une courbe en forme de &amp;ldquo;hamac&amp;rdquo; où la FCR atteint sa valeur minimale pendant la première moitié du sommeil est l&amp;rsquo;état dans lequel s&amp;rsquo;effectue la récupération de la meilleure qualité.&lt;/p>
&lt;h2 id="4-analyse-détaillée-de-larchitecture-du-sommeil">4. Analyse détaillée de l&amp;rsquo;architecture du sommeil
&lt;/h2>&lt;p>Ce qui détermine les performances du cerveau d&amp;rsquo;un ingénieur, ce n&amp;rsquo;est pas seulement la &amp;ldquo;quantité&amp;rdquo; de sommeil, mais sa &amp;ldquo;qualité&amp;rdquo;, c&amp;rsquo;est-à-dire l&amp;rsquo;architecture du sommeil (Sleep Architecture). Une nuit de sommeil répète généralement 4 à 5 fois un cycle de 90 à 110 minutes.&lt;/p>
&lt;h3 id="41-sommeil-nrem-stades-1-à-2-sommeil-léger--light-sleep">4.1 Sommeil NREM Stades 1 à 2 (Sommeil léger / Light Sleep)
&lt;/h3>&lt;p>C&amp;rsquo;est la phase de préparation où les ondes cérébrales ralentissent progressivement et où le corps commence à se détendre. Il représente environ 50 % de l&amp;rsquo;ensemble du sommeil. Bien que sa contribution à la récupération cognitive soit faible, il sert de pont important pour passer au stade suivant de sommeil profond.&lt;/p>
&lt;h3 id="42-sommeil-nrem-stade-3-sommeil-profond--deep-sleep--slow-wave-sleep--sws">4.2 Sommeil NREM Stade 3 (Sommeil profond / Deep Sleep / Slow Wave Sleep : SWS)
&lt;/h3>&lt;p>L&amp;rsquo;apparition d&amp;rsquo;ondes delta (basses fréquences de 0,5 à 2 Hz) sur l&amp;rsquo;électroencéphalogramme caractérise cette période qui est le cœur de la récupération physique et corporelle. Une grande quantité d&amp;rsquo;hormone de croissance est sécrétée et la réparation cellulaire a lieu. C&amp;rsquo;est également essentiel pour renforcer le système immunitaire, et cela est directement lié non seulement à la récupération de la fatigue musculaire des athlètes, mais aussi à la fatigue oculaire et à la réparation des muscles du cou et des épaules des ingénieurs. Le sommeil profond est généralement concentré dans les cycles de la première moitié du sommeil.&lt;/p>
&lt;h3 id="43-sommeil-rem-rapid-eye-movement">4.3 Sommeil REM (Rapid Eye Movement)
&lt;/h3>&lt;p>Le cerveau est aussi actif que pendant l&amp;rsquo;éveil, mais les muscles du corps sont paralysés. Ce sommeil REM est extrêmement important pour les ingénieurs ; il a pour rôle d&amp;rsquo;organiser dans le cerveau la syntaxe des nouveaux langages de programmation ou les concepts des algorithmes complexes appris pendant la journée, et de les fixer sous forme de mémoire à long terme (Memory Consolidation). Il augmente la neuroplasticité (Neuroplasticity), et la capacité de résolution créative de problèmes (comme l&amp;rsquo;inspiration soudaine d&amp;rsquo;une solution à un bug en prenant une douche) est également renforcée par le sommeil REM. Le sommeil REM a tendance à s&amp;rsquo;allonger dans la seconde moitié du sommeil (vers l&amp;rsquo;aube).&lt;/p>
&lt;p>En d&amp;rsquo;autres termes, &amp;ldquo;se forcer à se réveiller tôt avec une alarme et réduire son temps de sommeil&amp;rdquo; signifie réduire de manière drastique et localisée le sommeil REM impliqué dans la consolidation de la mémoire et la créativité, ce qui équivaut à un bug majeur dégradant considérablement les performances en tant qu&amp;rsquo;ingénieur.&lt;/p>
&lt;h2 id="5-mesure-continue-du-glucose-cgm-et-défense-contre-les-pics">5. Mesure continue du glucose (CGM) et défense contre les pics
&lt;/h2>&lt;p>Ces dernières années, l&amp;rsquo;introduction d&amp;rsquo;un CGM (Continuous Glucose Monitor : lecteur de glycémie en continu) est devenue incontournable parmi les biohackers. Les dispositifs représentatifs incluent FreeStyle Libre et Dexcom.
Lorsqu&amp;rsquo;on consomme de la nourriture (en particulier des glucides ou des sucres), la concentration de glucose dans le sang augmente rapidement (pic de glycémie), puis chute brutalement (crash) à cause d&amp;rsquo;une sécrétion massive d&amp;rsquo;insuline. C&amp;rsquo;est lors de ce &amp;ldquo;crash&amp;rdquo; qu&amp;rsquo;une somnolence intense (Brain Fog) et une baisse de concentration sont provoquées. La somnolence de la &amp;ldquo;démoniaque 14 heures&amp;rdquo; après le déjeuner n&amp;rsquo;est probablement pas seulement l&amp;rsquo;effet de l&amp;rsquo;horloge biologique, mais a de fortes chances d&amp;rsquo;être causée par un pic de glycémie dû à une consommation excessive de ramen ou de riz blanc.&lt;/p>
&lt;p>La courbe de réponse de la glycémie $G(t)$ peut être représentée de manière approximative comme un modèle d&amp;rsquo;oscillation amortie, traduisant la différence entre la vitesse d&amp;rsquo;absorption des glucides ingérés et la clairance par l&amp;rsquo;insuline, comme suit :&lt;/p>
$$ G(t) = G_{base} + \Delta G \cdot e^{-\alpha t} \sin(\beta t) $$&lt;p>Où,&lt;/p>
&lt;ul>
&lt;li>$G_{base}$ : Glycémie à jeun (ligne de base)&lt;/li>
&lt;li>$\Delta G$ : Amplitude de l&amp;rsquo;augmentation de la glycémie due au repas&lt;/li>
&lt;li>$\alpha$ : Coefficient d&amp;rsquo;atténuation basé sur la sensibilité à l&amp;rsquo;insuline et le taux métabolique&lt;/li>
&lt;li>$\beta$ : Composante fréquentielle de l&amp;rsquo;oscillation&lt;/li>
&lt;li>$t$ : Temps écoulé après le repas&lt;/li>
&lt;/ul>
&lt;p>Pour maintenir les performances d&amp;rsquo;un ingénieur, il est important de minimiser l&amp;rsquo;amplitude $\Delta G$. Concrètement, des hacks comme &amp;ldquo;manger d&amp;rsquo;abord les légumes (fibres alimentaires)&amp;rdquo;, &amp;ldquo;éviter les glucides raffinés&amp;rdquo;, et &amp;ldquo;faire une légère promenade de 15 minutes après le repas (pour activer les transporteurs GLUT4 et absorber le glucose dans les muscles indépendamment de l&amp;rsquo;insuline)&amp;rdquo; sont efficaces.&lt;/p>
&lt;h2 id="6-conception-de-larchitecture--construction-dun-pipeline-de-données-local">6. Conception de l&amp;rsquo;architecture : Construction d&amp;rsquo;un pipeline de données local
&lt;/h2>&lt;p>Nous allons construire un pipeline de données local pour analyser conjointement les données biométriques et les données de productivité.
Le diagramme Mermaid suivant (organigramme) montre le flux depuis la récupération des données via l&amp;rsquo;API jusqu&amp;rsquo;à leur visualisation sur un tableau de bord.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;API Oura Ring (Biométrie)&amp;#34;] --&amp;gt;|JSON via OAuth2| C[&amp;#34;Pipeline d&amp;#39;ingestion de données Python&amp;#34;]
B[&amp;#34;API WakaTime (Temps de code)&amp;#34;] --&amp;gt;|JSON via clé API| C
E[&amp;#34;API SwitchBot (Temp. de la pièce / CO2)&amp;#34;] --&amp;gt;|JSON via clé API| C
C --&amp;gt;|Extraire &amp;amp; Transformer| D[&amp;#34;Pandas DataFrame (Mémoire)&amp;#34;]
D --&amp;gt;|Charger| F[&amp;#34;TimescaleDB / PostgreSQL&amp;#34;]
F --&amp;gt; G[&amp;#34;Jupyter Notebook (Analyse Ad-hoc)&amp;#34;]
F --&amp;gt; H[&amp;#34;Application Web Streamlit (Surveillance Quotidienne)&amp;#34;]
&lt;/pre>
&lt;p>Grâce à cette architecture, on pourra surveiller automatiquement et quotidiennement la corrélation entre sa propre condition physique (input) et ses performances de codage (output).&lt;/p>
&lt;p>De plus, examinons en détail la séquence entre les systèmes.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant U as &amp;#34;Utilisateur (Ingénieur)&amp;#34;
participant W as &amp;#34;Plugin WakaTime (VS Code)&amp;#34;
participant O as &amp;#34;Oura Ring &amp;amp; API&amp;#34;
participant S as &amp;#34;Batch ETL Python&amp;#34;
participant DB as &amp;#34;TimescaleDB&amp;#34;
U-&amp;gt;&amp;gt;W: &amp;#34;Écrire du code (Frappe au clavier)&amp;#34;
W--&amp;gt;&amp;gt;W: &amp;#34;Enregistrer le battement de cœur du codage précis&amp;#34;
U-&amp;gt;&amp;gt;O: &amp;#34;Dormir (Porter l&amp;#39;anneau)&amp;#34;
O--&amp;gt;&amp;gt;O: &amp;#34;Enregistrer VFC, FCR, Temp &amp;amp; Stades de sommeil&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;Nettoyer et Fusionner les Données (Pandas)&amp;#34;
S-&amp;gt;&amp;gt;DB: &amp;#34;INSERT INTO daily_metrics&amp;#34;
Note over S,DB: &amp;#34;Planifié via Cron / Airflow&amp;#34;
&lt;/pre>
&lt;h2 id="7-ingestion-de-données-avec-python-et-pandas">7. Ingestion de données avec Python et Pandas
&lt;/h2>&lt;p>Regardons comment récupérer les données depuis les API Oura Ring et WakaTime en utilisant un script Python, et comment les intégrer en tant que DataFrame Pandas. Nous construirons un code robuste capable de supporter une utilisation en production.&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"># Environment Variables&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;Fetch daily sleep summary from 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"># Raise exception for 4xx/5xx errors&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"># Extract deeply nested values or select essential columns&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"># Convert dates to datetime objects and set as index&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;Fetch coding duration summaries from 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"># Extract total seconds spent coding&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"># Fetch data for the last 60 days&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"># Merge datasets on &amp;#39;day&amp;#39; index using inner join&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"># Save raw data to 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-prétraitement-des-données-et-ingénierie-des-caractéristiques">8. Prétraitement des données et Ingénierie des caractéristiques
&lt;/h2>&lt;p>Il est dangereux de soumettre directement les données brutes acquises à une analyse. Il est nécessaire de traiter les valeurs manquantes (Missing Values) dues à l&amp;rsquo;oubli de la recharge des appareils, et de générer de nouveaux indicateurs pertinents (Ingénierie des caractéristiques : 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;Apply feature engineering and cleaning to the merged 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. Handle missing values (e.g., forward fill)&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. Calculate Sleep Efficiency&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Formula: (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. Calculate Sleep Stage Ratios&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. Calculate 7-day Moving Averages (Rolling Mean) to smooth out daily noise&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. Calculate daily deviation from baseline&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. Normalize targets for Machine Learning (Optional)&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"># Drop rows with NaN generated by rolling window&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-analyse-de-corrélation--lintersection-entre-la-productivité-et-les-métriques-de-santé">9. Analyse de corrélation : L&amp;rsquo;intersection entre la productivité et les métriques de santé
&lt;/h2>&lt;p>À partir des données prétraitées, nous analysons la relation entre les indicateurs de santé et la productivité du codage. En tant qu&amp;rsquo;hypothèse, on peut penser que &amp;ldquo;plus la VFC est élevée (le système nerveux autonome est équilibré et on a récupéré) un jour donné, plus la concentration dure, ce qui allonge le temps de codage ou permet de traiter des tâches plus complexes&amp;rdquo;.&lt;/p>
&lt;pre class="mermaid">
xychart-beta
title VFC vs Heures de codage quotidiennes (Normalisées)
x-axis [&amp;#34;Lun&amp;#34;, &amp;#34;Mar&amp;#34;, &amp;#34;Mer&amp;#34;, &amp;#34;Jeu&amp;#34;, &amp;#34;Ven&amp;#34;, &amp;#34;Sam&amp;#34;, &amp;#34;Dim&amp;#34;]
y-axis &amp;#34;VFC &amp;amp; Sortie de codage&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>(Remarque : le graphique en courbes montre l&amp;rsquo;écart par rapport à la ligne de base de la VFC normalisée, et le graphique en barres montre le temps de codage de WakaTime. On peut observer une corrélation où les résultats de codage sont maximisés de mercredi à vendredi, lorsqu&amp;rsquo;une récupération suffisante est obtenue)&lt;/em>&lt;/p>
&lt;p>Nous calculons le coefficient de corrélation (coefficient de corrélation de Pearson $r$) avec Pandas, et effectuons un test de signification statistique (valeur p) en utilisant SciPy.&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"># Select numerical columns for correlation matrix&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"># Calculate Pearson correlation coefficient and p-value for REM sleep and Coding Hours&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>Dans de nombreux cas, une corrélation positive significative ($p &lt; 0.05$) est observée entre &lt;code>average_hrv&lt;/code> ou &lt;code>rem_sleep_duration&lt;/code> et &lt;code>coding_hours&lt;/code>. En particulier, il est rapporté dans de nombreuses communautés de quantification de soi (Quantified Self) d&amp;rsquo;ingénieurs que la durée du sommeil REM de la nuit précédente influence fortement &amp;ldquo;le temps passé à résoudre les erreurs (débogage)&amp;rdquo; et &amp;ldquo;la productivité&amp;rdquo; du jour en cours.&lt;/p>
&lt;h2 id="10-modèle-mathématique-du-rythme-circadien-et-optimisation-du-pic-cognitif">10. Modèle mathématique du rythme circadien et optimisation du pic cognitif
&lt;/h2>&lt;p>L&amp;rsquo;être humain est doté d&amp;rsquo;une horloge biologique d&amp;rsquo;une période d&amp;rsquo;environ 24 heures appelée rythme circadien (Circadian Rhythm). En fonction de ce rythme, la température corporelle, la sécrétion hormonale (pic de cortisol le matin et sécrétion de mélatonine la nuit), ainsi que &amp;ldquo;les capacités cognitives&amp;rdquo; fluctuent.&lt;/p>
&lt;p>La fluctuation du rythme circadien est souvent modélisée mathématiquement à l&amp;rsquo;aide d&amp;rsquo;une courbe cosinusoïdale (modèle Cosinor), et la variation d&amp;rsquo;un indicateur biométrique peut être formulée de la manière suivante :&lt;/p>
$$ y(t) = M + A \cos\left(\frac{2\pi}{24}(t - \phi)\right) + e(t) $$&lt;ul>
&lt;li>$y(t)$ : Indicateur biométrique à l&amp;rsquo;instant $t$ (ex. : température corporelle centrale ou niveau d&amp;rsquo;éveil)&lt;/li>
&lt;li>$M$ : MESOR (Midline Estimating Statistic of Rhythm) - Valeur centrale du rythme (niveau moyen)&lt;/li>
&lt;li>$A$ : Amplitude (Amplitude) - Ampleur de la fluctuation&lt;/li>
&lt;li>$\phi$ : Acrophase (Acrophase) - Phase du pic (heure)&lt;/li>
&lt;li>$e(t)$ : Terme d&amp;rsquo;erreur dû aux facteurs environnementaux, etc.&lt;/li>
&lt;/ul>
&lt;p>Dans le domaine de l&amp;rsquo;ingénierie, cette équation signifie que &amp;ldquo;la plage horaire où la performance (le niveau d&amp;rsquo;éveil) atteint son maximum dans une journée ($\phi$) est biologiquement déterminée, et c&amp;rsquo;est dans cette plage horaire qu&amp;rsquo;il faut allouer les tâches ayant la plus forte charge cognitive (correction de bugs complexes, conception de nouvelle architecture)&amp;rdquo;.&lt;/p>
&lt;p>Dans le cas d&amp;rsquo;un chronotype matinal typique (Morning Lark), le premier pic cognitif survient 2 à 4 heures après le réveil (par exemple de 9 h à 11 h). Ensuite, vers 14 h survient un creux du rythme circadien (Post-lunch dip), et un autre petit pic survient le soir. Le meilleur hack de santé consiste à identifier son temps de pic personnel ($\phi$) à partir des niveaux d&amp;rsquo;activité de ses appareils portables ou de son niveau de concentration subjectif, et à bloquer ce temps (&amp;ldquo;time blocking&amp;rdquo;) sur Google Calendar, par exemple, pour le protéger. Placer une réunion insignifiante pendant son heure de pointe revient à allouer le cœur de CPU le plus performant à un processus inactif.&lt;/p>
&lt;h2 id="11-pharmacocinétique-de-la-caféine-et-moment-optimal-de-consommation">11. Pharmacocinétique de la caféine et moment optimal de consommation
&lt;/h2>&lt;p>Les ingénieurs et le café sont indissociables, mais la surconsommation de caféine ou une consommation tardive bloque les récepteurs d&amp;rsquo;adénosine dans le cerveau et détruit le &amp;ldquo;sommeil profond (Deep Sleep)&amp;rdquo; la nuit. Même si vous avez subjectivement l&amp;rsquo;impression de bien dormir, en regardant les données de l&amp;rsquo;Oura Ring, vous pouvez constater que votre fréquence cardiaque ne baisse pas et que le pourcentage de sommeil profond a chuté drastiquement.&lt;/p>
&lt;p>L&amp;rsquo;élimination de la caféine de l&amp;rsquo;organisme suit une cinétique de premier ordre (First-order kinetics). En d&amp;rsquo;autres termes, la concentration sanguine diminue de manière exponentielle.&lt;/p>
$$ C(t) = C_0 e^{-k t} $$&lt;p>Où,&lt;/p>
&lt;ul>
&lt;li>$C(t)$ : Concentration sanguine de caféine après un temps écoulé $t$&lt;/li>
&lt;li>$C_0$ : Concentration initiale (concentration maximale immédiatement après l&amp;rsquo;ingestion)&lt;/li>
&lt;li>$k$ : Constante de vitesse d&amp;rsquo;élimination&lt;/li>
&lt;li>$t$ : Temps écoulé depuis l&amp;rsquo;ingestion (heures)&lt;/li>
&lt;/ul>
&lt;p>La constante de vitesse d&amp;rsquo;élimination $k$ s&amp;rsquo;exprime de la manière suivante en utilisant la demi-vie de la caféine ($t_{1/2}$) :&lt;/p>
$$ k = \frac{\ln(2)}{t_{1/2}} $$&lt;p>Pour un adulte en bonne santé, bien que cela dépende de la génétique de chacun (gène CYP1A2), la demi-vie de la caféine $t_{1/2}$ est considérée comme étant d&amp;rsquo;environ &lt;strong>5 à 6 heures&lt;/strong>.
Supposons, par exemple, que vous buviez 1 tasse de café filtre (environ 150 mg de caféine) à 15 heures ($C_0 = 150$). En supposant une demi-vie de 5,5 heures, $k \approx 0,126$.
Si nous calculons la concentration de caféine résiduelle dans le corps à l&amp;rsquo;heure du coucher, disons 23 heures (8 heures plus tard) :&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>Autrement dit, même à l&amp;rsquo;heure du coucher, il reste encore 54 mg de caféine (un peu plus d&amp;rsquo;un espresso) dans votre corps, ce qui affecte directement et négativement votre architecture du sommeil.
La conclusion basée sur les données qui découle de ce modèle pharmacocinétique est la suivante : &lt;strong>&amp;ldquo;Pour assurer un sommeil de haute qualité, la consommation de caféine devrait commencer au moins 90 minutes après le réveil (une fois que le pic de cortisol s&amp;rsquo;est calmé), et devrait être complètement arrêtée au plus tard à 14 heures (9 à 10 heures avant le coucher).&amp;rdquo;&lt;/strong>&lt;/p>
&lt;h2 id="12-hacking-des-variables-denvironnement-lux-température-co2">12. Hacking des variables d&amp;rsquo;environnement (Lux, Température, CO2)
&lt;/h2>&lt;p>Il est important d&amp;rsquo;optimiser non seulement le système interne de son propre corps, mais aussi les variables de l&amp;rsquo;environnement extérieur (Environment Variables).&lt;/p>
&lt;h3 id="121-programmation-de-lenvironnement-lumineux-lux">12.1 Programmation de l&amp;rsquo;environnement lumineux (Lux)
&lt;/h3>&lt;p>Le &amp;ldquo;Zeitgeber (indice qui donne l&amp;rsquo;heure)&amp;rdquo; le plus puissant pour réinitialiser le rythme circadien est la lumière. Le matin, lorsqu&amp;rsquo;environ 100 000 Lux de lumière solaire pénètrent dans les cellules réceptrices de lumière de la rétine (ipRGC), la sécrétion de mélatonine s&amp;rsquo;arrête et le minuteur est réinitialisé. Inversement, la nuit, il est impératif de bloquer la lumière bleue et de ne pas inhiber la sécrétion de mélatonine. Il est efficace non seulement de réduire la température de couleur de l&amp;rsquo;écran avec un logiciel comme f.lux, mais aussi de contrôler les lumières intelligentes (comme Philips Hue) via API, en créant un script pour baisser automatiquement l&amp;rsquo;éclairement et la température de couleur de la pièce à la tombée de la nuit.&lt;/p>
&lt;h3 id="122-contrôle-de-la-température-de-la-chambre-et-latence-dendormissement-sleep-latency">12.2 Contrôle de la température de la chambre et Latence d&amp;rsquo;endormissement (Sleep Latency)
&lt;/h3>&lt;p>L&amp;rsquo;être humain s&amp;rsquo;endort lorsque sa température corporelle centrale (Core Body Temperature) baisse. En gardant la chambre à coucher fraîche à 18-19 degrés et en se glissant sous les couvertures au moment où la température corporelle centrale (que l&amp;rsquo;on a temporairement élevée en prenant un bain chaud 90 minutes avant le coucher) chute rapidement, on peut raccourcir de manière drastique la latence d&amp;rsquo;endormissement (Sleep Latency : temps écoulé entre le moment où l&amp;rsquo;on se met au lit et celui où l&amp;rsquo;on s&amp;rsquo;endort) et maximiser le sommeil profond.&lt;/p>
&lt;h3 id="123-concentration-de-co2-et-déclin-des-fonctions-cognitives">12.3 Concentration de CO2 et déclin des fonctions cognitives
&lt;/h3>&lt;p>Si l&amp;rsquo;on ajoute l&amp;rsquo;API d&amp;rsquo;un hub SwitchBot ou d&amp;rsquo;une station météo Netatmo au pipeline de données, on constate une corrélation négative claire entre la concentration de dioxyde de carbone (CO2) à l&amp;rsquo;intérieur et la productivité.
Comme le montrent des études de l&amp;rsquo;Université de Harvard, etc., lorsque la concentration de CO2 dépasse 1000 ppm, les fonctions cognitives (en particulier la capacité de prise de décision stratégique) commencent à diminuer de manière significative, et au-delà de 2000 ppm, cela entraîne une baisse de performance sévère. Le travail à distance dans une pièce fermée en hiver fait baisser vos performances sans que vous vous en rendiez compte.&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"># Pseudo-code for intelligent room ventilation using 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"># Get current CO2 level from Netatmo/SwitchBot API&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"># Trigger smart plug to turn on ventilation fan&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"># Send notification to 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;Le ventilateur de ventilation a été démarré. La concentration en CO2 est élevée.&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>En exécutant régulièrement un tel script avec Cron, on complète un système de contrôle de l&amp;rsquo;environnement autonome qui maintient constamment une concentration optimale en oxygène.&lt;/p>
&lt;h2 id="13-conclusion--cicd-pour-le-système-du-corps-humain">13. Conclusion : CI/CD pour le système du corps humain
&lt;/h2>&lt;p>Essayez de considérer votre propre corps comme un système distribué complexe. L&amp;rsquo;appareil portable (Oura Ring) est l&amp;rsquo;exportateur de métriques pour la surveillance (Prometheus), les scripts Python/Pandas sont le pipeline d&amp;rsquo;analyse des logs (Logstash/Fluentd), et les changements quotidiens de l&amp;rsquo;état physique ou des performances représentent la santé du système affichée sur un tableau de bord (Grafana/Streamlit).&lt;/p>
&lt;p>&amp;ldquo;Travailler en réduisant son temps de sommeil&amp;rdquo; équivaut à forcer l&amp;rsquo;ajout de fonctionnalités en ignorant la dette technique (Technical Debt). Cela peut permettre de respecter une date de livraison à court terme, mais à long terme, cela provoquera inévitablement une panne du système (burn-out, graves problèmes de santé, dépression).&lt;/p>
&lt;p>Surveiller la VFC, vérifier les tendances de la FCR, et optimiser l&amp;rsquo;architecture du sommeil. Et peaufiner quotidiennement les &amp;ldquo;hyperparamètres&amp;rdquo; que sont l&amp;rsquo;alimentation, l&amp;rsquo;exercice, le sommeil et l&amp;rsquo;environnement tout en observant la corrélation avec les données de productivité de WakaTime. Cela n&amp;rsquo;est rien d&amp;rsquo;autre qu&amp;rsquo;un processus de &lt;strong>CI/CD (Intégration Continue / Déploiement Continu)&lt;/strong> appliqué au corps humain.&lt;/p>
&lt;p>En tirant parti de la science des données et des API, concevons un état de santé capable de libérer nos meilleures performances. Car la qualité du code que vous écrivez est directement liée à la santé de votre propre système biologique.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Avertissement : Cet article compile les expériences personnelles de l&amp;rsquo;auteur et son approche en science des données, et ne fournit pas de conseils médicaux. En cas de mauvaise santé persistante ou de troubles du sommeil, veuillez consulter une institution médicale spécialisée.&lt;/em>&lt;/p></description></item></channel></rss>