<?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/es/tags/biohacking/</link><description>Recent content in Biohacking on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>es</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 12:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/es/tags/biohacking/index.xml" rel="self" type="application/rss+xml"/><item><title>El día a día de un ingeniero que gestiona su salud con anillos inteligentes (Hackeos de Salud)</title><link>http://kenji.blog/es/p/engineer-health-hacks-wearables/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 El día a día de un ingeniero que gestiona su salud con anillos inteligentes (Hackeos de Salud)" />&lt;h2 id="1-introducción-la-intersección-entre-la-ingeniería-de-software-y-el-biohacking">1. Introducción: La intersección entre la ingeniería de software y el biohacking
&lt;/h2>&lt;p>La ingeniería de software moderna es un trabajo intelectual agotador que implica una carga cognitiva extrema y un estilo de vida sedentario (Sedentary Lifestyle). Estar al día con la pila de tecnología en constante cambio, cazar errores en sistemas distribuidos complejos y la presión de las fechas de entrega. Para superar esto, en lugar de depender únicamente del &amp;ldquo;espíritu&amp;rdquo; y la &amp;ldquo;fuerza de voluntad&amp;rdquo;, es indispensable un enfoque de ajuste del hardware que es nuestro propio cuerpo, como si estuviéramos depurando un sistema, es decir, el &amp;ldquo;Biohacking&amp;rdquo;.&lt;/p>
&lt;p>En el pasado, dependíamos de sentimientos subjetivos (heurísticas) como &amp;ldquo;hoy me siento más o menos bien/mal&amp;rdquo;, pero en la actualidad, con la popularización de dispositivos portátiles de alto rendimiento como Oura Ring, Apple Watch y Garmin, es posible obtener datos biométricos de forma no invasiva las 24 horas del día, los 365 días del año. En este artículo, explicaremos cómo obtener datos biométricos (VFC, FCR y arquitectura del sueño) y datos de productividad (métricas de codificación mediante WakaTime, etc.) a través de una API, y realizar un análisis de correlación con un enfoque de ciencia de datos utilizando Python y Pandas. Además, desentrañaremos con gran detalle hackeos de salud para ingenieros basados en evidencia científica, como el modelo matemático del ritmo circadiano y el momento óptimo para consumir café según la vida media del metabolismo de la cafeína.&lt;/p>
&lt;h2 id="2-lo-que-no-se-puede-medir-no-se-puede-gestionar-hardware-para-la-adquisición-de-datos-biométricos">2. Lo que no se puede medir, no se puede gestionar: Hardware para la adquisición de datos biométricos
&lt;/h2>&lt;p>Los sensores (dispositivos portátiles) para obtener datos biométricos tienen sus propias áreas de especialidad. En la gestión de la salud basada en datos, el primer paso es seleccionar el dispositivo óptimo según el objetivo.&lt;/p>
&lt;h3 id="21-oura-ring-generación-3--4">2.1 Oura Ring (Generación 3 / 4)
&lt;/h3>&lt;p>Al obtener datos directamente desde las arterias del dedo, su precisión para medir la frecuencia cardíaca durante el sueño, la variabilidad de la frecuencia cardíaca (VFC) y los cambios en la temperatura de la superficie corporal es muy alta en comparación con los relojes inteligentes que miden en la muñeca. Los dedos están densamente poblados de capilares, lo que permite la obtención de datos con menos ruido utilizando un sensor óptico de frecuencia cardíaca (PPG: Fotopletismografía). Además, cuenta con una rica API REST que permite exportar fácilmente datos sin procesar en formato JSON a través de OAuth2.0, lo que lo convierte en el dispositivo más hackeable para los ingenieros.&lt;/p>
&lt;h3 id="22-apple-watch-series--ultra">2.2 Apple Watch Series / Ultra
&lt;/h3>&lt;p>Destaca en el seguimiento durante la actividad y en la medición de la saturación de oxígeno en sangre (SpO2) y electrocardiogramas (ECG). Es el mejor dispositivo para medir la VFC bajo demanda a través del volumen de actividad diurna y la aplicación de atención plena (aplicación de respiración). Sin embargo, exportar los datos requiere pasar por HealthKit, por lo que el acceso directo desde Python, etc., necesita un paso intermedio, como la exportación a CSV a través de una aplicación de iOS (como AutoSleep o HealthFit).&lt;/p>
&lt;h3 id="23-garmin-fenix--forerunner">2.3 Garmin (Fenix / Forerunner)
&lt;/h3>&lt;p>Además de la precisión de su seguimiento GPS, destaca por su exclusivo indicador de energía restante llamado &amp;ldquo;Body Battery&amp;rdquo; (Batería Corporal). Se calcula en base a la VFC y el nivel de estrés. Se puede acceder a los datos de Garmin a través de la API Garmin Connect, pero debido a la barrera de la API corporativa, los desarrolladores individuales deben utilizar bibliotecas de código abierto o herramientas de web scraping creadas por voluntarios.&lt;/p>
&lt;p>En este artículo, centraremos la explicación principalmente en los datos del &lt;strong>Oura Ring&lt;/strong>, que es supremo en el seguimiento del sueño y la recuperación y cuya extracción de datos de la API es extremadamente fácil, y los datos de &lt;strong>WakaTime&lt;/strong>, que mide el tiempo de codificación como un complemento del IDE (VS Code, IntelliJ, etc.).&lt;/p>
&lt;h2 id="3-teoría-básica-de-los-datos-biométricos-ciencia-de-datos-de-la-vfc-y-la-fcr">3. Teoría básica de los datos biométricos: Ciencia de datos de la VFC y la FCR
&lt;/h2>&lt;p>Desde la perspectiva de la ciencia de datos, en lugar de un indicador simple como &amp;ldquo;dormir más es mejor&amp;rdquo;, los siguientes dos indicadores son las métricas maestras de la &amp;ldquo;Recuperación (Recovery)&amp;rdquo;.&lt;/p>
&lt;h3 id="31-vfc-variabilidad-de-la-frecuencia-cardíaca-heart-rate-variability-y-modelado-del-sistema-nervioso-autónomo">3.1 VFC (Variabilidad de la Frecuencia Cardíaca: Heart Rate Variability) y modelado del sistema nervioso autónomo
&lt;/h3>&lt;p>El corazón no late con un ritmo constante como un metrónomo. Por ejemplo, incluso si la frecuencia cardíaca es de 60 lpm, el intervalo entre cada latido (intervalo R-R) fluctúa constantemente, como &amp;ldquo;0.92 segundos&amp;rdquo;, &amp;ldquo;1.05 segundos&amp;rdquo;, &amp;ldquo;0.98 segundos&amp;rdquo;. La cuantificación de la magnitud de esta fluctuación es la VFC (Variabilidad de la Frecuencia Cardíaca).&lt;/p>
&lt;p>La VFC refleja directamente el equilibrio del sistema nervioso autónomo, es decir, el &amp;ldquo;sistema nervioso simpático (acelerador)&amp;rdquo; y el &amp;ldquo;sistema nervioso parasimpático (freno)&amp;rdquo;. En estados de estrés, exceso de trabajo o después del consumo de alcohol, el sistema nervioso simpático se vuelve dominante, los latidos del corazón se vuelven más constantes y la VFC disminuye. Por el contrario, en un estado de relajación total y recuperación, el sistema nervioso parasimpático (nervio vago) es dominante, y la frecuencia cardíaca fluctúa dinámicamente con la respiración, por lo que la VFC es alta.&lt;/p>
&lt;p>Existen dos enfoques para calcular la VFC: el dominio del tiempo (Time-domain) y el dominio de la frecuencia (Frequency-domain). En el análisis del dominio del tiempo, el más comúnmente utilizado y adoptado por Oura Ring y Apple Watch es el &lt;strong>RMSSD (Root Mean Square of Successive Differences, Raíz Cuadrada Media de las Diferencias Sucesivas)&lt;/strong>. Esto calcula la raíz cuadrada media de las diferencias al cuadrado de los intervalos de latidos consecutivos (intervalos RR).&lt;/p>
&lt;p>Matemáticamente, se expresa estrictamente de la siguiente manera:&lt;/p>
$$ RMSSD = \sqrt{\frac{1}{N-1} \sum_{i=1}^{N-1} (RR_{i+1} - RR_i)^2} $$&lt;p>Donde,&lt;/p>
&lt;ul>
&lt;li>$N$ es el número total de latidos cardíacos medidos&lt;/li>
&lt;li>$RR_i$ es el $i$-ésimo intervalo RR (milisegundos)&lt;/li>
&lt;/ul>
&lt;p>Para un ingeniero, si la VFC (RMSSD) al despertar por la mañana cae significativamente por debajo de su línea base personal (promedio móvil de las últimas semanas), le permite tomar una decisión basada en datos: &amp;ldquo;Hoy es un día en el que debo evitar el diseño de arquitectura con alta carga cognitiva y los despliegues en el entorno de producción, y dedicarme a ampliar el código de prueba y redactar documentación&amp;rdquo;.&lt;/p>
&lt;h3 id="32-frecuencia-cardíaca-en-reposo-fcr-resting-heart-rate-y-las-señales-de-recuperación">3.2 Frecuencia Cardíaca en Reposo (FCR: Resting Heart Rate) y las señales de recuperación
&lt;/h3>&lt;p>La FCR es la cantidad de latidos por minuto cuando el cuerpo está completamente relajado (generalmente durante el sueño). Cuando el cuerpo está dedicando energía a reacciones inmunológicas o metabólicas internas, como después de consumir alcohol, comer en exceso a altas horas de la noche, o como síntoma inicial de una enfermedad (como una infección), la FCR aumenta de varios a una decena de lpm por encima de la línea base.&lt;/p>
&lt;p>Cuanto más baja sea la FCR, significa que el músculo cardíaco puede bombear más sangre en un solo latido (mayor volumen sistólico), lo que indica un alto nivel de capacidad aeróbica y el grado de recuperación de la fatiga. Idealmente, el estado de recuperación de mayor calidad se alcanza cuando la FCR describe una curva en &amp;ldquo;forma de hamaca&amp;rdquo;, alcanzando su valor más bajo en la primera mitad del sueño.&lt;/p>
&lt;h2 id="4-análisis-detallado-de-la-arquitectura-del-sueño">4. Análisis detallado de la arquitectura del sueño
&lt;/h2>&lt;p>Lo que determina el rendimiento cerebral de un ingeniero no es solo la &amp;ldquo;cantidad&amp;rdquo; de sueño, sino su &amp;ldquo;calidad&amp;rdquo;, es decir, la arquitectura del sueño (Sleep Architecture). Una noche de sueño suele repetir de 4 a 5 ciclos de 90 a 110 minutos.&lt;/p>
&lt;h3 id="41-sueño-nrem-etapas-1-2-sueño-ligero--light-sleep">4.1 Sueño NREM Etapas 1-2 (Sueño ligero / Light Sleep)
&lt;/h3>&lt;p>Es la etapa de preparación donde las ondas cerebrales se ralentizan gradualmente y el cuerpo comienza a relajarse. Ocupa aproximadamente el 50% del sueño total. Aunque su contribución a la recuperación cognitiva es pequeña, es un puente importante para la transición a las siguientes etapas de sueño profundo.&lt;/p>
&lt;h3 id="42-sueño-nrem-etapa-3-sueño-profundo--deep-sleep--slow-wave-sleep-sws">4.2 Sueño NREM Etapa 3 (Sueño profundo / Deep Sleep / Slow Wave Sleep: SWS)
&lt;/h3>&lt;p>Aparecen las ondas delta (baja frecuencia de 0.5 a 2Hz) en el cerebro; es el momento central para la recuperación física del cuerpo. Se segregan grandes cantidades de hormona del crecimiento y se realiza la reparación celular. Es indispensable para fortalecer el sistema inmunológico, y está directamente relacionado no solo con la recuperación de la fatiga muscular en los atletas, sino también con la fatiga ocular y la reparación de los músculos del cuello y los hombros en los ingenieros. El sueño profundo generalmente se concentra en los primeros ciclos del sueño.&lt;/p>
&lt;h3 id="43-sueño-rem-movimiento-ocular-rápido--rapid-eye-movement">4.3 Sueño REM (Movimiento Ocular Rápido / Rapid Eye Movement)
&lt;/h3>&lt;p>El cerebro está tan activo como cuando está despierto, pero los músculos del cuerpo están paralizados. Este sueño REM es extremadamente importante para los ingenieros; es responsable de organizar en el cerebro la sintaxis de un nuevo lenguaje de programación o los conceptos de un algoritmo complejo aprendidos durante el día, y consolidarlos en la memoria a largo plazo (Memory Consolidation). Aumenta la neuroplasticidad (Neuroplasticity), y las habilidades creativas para la resolución de problemas (esa &amp;ldquo;inspiración repentina para solucionar un error mientras te duchas&amp;rdquo;) también se fortalecen con el sueño REM. El sueño REM tiende a ser más largo en la segunda mitad del sueño (hacia el amanecer).&lt;/p>
&lt;p>En otras palabras, &amp;ldquo;despertarse a la fuerza temprano con una alarma reduciendo el tiempo de sueño&amp;rdquo; significa reducir drásticamente de forma localizada el sueño REM, que está relacionado con la consolidación de la memoria y la creatividad, lo que equivale a un error grave que reduce significativamente el rendimiento como ingeniero.&lt;/p>
&lt;h2 id="5-monitorización-continua-de-glucosa-mcg-y-defensa-contra-los-picos">5. Monitorización Continua de Glucosa (MCG) y defensa contra los picos
&lt;/h2>&lt;p>Recientemente, la adopción de MCG (Monitores Continuos de Glucosa) se ha vuelto esencial entre los biohackers. Dispositivos representativos incluyen FreeStyle Libre y Dexcom.
Al ingerir alimentos (especialmente carbohidratos y azúcares), la concentración de glucosa en la sangre aumenta drásticamente (pico de glucosa en sangre) y luego cae en picado (choque) debido a la secreción masiva de insulina. En el momento de este &amp;ldquo;choque&amp;rdquo;, se produce una fuerte somnolencia (Niebla Mental / Brain Fog) y una pérdida de concentración. La somnolencia de la &amp;ldquo;maldita hora de las 2 de la tarde&amp;rdquo; después del almuerzo tiene muchas probabilidades de ser causada por un pico de glucosa en sangre debido a la ingesta excesiva de ramen o arroz blanco, y no simplemente por la influencia del reloj biológico.&lt;/p>
&lt;p>La curva de respuesta de la glucosa en sangre $G(t)$ se puede expresar aproximadamente como un modelo de oscilación amortiguada de la siguiente manera, como la diferencia entre la tasa de absorción de los carbohidratos ingeridos y la tasa de eliminación de la glucosa por la insulina.&lt;/p>
$$ G(t) = G_{base} + \Delta G \cdot e^{-\alpha t} \sin(\beta t) $$&lt;p>Donde,&lt;/p>
&lt;ul>
&lt;li>$G_{base}$: Nivel de glucosa en ayunas (línea base)&lt;/li>
&lt;li>$\Delta G$: Amplitud del aumento de la glucosa en sangre debido a las comidas&lt;/li>
&lt;li>$\alpha$: Coeficiente de atenuación basado en la sensibilidad a la insulina y la tasa metabólica&lt;/li>
&lt;li>$\beta$: Componente de frecuencia de la oscilación&lt;/li>
&lt;li>$t$: Tiempo transcurrido después de la comida&lt;/li>
&lt;/ul>
&lt;p>Para mantener el rendimiento del ingeniero, es importante mantener la amplitud $\Delta G$ al mínimo. Específicamente, son efectivos hackeos como &amp;ldquo;comer primero las verduras (fibra dietética)&amp;rdquo;, &amp;ldquo;evitar los carbohidratos refinados&amp;rdquo; y &amp;ldquo;dar un paseo ligero de 15 minutos después de las comidas (activa los transportadores GLUT4 para absorber glucosa en los músculos independientemente de la insulina)&amp;rdquo;.&lt;/p>
&lt;h2 id="6-diseño-de-la-arquitectura-construcción-del-pipeline-de-datos-local">6. Diseño de la arquitectura: Construcción del pipeline de datos local
&lt;/h2>&lt;p>Construiremos un pipeline de datos local para analizar de forma conjunta los datos biométricos y de productividad.
El siguiente diagrama de Mermaid (diagrama de flujo) muestra el flujo desde la obtención de datos desde las API hasta su visualización en un panel.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;API de Oura Ring (Biometría)&amp;#34;] --&amp;gt;|JSON via OAuth2| C[&amp;#34;Pipeline de Ingestión de Datos de Python&amp;#34;]
B[&amp;#34;API de WakaTime (Tiempo de Código)&amp;#34;] --&amp;gt;|JSON via API Key| C
E[&amp;#34;API de SwitchBot (Temp. de Habitación / CO2)&amp;#34;] --&amp;gt;|JSON via API Key| C
C --&amp;gt;|Extract &amp;amp; Transform| D[&amp;#34;DataFrame de Pandas (Memoria)&amp;#34;]
D --&amp;gt;|Load| F[&amp;#34;TimescaleDB / PostgreSQL&amp;#34;]
F --&amp;gt; G[&amp;#34;Jupyter Notebook (Análisis Ad-hoc)&amp;#34;]
F --&amp;gt; H[&amp;#34;Aplicación Web de Streamlit (Monitoreo Diario)&amp;#34;]
&lt;/pre>
&lt;p>Con esta arquitectura, podrás monitorizar automáticamente cada día la correlación entre tu estado de salud (entrada) y el rendimiento de codificación (salida).&lt;/p>
&lt;p>Además, veamos detalladamente la secuencia entre los sistemas.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant U as &amp;#34;Usuario (Ingeniero)&amp;#34;
participant W as &amp;#34;Plugin de WakaTime (VS Code)&amp;#34;
participant O as &amp;#34;Oura Ring y API&amp;#34;
participant S as &amp;#34;Lote ETL de Python&amp;#34;
participant DB as &amp;#34;TimescaleDB&amp;#34;
U-&amp;gt;&amp;gt;W: &amp;#34;Escribir código (Tecleo en el teclado)&amp;#34;
W--&amp;gt;&amp;gt;W: &amp;#34;Registrar latido preciso de codificación&amp;#34;
U-&amp;gt;&amp;gt;O: &amp;#34;Dormir (Usar anillo)&amp;#34;
O--&amp;gt;&amp;gt;O: &amp;#34;Registrar VFC, FCR, Temp. y Etapas del Sueño&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;Limpiar y Fusionar Datos (Pandas)&amp;#34;
S-&amp;gt;&amp;gt;DB: &amp;#34;INSERT INTO daily_metrics&amp;#34;
Note over S,DB: &amp;#34;Programado a través de Cron / Airflow&amp;#34;
&lt;/pre>
&lt;h2 id="7-ingestión-de-datos-con-python-y-pandas">7. Ingestión de datos con Python y Pandas
&lt;/h2>&lt;p>Veamos cómo obtener los datos de las API de Oura Ring y WakaTime usando un script de Python real, y combinarlos en un DataFrame de Pandas. Construiremos un código robusto adecuado para un uso práctico.&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"># Variables de entorno&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;Obtener resumen de sueño diario de la API v2 de Oura Ring.&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"># Generar excepción por errores 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"># Extraer valores profundamente anidados o seleccionar columnas esenciales&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"># Convertir fechas a objetos datetime y establecer como índice&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;Obtener resúmenes de duración de codificación de la API de WakaTime.&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"># Extraer total de segundos de codificación&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"># Obtener datos de los últimos 60 días&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"># Fusionar conjuntos de datos en el índice &amp;#39;day&amp;#39; usando 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"># Guardar datos sin procesar en 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;Ingeridos &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"> días de datos.&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-preprocesamiento-de-datos-e-ingeniería-de-características">8. Preprocesamiento de datos e ingeniería de características
&lt;/h2>&lt;p>Es peligroso introducir datos sin procesar directamente en el análisis. Es necesario procesar los valores faltantes (Missing Values) debido a descuidos al cargar dispositivos, o generar nuevos indicadores significativos (Ingeniería de Características: 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;Aplicar ingeniería de características y limpieza al dataframe fusionado.&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. Manejar valores faltantes (ej. 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. Calcular Eficiencia del Sueño&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Fórmula: (Tiempo Total de Sueño / Tiempo en la Cama) * 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. Calcular Proporciones de Etapas del Sueño&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. Calcular Promedios Móviles de 7 días para suavizar el ruido diario&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. Calcular desviación diaria de la línea base&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. Normalizar objetivos para Machine Learning (Opcional)&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"># Eliminar filas con NaN generadas por la ventana móvil&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-análisis-de-correlación-la-intersección-entre-la-productividad-y-las-métricas-de-salud">9. Análisis de correlación: La intersección entre la productividad y las métricas de salud
&lt;/h2>&lt;p>A partir de los datos preprocesados, analizamos la relación entre los indicadores de salud y la productividad en la codificación. Como hipótesis, se puede pensar que &amp;ldquo;los días con una VFC más alta (el sistema nervioso autónomo está en orden y recuperado), se mantiene la concentración y el tiempo de codificación es mayor, o se pueden realizar tareas más complejas&amp;rdquo;.&lt;/p>
&lt;pre class="mermaid">
xychart-beta
title VFC vs Horas Diarias de Codificación (Normalizado)
x-axis [&amp;#34;Lun&amp;#34;, &amp;#34;Mar&amp;#34;, &amp;#34;Mié&amp;#34;, &amp;#34;Jue&amp;#34;, &amp;#34;Vie&amp;#34;, &amp;#34;Sáb&amp;#34;, &amp;#34;Dom&amp;#34;]
y-axis &amp;#34;VFC y Rendimiento de Codificación&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>(Nota: El gráfico de líneas muestra la desviación de la VFC desde su línea base normalizada, y el gráfico de barras muestra el tiempo de codificación en WakaTime. Se puede observar una correlación donde el rendimiento de codificación se maximiza desde el miércoles hasta el viernes, una vez que se ha obtenido suficiente recuperación)&lt;/em>&lt;/p>
&lt;p>Realizamos el cálculo del coeficiente de correlación (coeficiente de correlación producto-momento de Pearson $r$) en Pandas, y una prueba de significación estadística (valor p) utilizando 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"># Seleccionar columnas numéricas para la matriz de correlación&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;Correlación con Horas de Codificación:&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"># Calcular coeficiente de correlación de Pearson y valor p para Sueño REM y Horas de Codificación&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;Sueño REM vs Horas de Codificación: 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">, valor p = &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>En muchos casos, se observa una correlación positiva significativa ($p &lt; 0.05$) entre &lt;code>average_hrv&lt;/code> o &lt;code>rem_sleep_duration&lt;/code> y &lt;code>coding_hours&lt;/code>. En particular, se ha informado ampliamente en la comunidad de autoseguimiento (Quantified Self) de ingenieros que la duración del sueño REM de la noche anterior influye fuertemente en el &amp;ldquo;tiempo que se tarda en resolver errores (depuración)&amp;rdquo; y la &amp;ldquo;productividad&amp;rdquo; del día.&lt;/p>
&lt;h2 id="10-modelo-matemático-del-ritmo-circadiano-y-optimización-del-pico-cognitivo">10. Modelo matemático del ritmo circadiano y optimización del pico cognitivo
&lt;/h2>&lt;p>Los humanos poseemos un reloj biológico con un ciclo de aproximadamente 24 horas, llamado ritmo circadiano (Circadian Rhythm). Este ritmo provoca fluctuaciones en la temperatura corporal, la secreción de hormonas (pico matutino de cortisol y secreción nocturna de melatonina), y la &amp;ldquo;capacidad cognitiva&amp;rdquo;.&lt;/p>
&lt;p>Las fluctuaciones del ritmo circadiano a menudo se aproximan y representan mediante un modelo matemático que utiliza curvas cosenoidales (modelo Cosinor), y los cambios en los indicadores biométricos pueden formularse de la siguiente manera:&lt;/p>
$$ y(t) = M + A \cos\left(\frac{2\pi}{24}(t - \phi)\right) + e(t) $$&lt;ul>
&lt;li>$y(t)$: Indicador biométrico (ej. temperatura corporal central o nivel de alerta) en el tiempo $t$&lt;/li>
&lt;li>$M$: MESOR (Estadística de Estimación de la Línea Media del Ritmo) - Valor central del ritmo (nivel medio)&lt;/li>
&lt;li>$A$: Amplitud (Amplitude) - Magnitud de la fluctuación&lt;/li>
&lt;li>$\phi$: Acrofase (Acrophase) - Fase (hora) en la que se alcanza el pico&lt;/li>
&lt;li>$e(t)$: Término de error debido a factores ambientales, etc.&lt;/li>
&lt;/ul>
&lt;p>Lo que significa esta ecuación en la ingeniería es que &amp;ldquo;la franja horaria ($\phi$) en la que el rendimiento (estado de alerta) alcanza su pico en un día está determinada biológicamente, y las tareas con la mayor carga cognitiva (corrección de errores complejos, diseño de nueva arquitectura) deben asignarse en ese periodo de tiempo&amp;rdquo;.&lt;/p>
&lt;p>En el caso del cronotipo matutino general (Morning Lark), el primer pico cognitivo se alcanza entre 2 y 4 horas después de despertarse (por ejemplo, entre las 9 y las 11 de la mañana). Posteriormente, un valle del ritmo circadiano (depresión post-almuerzo / Post-lunch dip) ocurre alrededor de las 2 de la tarde, y otro pequeño pico llega por la tarde-noche. El mejor hackeo de salud es identificar tu tiempo pico ($\phi$) a partir del volumen de actividad de los datos portátiles y tu nivel de concentración subjetiva, y protegerlo usando &amp;ldquo;bloqueo de tiempo&amp;rdquo; (Time Blocking) en herramientas como Google Calendar. Programar reuniones sin sentido durante tu pico de tiempo es como asignar el núcleo de la CPU de mayor rendimiento a un proceso inactivo.&lt;/p>
&lt;h2 id="11-farmacocinética-de-la-cafeína-y-el-momento-óptimo-de-ingesta">11. Farmacocinética de la cafeína y el momento óptimo de ingesta
&lt;/h2>&lt;p>Los ingenieros y el café tienen una relación inseparable, pero el consumo excesivo de cafeína o su ingesta a horas tardías bloquea los receptores de adenosina en el cerebro y destruye el &amp;ldquo;sueño profundo (Deep Sleep)&amp;rdquo; nocturno. Aunque subjetivamente sientas que has dormido, al observar los datos del Oura Ring, puedes confirmar que la frecuencia cardíaca no disminuyó y el porcentaje de sueño profundo cayó drásticamente.&lt;/p>
&lt;p>La eliminación de la cafeína del cuerpo sigue una cinética de primer orden (First-order kinetics). Es decir, la concentración en sangre disminuye exponencialmente.&lt;/p>
$$ C(t) = C_0 e^{-k t} $$&lt;p>Donde,&lt;/p>
&lt;ul>
&lt;li>$C(t)$: Concentración de cafeína en la sangre tras transcurrir un tiempo $t$&lt;/li>
&lt;li>$C_0$: Concentración inicial (concentración máxima inmediatamente después de la ingesta)&lt;/li>
&lt;li>$k$: Constante de tasa de eliminación&lt;/li>
&lt;li>$t$: Tiempo transcurrido desde la ingesta (horas)&lt;/li>
&lt;/ul>
&lt;p>La constante de tasa de eliminación $k$ se puede expresar utilizando la vida media de la cafeína ($t_{1/2}$) de la siguiente manera:&lt;/p>
$$ k = \frac{\ln(2)}{t_{1/2}} $$&lt;p>Para un adulto sano, aunque depende de los genes individuales (gen CYP1A2), se considera que la vida media de la cafeína $t_{1/2}$ es de aproximadamente &lt;strong>5 a 6 horas&lt;/strong>.
Por ejemplo, si se bebe una taza de café de filtro (unos 150 mg de cafeína) a las 3 de la tarde ($C_0 = 150$). Asumiendo una vida media de 5.5 horas, $k \approx 0.126$.
Al calcular la concentración de cafeína restante en el cuerpo a la hora de acostarse a las 11 de la noche (8 horas después):&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>En otras palabras, a la hora de dormir, aún quedan 54 mg de cafeína (algo más de un trago de espresso) en el cuerpo, lo que afecta directamente y negativamente a la arquitectura del sueño.
La conclusión basada en datos derivada de este modelo farmacocinético es que, &lt;strong>&amp;ldquo;para asegurar un sueño de alta calidad, la ingesta de cafeína debe comenzar a partir de los 90 minutos después de despertarse (una vez que el pico de cortisol se haya calmado), y debe suspenderse por completo a las 2 p.m. a más tardar (de 9 a 10 horas antes de acostarse)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h2 id="12-hackeo-de-variables-de-entorno-lux-temperatura-co2">12. Hackeo de variables de entorno (Lux, Temperatura, CO2)
&lt;/h2>&lt;p>Es importante no solo optimizar el sistema interno que es tu propio cuerpo, sino también las variables de entorno externas (Environment Variables).&lt;/p>
&lt;h3 id="121-programación-del-entorno-luminoso-lux">12.1 Programación del entorno luminoso (Lux)
&lt;/h3>&lt;p>El &amp;ldquo;Zeitgeber (Pista para señalar la hora)&amp;rdquo; más poderoso que resetea el ritmo circadiano es la luz. Por la mañana, al entrar aproximadamente 100,000 Lux de luz solar a las células fotorreceptoras (ipRGC) de la retina, se detiene la secreción de melatonina y el temporizador se reinicia. A la inversa, por la noche es esencial bloquear la luz azul para no inhibir la secreción de melatonina. Es efectivo no solo bajar la temperatura de color de la pantalla con software como f.lux, sino también crear un script que controle la iluminación inteligente (como Philips Hue) mediante una API para reducir automáticamente la iluminancia y la temperatura de color de la habitación con la puesta de sol.&lt;/p>
&lt;h3 id="122-control-de-temperatura-del-dormitorio-y-latencia-de-inicio-del-sueño-sleep-latency">12.2 Control de temperatura del dormitorio y latencia de inicio del sueño (Sleep Latency)
&lt;/h3>&lt;p>Los seres humanos entran en el estado de sueño a medida que su temperatura corporal central (Core Body Temperature) disminuye. Manteniendo la temperatura del dormitorio fresca entre 18 y 19 grados, y dirigiéndote a la cama exactamente cuando la temperatura corporal central, elevada temporalmente por un baño caliente 90 minutos antes de acostarte, comienza a caer drásticamente, puedes acortar drásticamente la latencia del sueño (Sleep Latency: tiempo que tardas en conciliar el sueño desde que te metes en la cama) y maximizar el sueño profundo.&lt;/p>
&lt;h3 id="123-concentración-de-co2-y-disminución-de-la-función-cognitiva">12.3 Concentración de CO2 y disminución de la función cognitiva
&lt;/h3>&lt;p>Si añades los datos de las API del SwitchBot Hub o de la estación meteorológica Netatmo a tu pipeline de datos, podrás observar una clara correlación negativa entre la concentración de dióxido de carbono (CO2) en la habitación y la productividad.
Como han demostrado investigaciones como las de la Universidad de Harvard, cuando la concentración de CO2 supera los 1000 ppm, la función cognitiva (especialmente la capacidad de tomar decisiones estratégicas) comienza a disminuir significativamente, y superando los 2000 ppm causa una grave caída del rendimiento. Trabajar a distancia en una habitación cerrada durante el invierno reduce el rendimiento sin que te des cuenta.&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-código para ventilación inteligente de habitaciones usando Home Assistant / API de SwitchBot&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"># Obtener el nivel actual de CO2 desde la API de Netatmo/SwitchBot&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;Advertencia: Nivel alto de 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). Riesgo de deterioro cognitivo.&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"># Activar enchufe inteligente para encender el ventilador de ventilación&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"># Enviar notificación a 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;He activado el ventilador de ventilación. El nivel de CO2 es alto.&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>Al ejecutar periódicamente un script de este tipo mediante Cron, se completa un sistema de control de entorno autónomo que mantiene siempre la concentración de oxígeno óptima.&lt;/p>
&lt;h2 id="13-conclusión-cicd-del-sistema-que-es-el-cuerpo-humano">13. Conclusión: CI/CD del sistema que es el cuerpo humano
&lt;/h2>&lt;p>Intenta considerar tu propio cuerpo como un único sistema distribuido complejo. El dispositivo portátil (Oura Ring) es el exportador de métricas (Prometheus) para la monitorización, el script de Python/Pandas es el pipeline de análisis de registros (Logstash/Fluentd), y los cambios diarios en la condición física y el rendimiento son la salud del sistema mostrada en el panel de control (Grafana/Streamlit).&lt;/p>
&lt;p>&amp;ldquo;Reducir las horas de sueño para trabajar&amp;rdquo; equivale a forzar la adición de nuevas funcionalidades ignorando la deuda técnica (Technical Debt). A corto plazo, puedes llegar a tiempo para el lanzamiento, pero a largo plazo definitivamente provocará una caída del sistema (Burnout o síndrome de agotamiento, daños graves a la salud o depresión).&lt;/p>
&lt;p>Monitorea la VFC, revisa las tendencias de la FCR, y optimiza la arquitectura de tu sueño. Luego, mientras observas la correlación con los datos de productividad en WakaTime, ajusta finamente los &amp;ldquo;hiperparámetros&amp;rdquo; diarios de dieta, ejercicio, sueño y entorno. Esto no es otra cosa que un proceso de &lt;strong>CI/CD (Integración Continua / Entrega Continua)&lt;/strong> para el cuerpo humano.&lt;/p>
&lt;p>Aprovechando la ciencia de datos y las API, diseñemos las condiciones de salud óptimas para lograr el máximo rendimiento. Porque la calidad del código que escribes está directamente ligada a la salud de tu propio sistema biológico.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Aviso legal: Este artículo resume los experimentos personales y el enfoque de ciencia de datos del autor, y no tiene como objetivo proporcionar asesoramiento médico. Si experimenta problemas de salud persistentes o trastornos del sueño, consulte a una institución médica especializada.&lt;/em>&lt;/p></description></item></channel></rss>