<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>BIT</title>
<link>https://biitt.com/es/blog/analisis-de-datos/</link>
<atom:link href="https://biitt.com/es/blog/analisis-de-datos/index.xml" rel="self" type="application/rss+xml"/>
<description>BIT — Business Innovation Technology. Estadística, Machine Learning, Deep Learning, Big Data, MLOps e IoT: notebooks y artículos técnicos de Wilder Ramírez Delgado.</description>
<generator>quarto-1.8.27</generator>
<lastBuildDate>Fri, 02 Oct 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>Análisis Avanzado de Datos — 13. Métodos de reducción de dimensionalidad: más allá de PCA</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/avanzado/14-reduccion-dimensionalidad/</link>
  <description><![CDATA[ 




<section id="análisis-avanzado-de-datos-13.-métodos-de-reducción-de-dimensionalidad-más-allá-de-pca" class="level1">
<h1>Análisis Avanzado de Datos — 13. Métodos de reducción de dimensionalidad: más allá de PCA</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado convierte datos en decisiones. Científico de Datos, Arquitecto de IA y asesor tecnológico con más de 20 años de experiencia en analítica avanzada, machine learning, Big Data e IoT. Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), asesora a entidades gubernamentales y empresas privadas en Colombia y es referente en analítica y normatividad para los sectores postal y logístico del país. Una serie pensada para ir de la teoría a la práctica, con ejemplos concretos en cada paso.</p>
<p>📌 <em>Parte de la serie <strong>Análisis Avanzado de Datos</strong>.</em></p>
</section>
<section id="de-varianza-e-independencia-a-vecindad-y-estructura" class="level2">
<h2 class="anchored" data-anchor-id="de-varianza-e-independencia-a-vecindad-y-estructura">De varianza e independencia a vecindad y estructura</h2>
<p>En el artículo anterior viste ICA: una alternativa a PCA que busca componentes <strong>estadísticamente independientes</strong> en vez de solo no correlacionados. PCA e ICA comparten algo importante: las dos son transformaciones <strong>lineales</strong> — el nuevo sistema de coordenadas es una combinación lineal (una rotación o un cizallamiento) de las variables originales.</p>
<p>Ese supuesto de linealidad es también su límite. Cuando la estructura real de los datos vive sobre una superficie curva — una <em>variedad</em> (<em>manifold</em>) de menor dimensión, enredada dentro del espacio original —, ninguna rotación lineal la desenreda bien. Este artículo cierra la serie de reducción de dimensionalidad mirando qué pasa cuando se abandona la linealidad, y qué se gana y qué se pierde al hacerlo.</p>
</section>
<section id="objetivos-de-aprendizaje" class="level2">
<h2 class="anchored" data-anchor-id="objetivos-de-aprendizaje">Objetivos de aprendizaje</h2>
<p>Al terminar este artículo vas a ser capaz de:</p>
<ul>
<li>explicar qué es la maldición de la dimensionalidad y por qué distorsiona las distancias;</li>
<li>distinguir selección de variables de proyección de variables;</li>
<li>describir la intuición de MDS, t-SNE y UMAP, y qué tipo de estructura preserva cada uno;</li>
<li>elegir entre reducir para visualizar y reducir para predecir;</li>
<li>reconocer los riesgos de sobre-interpretar una proyección no lineal.</li>
</ul>
</section>
<section id="preparación-del-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparación-del-entorno">Preparación del entorno</h2>
<div id="dcb8e348" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:49:21.118997Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:49:21.118559Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:49:58.337312Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:49:58.335026Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.datasets <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> load_wine</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.decomposition <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PCA</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.manifold <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> MDS, TSNE</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> StandardScaler</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> umap</span>
<span id="cb1-9"></span>
<span id="cb1-10">SEMILLA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2026</span></span>
<span id="cb1-11">COLORES <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#2A6F97'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#D97706'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#2D6A4F'</span>]</span>
<span id="cb1-12">plt.rcParams.update({</span>
<span id="cb1-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'figure.figsize'</span>: (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb1-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.top'</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb1-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.right'</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb1-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.titleweight'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'bold'</span>,</span>
<span id="cb1-17">})</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>C:\Users\wilde\.conda\envs\ANALITICA\Lib\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm</code></pre>
</div>
</div>
</section>
<section id="la-maldición-de-la-dimensionalidad" class="level2">
<h2 class="anchored" data-anchor-id="la-maldición-de-la-dimensionalidad">La maldición de la dimensionalidad</h2>
<p>A medida que agregamos variables, el espacio donde viven los datos crece mucho más rápido de lo que crecen los datos mismos. Dos consecuencias prácticas de esto:</p>
<ul>
<li><strong>Los datos se vuelven ralos.</strong> Para cubrir un espacio de <img src="https://latex.codecogs.com/png.latex?p"> dimensiones con la misma densidad que lográs en 2 dimensiones, necesitás un número de observaciones que crece exponencialmente con <img src="https://latex.codecogs.com/png.latex?p">.</li>
<li><strong>Las distancias dejan de discriminar.</strong> En dimensión alta, la distancia entre el punto más cercano y el más lejano a un punto de referencia tiende a volverse casi igual — todos los puntos terminan “igual de lejos”. Esto es un problema serio para cualquier método (como <img src="https://latex.codecogs.com/png.latex?k"> vecinos más cercanos, o el propio t-SNE que vas a ver más abajo) que depende de distinguir “cerca” de “lejos”.</li>
</ul>
<div id="ea9c5593" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:49:58.343149Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:49:58.342315Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:49:58.404579Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:49:58.402458Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb3-2">dimensiones <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>]</span>
<span id="cb3-3">n_puntos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span></span>
<span id="cb3-4"></span>
<span id="cb3-5">contraste <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb3-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> d <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> dimensiones:</span>
<span id="cb3-7">    puntos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(n_puntos, d))</span>
<span id="cb3-8">    referencia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> puntos[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb3-9">    distancias <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.norm(puntos[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> referencia, axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb3-10">    contraste.append({</span>
<span id="cb3-11">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dimension'</span>: d,</span>
<span id="cb3-12">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_min'</span>: distancias.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(),</span>
<span id="cb3-13">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_max'</span>: distancias.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(),</span>
<span id="cb3-14">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'contraste_relativo'</span>: (distancias.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> distancias.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> distancias.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(),</span>
<span id="cb3-15">    })</span>
<span id="cb3-16"></span>
<span id="cb3-17">tabla_contraste <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(contraste)</span>
<span id="cb3-18">display(tabla_contraste.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">dimension</th>
<th data-quarto-table-cell-role="th">distancia_min</th>
<th data-quarto-table-cell-role="th">distancia_max</th>
<th data-quarto-table-cell-role="th">contraste_relativo</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>2</td>
<td>0.0271</td>
<td>1.0183</td>
<td>36.5213</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>5</td>
<td>0.1792</td>
<td>1.4237</td>
<td>6.9467</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>10</td>
<td>0.5600</td>
<td>2.0303</td>
<td>2.6257</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>20</td>
<td>1.1202</td>
<td>2.5830</td>
<td>1.3057</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>50</td>
<td>2.1826</td>
<td>3.5546</td>
<td>0.6286</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">5</th>
<td>100</td>
<td>3.5330</td>
<td>4.9877</td>
<td>0.4117</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">6</th>
<td>300</td>
<td>6.3599</td>
<td>7.8809</td>
<td>0.2392</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-este-resultado" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado">Cómo leer este resultado</h3>
<p>La columna <code>contraste_relativo</code> es <img src="https://latex.codecogs.com/png.latex?(d_%7B%5Cmax%7D%20-%20d_%7B%5Cmin%7D)%20/%20d_%7B%5Cmin%7D">: qué tanto más lejos está el punto más distante que el más cercano, en proporción. En dimensión 2 ese contraste es grande (<strong>36.5213</strong>): hay puntos claramente cerca y otros claramente lejos. A medida que <img src="https://latex.codecogs.com/png.latex?d"> crece hasta 300, el contraste cae hacia <strong>0.2392</strong> — cerca y lejos se vuelven casi lo mismo. Ningún método de reducción puede devolver información que esta pérdida de contraste ya borró; lo que sí puede hacer es encontrar la combinación de variables donde el contraste real (la estructura que importa) sigue siendo detectable.</p>
</section>
</section>
<section id="los-datos-los-mismos-trece-vinos-del-capítulo-anterior" class="level2">
<h2 class="anchored" data-anchor-id="los-datos-los-mismos-trece-vinos-del-capítulo-anterior">Los datos: los mismos trece vinos del capítulo anterior</h2>
<p>Para que las comparaciones de este artículo sean justas, usamos el mismo conjunto de datos que en PCA e ICA: 178 vinos italianos de tres cultivos distintos, descritos por 13 mediciones químicas. Volvemos a cargarlo y a estandarizarlo exactamente igual que antes.</p>
<div id="6fcbdaad" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:49:58.412115Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:49:58.411443Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:49:58.581172Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:49:58.578711Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">wine <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> load_wine(as_frame<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb4-2">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> wine.data.copy()</span>
<span id="cb4-3">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> wine.target.copy()</span>
<span id="cb4-4">nombres_clase <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> wine.target_names</span>
<span id="cb4-5"></span>
<span id="cb4-6">escalador <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler()</span>
<span id="cb4-7">X_std <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> escalador.fit_transform(X)</span>
<span id="cb4-8"></span>
<span id="cb4-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Observaciones: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb4-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Variables numéricas: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb4-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Observaciones por clase:'</span>, y.value_counts().sort_index().to_dict())</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Observaciones: 178
Variables numéricas: 13
Observaciones por clase: {0: 59, 1: 71, 2: 48}</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-1">Cómo leer este resultado</h3>
<p>Mismo dataset que en PCA: <strong>178</strong> observaciones, <strong>13</strong> variables numéricas, tres clases de vino. <code>X_std</code> queda estandarizado (media 0, desviación 1 por columna) porque todos los métodos de este artículo, igual que PCA, son sensibles a la escala: una variable medida en una unidad con rango más amplio dominaría la distancia entre observaciones si no se corrige.</p>
</section>
</section>
<section id="punto-de-partida-la-proyección-lineal-que-ya-conocés" class="level2">
<h2 class="anchored" data-anchor-id="punto-de-partida-la-proyección-lineal-que-ya-conocés">Punto de partida: la proyección lineal que ya conocés</h2>
<p>Antes de ver métodos no lineales, proyectamos los mismos datos con PCA a 2 dimensiones, igual que en el capítulo anterior. Esta proyección queda como referencia para comparar visualmente contra MDS, t-SNE y UMAP más abajo — no es una repetición del análisis completo de PCA, que ya hiciste a fondo.</p>
<div id="104227ac" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:49:58.586286Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:49:58.585740Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:49:59.153990Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:49:59.151838Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">pca_2d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA)</span>
<span id="cb6-2">proy_pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_2d.fit_transform(X_std)</span>
<span id="cb6-3">varianza_2d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_2d.explained_variance_ratio_.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()</span>
<span id="cb6-4"></span>
<span id="cb6-5">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb6-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> clase, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), COLORES):</span>
<span id="cb6-7">    mascara <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> clase</span>
<span id="cb6-8">    ax.scatter(proy_pca[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], proy_pca[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres_clase[clase], alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb6-9">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC1'</span>)</span>
<span id="cb6-10">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>)</span>
<span id="cb6-11">ax.set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PCA (2 componentes, </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>varianza_2d<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> de varianza explicada)'</span>)</span>
<span id="cb6-12">ax.legend()</span>
<span id="cb6-13">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/14-reduccion-dimensionalidad/index_files/figure-html/cell-5-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-esta-proyeccióncon-2-componentes-pca-conserva-el-55.4-de-la-varianza-total-frente-al-73.60-que-alcanzaba-con-4-componentes-en-el-capítulo-anterior.-dos-componentes-alcanzan-para-separar-visualmente-las-clases-pero-es-una-compresión-más-agresiva-que-la-que-usamos-antes-para-el-modelo-predictivo.-las-tres-clases-de-vino-ya-se-separan-razonablemente-bien-con-una-transformación-puramente-lineal-guardá-esta-imagen-en-la-cabeza-como-referencia-para-las-que-siguen." class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-proyeccióncon-2-componentes-pca-conserva-el-55.4-de-la-varianza-total-frente-al-73.60-que-alcanzaba-con-4-componentes-en-el-capítulo-anterior.-dos-componentes-alcanzan-para-separar-visualmente-las-clases-pero-es-una-compresión-más-agresiva-que-la-que-usamos-antes-para-el-modelo-predictivo.-las-tres-clases-de-vino-ya-se-separan-razonablemente-bien-con-una-transformación-puramente-lineal-guardá-esta-imagen-en-la-cabeza-como-referencia-para-las-que-siguen.">Cómo leer esta proyecciónCon 2 componentes, PCA conserva el <strong>55.4%</strong> de la varianza total — frente al <strong>73.60%</strong> que alcanzaba con 4 componentes en el capítulo anterior. Dos componentes alcanzan para separar visualmente las clases, pero es una compresión más agresiva que la que usamos antes para el modelo predictivo. Las tres clases de vino ya se separan razonablemente bien con una transformación puramente lineal; guardá esta imagen en la cabeza como referencia para las que siguen.</h3>
</section>
</section>
<section id="selección-de-variables-frente-a-proyección-de-variables" class="level2">
<h2 class="anchored" data-anchor-id="selección-de-variables-frente-a-proyección-de-variables">Selección de variables frente a proyección de variables</h2>
<p>Reducir dimensiones no siempre significa proyectar. Hay dos familias de estrategias y conviene no confundirlas:</p>
<ul>
<li><strong>Selección de variables</strong>: te quedás con un subconjunto de las columnas originales (por ejemplo, las 4 más correlacionadas con la variable objetivo) y descartás el resto. El resultado sigue siendo interpretable en las unidades originales — “alcohol” sigue siendo “alcohol” — pero podés perder información que solo aparecía combinada entre variables descartadas.</li>
<li><strong>Proyección de variables</strong>: construís nuevas variables como función de todas las originales (PCA, ICA, MDS, t-SNE, UMAP entran acá). Usás toda la información disponible, pero el resultado — “componente 1”, “dimensión UMAP 2” — ya no tiene una unidad ni un significado directo.</li>
</ul>
<p>Este artículo trata exclusivamente de proyección. Si tu objetivo es mantener variables interpretables para alguien que va a actuar sobre ellas (un médico, un auditor, un regulador), selección de variables puede ser preferible aunque “explique menos varianza” en el papel.</p>
</section>
<section id="métodos-no-lineales-la-idea-general" class="level2">
<h2 class="anchored" data-anchor-id="métodos-no-lineales-la-idea-general">Métodos no lineales: la idea general</h2>
<p>PCA busca una rotación que maximice varianza global. Los métodos de esta sección, en cambio, parten de las distancias o las vecindades entre observaciones y buscan una representación en pocas dimensiones que las reproduzca lo mejor posible — sin exigir que la transformación sea una combinación lineal de las variables originales. Eso les da más flexibilidad para seguir curvas y superficies, pero a cambio pierden varias propiedades cómodas de PCA: no hay una fórmula cerrada única, el resultado depende de un proceso de optimización (y por lo tanto de la semilla), y — salvo UMAP, como vas a ver — no siempre hay una forma clara de aplicar la misma transformación a una observación nueva.</p>
</section>
<section id="mds-preservar-distancias-globales" class="level2">
<h2 class="anchored" data-anchor-id="mds-preservar-distancias-globales">MDS: preservar distancias globales</h2>
<p>El escalamiento multidimensional (<em>multidimensional scaling</em>, MDS) parte de todas las distancias por pares entre observaciones en el espacio original y busca coordenadas en 2 dimensiones que reproduzcan esas distancias lo más fielmente posible. Formalmente, minimiza una función de “estrés”:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7Bestr%C3%A9s%7D%20=%20%5Csum_%7Bi%20%3C%20j%7D%20%5Cleft(%20d_%7Bij%7D%20-%20%5Chat%7Bd%7D_%7Bij%7D%20%5Cright)%5E2%0A"></p>
<p>donde <img src="https://latex.codecogs.com/png.latex?d_%7Bij%7D"> es la distancia original entre las observaciones <img src="https://latex.codecogs.com/png.latex?i"> y <img src="https://latex.codecogs.com/png.latex?j">, y <img src="https://latex.codecogs.com/png.latex?%5Chat%7Bd%7D_%7Bij%7D"> es la distancia entre sus proyecciones en 2D. A diferencia de PCA, MDS no pasa por una matriz de covarianza ni por componentes ortogonales: trabaja directamente sobre la matriz de distancias, lo que le permite —en principio— capturar relaciones no lineales si se usa una noción de distancia no euclidiana. En su versión más simple (la que usamos acá), con distancia euclidiana, MDS clásico da un resultado muy cercano a PCA; su verdadero valor aparece con otras métricas de distancia o con datos ya dados como una matriz de disimilitud.</p>
<div id="79bea03e" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:49:59.159437Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:49:59.158945Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:50:00.274507Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:50:00.272656Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">mds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MDS(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA, normalized_stress<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'auto'</span>, n_init<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb7-2">proy_mds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mds.fit_transform(X_std)</span>
<span id="cb7-3"></span>
<span id="cb7-4">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb7-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> clase, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), COLORES):</span>
<span id="cb7-6">    mascara <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> clase</span>
<span id="cb7-7">    ax.scatter(proy_mds[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], proy_mds[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres_clase[clase], alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb7-8">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Dimensión 1'</span>)</span>
<span id="cb7-9">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Dimensión 2'</span>)</span>
<span id="cb7-10">ax.set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'MDS (estrés final: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>stress_<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb7-11">ax.legend()</span>
<span id="cb7-12">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>C:\Users\wilde\.conda\envs\ANALITICA\Lib\site-packages\sklearn\manifold\_mds.py:735: FutureWarning: The default value of `init` will change from 'random' to 'classical_mds' in 1.10. To suppress this warning, provide some value of `init`.
  warnings.warn(</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/14-reduccion-dimensionalidad/index_files/figure-html/cell-6-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-esta-proyecciónel-estrés-final-21675.5-es-la-versión-sin-normalizar-resuelve-a-estrés-crudo-cuando-como-acá-se-usa-mds-métrico-no-es-una-fracción-entre-0-y-1-crece-con-el-número-de-observaciones-y-con-la-magnitud-de-las-distancias-así-que-la-cifra-por-sí-sola-no-dice-bueno-o-malo-solo-sirve-para-comparar-entre-corridas-o-entre-números-de-dimensiones-sobre-el-mismo-conjunto-de-datos.-con-datos-euclidianos-como-estos-esperá-una-forma-parecida-a-la-de-pca-es-el-mismo-tipo-de-objetivo-preservar-distanciasvarianza-global-resuelto-con-un-algoritmo-distinto." class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-proyecciónel-estrés-final-21675.5-es-la-versión-sin-normalizar-resuelve-a-estrés-crudo-cuando-como-acá-se-usa-mds-métrico-no-es-una-fracción-entre-0-y-1-crece-con-el-número-de-observaciones-y-con-la-magnitud-de-las-distancias-así-que-la-cifra-por-sí-sola-no-dice-bueno-o-malo-solo-sirve-para-comparar-entre-corridas-o-entre-números-de-dimensiones-sobre-el-mismo-conjunto-de-datos.-con-datos-euclidianos-como-estos-esperá-una-forma-parecida-a-la-de-pca-es-el-mismo-tipo-de-objetivo-preservar-distanciasvarianza-global-resuelto-con-un-algoritmo-distinto.">Cómo leer esta proyecciónEl estrés final (<strong>21675.5</strong>) es la versión <strong>sin normalizar</strong> ( resuelve a estrés crudo cuando, como acá, se usa MDS métrico): no es una fracción entre 0 y 1, crece con el número de observaciones y con la magnitud de las distancias, así que la cifra por sí sola no dice “bueno” o “malo” — solo sirve para comparar entre corridas o entre números de dimensiones sobre el mismo conjunto de datos. Con datos euclidianos como estos, esperá una forma parecida a la de PCA: es el mismo tipo de objetivo (preservar distancias/varianza global), resuelto con un algoritmo distinto.</h3>
</section>
</section>
<section id="t-sne-preservar-vecindades-locales" class="level2">
<h2 class="anchored" data-anchor-id="t-sne-preservar-vecindades-locales">t-SNE: preservar vecindades locales</h2>
<p>t-SNE (<em>t-distributed Stochastic Neighbor Embedding</em>) cambia el objetivo: en vez de intentar reproducir todas las distancias por igual, se concentra en preservar <strong>quién es vecino de quién</strong>. Para cada observación, construye una distribución de probabilidad sobre “cuáles son sus vecinos cercanos” en el espacio original, y busca una configuración en 2D donde esa misma distribución de vecindad se mantenga lo más parecida posible.</p>
<p>El hiperparámetro central es la <strong>perplejidad</strong>, que fija de manera aproximada cuántos vecinos efectivos considera cada punto — perplejidades bajas priorizan estructura muy local (grupos pequeños), perplejidades altas priorizan estructura más amplia. t-SNE no tiene una solución única: el proceso de optimización es no convexo, así que el resultado cambia con la semilla y con la perplejidad, y <strong>no existe una forma de aplicar la misma transformación a una observación nueva</strong> — solo sabe proyectar el conjunto completo con el que fue ajustado. Esto importa más adelante, en el notebook aplicado, cuando comparemos qué tan útil es cada método para un modelo de producción.</p>
<div id="fa9b289c" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:50:00.278208Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:50:00.277774Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:50:07.225232Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:50:07.221330Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1">tsne <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> TSNE(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, perplexity<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA, init<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pca'</span>, learning_rate<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'auto'</span>)</span>
<span id="cb9-2">proy_tsne <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tsne.fit_transform(X_std)</span>
<span id="cb9-3"></span>
<span id="cb9-4">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb9-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> clase, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), COLORES):</span>
<span id="cb9-6">    mascara <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> clase</span>
<span id="cb9-7">    ax.scatter(proy_tsne[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], proy_tsne[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres_clase[clase], alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb9-8">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Dimensión 1 (t-SNE)'</span>)</span>
<span id="cb9-9">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Dimensión 2 (t-SNE)'</span>)</span>
<span id="cb9-10">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'t-SNE (perplejidad = 30)'</span>)</span>
<span id="cb9-11">ax.legend()</span>
<span id="cb9-12">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/14-reduccion-dimensionalidad/index_files/figure-html/cell-7-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-esta-proyección" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-proyección">Cómo leer esta proyección</h3>
<p><strong>Advertencia importante, y no una curiosidad menor</strong>: en un gráfico de t-SNE, ni el tamaño de un grupo ni la distancia entre dos grupos tienen un significado confiable. t-SNE puede dibujar un grupo compacto como grande o uno disperso como pequeño, y puede acercar o alejar grupos en el plano sin que eso refleje qué tan parecidos son en el espacio original — lo único que intenta preservar con cuidado es <em>quién es vecino cercano de quién dentro de cada grupo</em>. Lo que sí podés leer con confianza es la separación cualitativa entre clases: las tres clases forman grupos distinguibles — class_0 abajo a la derecha, class_2 arriba a la izquierda y class_1 al centro, más alargado, con unos pocos puntos naranjas metidos en los otros dos grupos.</p>
</section>
</section>
<section id="umap-vecindades-locales-con-más-estructura-global" class="level2">
<h2 class="anchored" data-anchor-id="umap-vecindades-locales-con-más-estructura-global">UMAP: vecindades locales con más estructura global</h2>
<p>UMAP (<em>Uniform Manifold Approximation and Projection</em>) persigue un objetivo parecido al de t-SNE — preservar vecindades locales —, pero parte de una formulación distinta, basada en topología de variedades, que en la práctica tiende a conservar algo más de la estructura global (la posición relativa entre grupos lejanos) que t-SNE, además de ser considerablemente más rápido en datasets grandes.</p>
<p>Sus dos hiperparámetros principales son <code>n_neighbors</code> (cuántos vecinos considera al construir el grafo de vecindad local — el equivalente aproximado a la perplejidad de t-SNE) y <code>min_dist</code> (qué tan apretados deja los puntos dentro de un mismo grupo en la proyección final). A diferencia de t-SNE, UMAP <strong>sí</strong> aprende una función de proyección reutilizable: una vez ajustado, se puede llamar <code>.transform()</code> sobre observaciones nuevas sin tener que reajustar todo el modelo. Esa diferencia técnica, aparentemente pequeña, es la que determina si un método sirve solo para explorar datos o también para un pipeline de producción.</p>
<div id="e3df27e2" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:50:07.232836Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:50:07.231533Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:50:25.627043Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:50:25.624996Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">modelo_umap <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> umap.UMAP(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, n_neighbors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, min_dist<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA)</span>
<span id="cb10-2">proy_umap <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_umap.fit_transform(X_std)</span>
<span id="cb10-3"></span>
<span id="cb10-4">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb10-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> clase, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), COLORES):</span>
<span id="cb10-6">    mascara <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> clase</span>
<span id="cb10-7">    ax.scatter(proy_umap[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], proy_umap[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres_clase[clase], alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb10-8">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Dimensión 1 (UMAP)'</span>)</span>
<span id="cb10-9">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Dimensión 2 (UMAP)'</span>)</span>
<span id="cb10-10">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'UMAP (n_neighbors=15, min_dist=0.1)'</span>)</span>
<span id="cb10-11">ax.legend()</span>
<span id="cb10-12">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>C:\Users\wilde\.conda\envs\ANALITICA\Lib\site-packages\umap\umap_.py:1952: UserWarning: n_jobs value 1 overridden to 1 by setting random_state. Use no seed for parallelism.
  warn(</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/14-reduccion-dimensionalidad/index_files/figure-html/cell-8-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-esta-proyección-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-proyección-1">Cómo leer esta proyección</h3>
<p>Igual que con t-SNE, las distancias entre grupos no son literales — son una guía aproximada, no una medida. Lo que conviene comparar acá es la <strong>compacidad</strong> de cada clase y si la separación entre clases coincide cualitativamente con lo que viste en PCA, MDS y t-SNE: UMAP también deja tres grupos y el mismo orden cualitativo que t-SNE y PCA (class_0 compacto y separado, class_2 apretado, class_1 más extendido, con algunos naranjas cerca de los otros). Los grupos se ven más compactos que en MDS.</p>
</section>
</section>
<section id="las-cuatro-proyecciones-lado-a-lado" class="level2">
<h2 class="anchored" data-anchor-id="las-cuatro-proyecciones-lado-a-lado">Las cuatro proyecciones, lado a lado</h2>
<div id="9aecc4d4" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:50:25.631107Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:50:25.630644Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:50:26.078486Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:50:26.076548Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">proyecciones <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb12-2">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PCA'</span>, proy_pca),</span>
<span id="cb12-3">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MDS'</span>, proy_mds),</span>
<span id="cb12-4">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'t-SNE'</span>, proy_tsne),</span>
<span id="cb12-5">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'UMAP'</span>, proy_umap),</span>
<span id="cb12-6">]</span>
<span id="cb12-7"></span>
<span id="cb12-8">fig, ejes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>))</span>
<span id="cb12-9"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax, (nombre, proy) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(ejes.ravel(), proyecciones):</span>
<span id="cb12-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> clase, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), COLORES):</span>
<span id="cb12-11">        mascara <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> clase</span>
<span id="cb12-12">        ax.scatter(proy[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], proy[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)</span>
<span id="cb12-13">    ax.set_title(nombre)</span>
<span id="cb12-14">    ax.set_xticks([])</span>
<span id="cb12-15">    ax.set_yticks([])</span>
<span id="cb12-16">fig.suptitle(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Mismo dataset, cuatro formas de aplastarlo a 2 dimensiones'</span>)</span>
<span id="cb12-17">plt.tight_layout()</span>
<span id="cb12-18">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/14-reduccion-dimensionalidad/index_files/figure-html/cell-9-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-esta-comparación" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-comparación">Cómo leer esta comparación</h3>
<p>Las cuatro parten exactamente de los mismos 178 vinos estandarizados. PCA y MDS, al preservar distancias/varianza global, producen formas más parecidas entre sí. t-SNE y UMAP, al priorizar vecindades locales, suelen mostrar grupos más compactos y mejor separados — pero recordá la advertencia de más arriba: esa separación más “limpia” no significa que el método haya encontrado más información real; significa que optimiza para otra cosa (vecindad local en vez de distancia global).</p>
</section>
</section>
<section id="reducir-para-visualizar-frente-a-reducir-para-predecir" class="level2">
<h2 class="anchored" data-anchor-id="reducir-para-visualizar-frente-a-reducir-para-predecir">Reducir para visualizar frente a reducir para predecir</h2>
<p>Esta distinción organiza todo lo que viste hasta acá:</p>
<ul>
<li><strong>Reducir para visualizar</strong>: el objetivo es que una persona entienda la estructura de los datos de un vistazo. Acá t-SNE y UMAP suelen ganar — producen imágenes más legibles, con grupos más definidos — siempre que quien las lea conozca sus límites (distancias y tamaños no literales).</li>
<li><strong>Reducir para predecir</strong>: el objetivo es alimentar un modelo supervisado con menos columnas sin perder poder predictivo, dentro de un pipeline reproducible que después va a recibir datos nuevos. Acá importan otras dos cosas que visualizar no exige: que el método tenga una forma honesta de transformar observaciones nuevas (ver la advertencia sobre t-SNE más arriba), y que exista algún criterio objetivo — como la varianza explicada de PCA — para decidir cuántas dimensiones retener, en vez de fijar 2 solo porque es lo que cabe en una pantalla.</li>
</ul>
<p>El notebook aplicado de este artículo retoma exactamente esta distinción con números concretos.</p>
</section>
<section id="riesgos-distorsión-e-inestabilidad" class="level2">
<h2 class="anchored" data-anchor-id="riesgos-distorsión-e-inestabilidad">Riesgos: distorsión e inestabilidad</h2>
<p>Tres riesgos concretos a tener presentes antes de usar cualquiera de estos métodos para sacar una conclusión:</p>
<ul>
<li><strong>Distorsión de distancias.</strong> Ya lo viste: en t-SNE y UMAP, ni el tamaño de un grupo ni la distancia entre grupos son literales. Tratarlos como si lo fueran — “el grupo A está más lejos del B que del C, entonces A y B son más distintos” — es sobre-interpretar la imagen.</li>
<li><strong>Inestabilidad frente a hiperparámetros.</strong> La forma de la proyección de t-SNE y UMAP cambia con la perplejidad o <code>n_neighbors</code>. Un cambio de hiperparámetro puede hacer aparecer o desaparecer grupos que no reflejan ninguna estructura real adicional en los datos — solo un ajuste distinto del algoritmo.</li>
</ul>
<div id="97faa041" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:50:26.082929Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:50:26.082402Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:50:28.400730Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:50:28.398888Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">fig, ejes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb13-2">perplejidades <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>]</span>
<span id="cb13-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax, perp <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(ejes, perplejidades):</span>
<span id="cb13-4">    tsne_prueba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> TSNE(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, perplexity<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>perp, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA, init<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pca'</span>, learning_rate<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'auto'</span>)</span>
<span id="cb13-5">    proy_prueba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tsne_prueba.fit_transform(X_std)</span>
<span id="cb13-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> clase, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), COLORES):</span>
<span id="cb13-7">        mascara <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> clase</span>
<span id="cb13-8">        ax.scatter(proy_prueba[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], proy_prueba[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)</span>
<span id="cb13-9">    ax.set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'perplejidad = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>perp<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb13-10">    ax.set_xticks([])</span>
<span id="cb13-11">    ax.set_yticks([])</span>
<span id="cb13-12">fig.suptitle(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Mismos datos, misma semilla, solo cambia la perplejidad'</span>)</span>
<span id="cb13-13">plt.tight_layout()</span>
<span id="cb13-14">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/14-reduccion-dimensionalidad/index_files/figure-html/cell-10-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-2" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-2">Cómo leer este resultado</h3>
<p>Las tres imágenes vienen exactamente de los mismos datos y la misma semilla; lo único que cambió es la perplejidad. Con perplejidad 5 los grupos se fragmentan: class_0 se parte en dos nubes y hay más mezcla con class_1. Con 30 aparecen tres bloques claros, la misma lectura del gráfico principal. Con 100 los tres cultivos siguen ocupando regiones distintas, pero más difusas y menos apretadas. La estructura de tres clases se sostiene; cambia cuán partidos o extendidos se dibujan los grupos. Esa sensibilidad es la razón práctica para probar más de un valor de hiperparámetro antes de quedarte con una sola imagen como si fuera “la” respuesta — y para nunca reportar una proyección de t-SNE sin decir con qué perplejidad se generó.</p>
<ul>
<li><strong>Falta de reproducibilidad entre corridas.</strong> Si no fijás la semilla, dos ejecuciones con los mismos datos y los mismos hiperparámetros pueden dar proyecciones visualmente distintas (aunque preserven la misma estructura de vecindad). En este artículo fijamos <code>random_state=SEMILLA</code> en MDS, t-SNE y UMAP por la misma razón que en bootstrap o validación cruzada: para que el resultado sea reproducible.</li>
</ul>
</section>
</section>
<section id="qué-hace-y-qué-no-hace-cada-método" class="level2">
<h2 class="anchored" data-anchor-id="qué-hace-y-qué-no-hace-cada-método">Qué hace y qué no hace cada método</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
</colgroup>
<thead>
<tr class="header">
<th>Método</th>
<th>Preserva</th>
<th>Determinista</th>
<th>Proyecta datos nuevos (<code>.transform</code>)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>PCA</td>
<td>Varianza global, relaciones lineales</td>
<td>Sí</td>
<td>Sí</td>
</tr>
<tr class="even">
<td>MDS</td>
<td>Distancias globales por pares</td>
<td>No (optimización iterativa)</td>
<td>No</td>
</tr>
<tr class="odd">
<td>t-SNE</td>
<td>Vecindades locales</td>
<td>No</td>
<td>No</td>
</tr>
<tr class="even">
<td>UMAP</td>
<td>Vecindades locales + algo de estructura global</td>
<td>No (semilla fija ayuda)</td>
<td>Sí</td>
</tr>
</tbody>
</table>
<p>Ningún método de esta tabla “gana” en todos los criterios. La elección depende de la pregunta: si necesitás entender visualmente cómo se agrupan tus datos, t-SNE o UMAP suelen ser más informativos; si necesitás una transformación reproducible dentro de un pipeline predictivo, PCA o UMAP son las opciones honestas; MDS rinde más cuando el punto de partida ya es una matriz de distancias (no necesariamente euclidianas) en vez de variables numéricas crudas.</p>
</section>
<section id="qué-sigue" class="level2">
<h2 class="anchored" data-anchor-id="qué-sigue">Qué sigue</h2>
<p>Hasta acá, toda la serie trabajó con observaciones que podían reordenarse libremente — filas intercambiables de una tabla. El siguiente artículo cambia esa premisa: entran los datos donde el orden <em>sí</em> importa, porque cada observación depende de las anteriores en el tiempo.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>reduccion-dimensionalidad</category>
  <category>tsne</category>
  <category>umap</category>
  <category>manifold-learning</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/avanzado/14-reduccion-dimensionalidad/</guid>
  <pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Análisis Avanzado de Datos — Caso aplicado: comparar PCA, t-SNE y UMAP en los mismos datos</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/avanzado/14a-caso-comparacion-pca-tsne-umap/</link>
  <description><![CDATA[ 




<section id="análisis-avanzado-de-datos-caso-aplicado-comparar-pca-t-sne-y-umap-en-los-mismos-datos" class="level1">
<h1>Análisis Avanzado de Datos — Caso aplicado: comparar PCA, t-SNE y UMAP en los mismos datos</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado convierte datos en decisiones. Científico de Datos, Arquitecto de IA y asesor tecnológico con más de 20 años de experiencia en analítica avanzada, machine learning, Big Data e IoT. Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), asesora a entidades gubernamentales y empresas privadas en Colombia y es referente en analítica y normatividad para los sectores postal y logístico del país. Una serie pensada para ir de la teoría a la práctica, con ejemplos concretos en cada paso.</p>
<p>📌 <em>Parte de la serie <strong>Análisis Avanzado de Datos</strong>.</em></p>
</section>
<section id="de-la-intuición-a-los-números" class="level2">
<h2 class="anchored" data-anchor-id="de-la-intuición-a-los-números">De la intuición a los números</h2>
<p>El artículo anterior mostró, de forma visual, cómo PCA, MDS, t-SNE y UMAP proyectan el mismo conjunto de vinos a 2 dimensiones, y advirtió que las distancias en t-SNE y UMAP no son literales. Este caso aplicado reemplaza esa intuición visual por dos métricas concretas de qué tanta estructura conserva cada método, y usa esas métricas para responder una pregunta de producción: si el objetivo es alimentar un modelo predictivo en vez de solo mirar un gráfico, ¿cuál conviene usar?</p>
</section>
<section id="objetivos-de-este-caso" class="level2">
<h2 class="anchored" data-anchor-id="objetivos-de-este-caso">Objetivos de este caso</h2>
<p>Al terminar vas a ser capaz de:</p>
<ul>
<li>calcular y leer el <em>trustworthiness</em> de una proyección, una métrica de preservación local;</li>
<li>comparar la preservación global de distancias entre métodos mediante correlación de rangos;</li>
<li>explicar por qué t-SNE y MDS clásico no son aptos para un pipeline que debe transformar datos nuevos;</li>
<li>decidir, con una comparación numérica, si conviene proyectar a 2D para un modelo predictivo o no.</li>
</ul>
</section>
<section id="preparación-del-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparación-del-entorno">Preparación del entorno</h2>
<div id="6ba1519d" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:50:32.886342Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:50:32.886127Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:51:07.930736Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:51:07.927681Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy.spatial.distance <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pdist</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy.stats <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> spearmanr</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.datasets <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> load_wine</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.decomposition <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PCA</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LogisticRegression</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.manifold <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> TSNE, trustworthiness</span>
<span id="cb1-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> accuracy_score</span>
<span id="cb1-11"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split</span>
<span id="cb1-12"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.pipeline <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Pipeline</span>
<span id="cb1-13"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> StandardScaler</span>
<span id="cb1-14"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> umap</span>
<span id="cb1-15"></span>
<span id="cb1-16">SEMILLA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2026</span></span>
<span id="cb1-17">COLORES <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#2A6F97'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#D97706'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#2D6A4F'</span>]</span>
<span id="cb1-18">plt.rcParams.update({</span>
<span id="cb1-19">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'figure.figsize'</span>: (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb1-20">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.top'</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb1-21">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.right'</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb1-22">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.titleweight'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'bold'</span>,</span>
<span id="cb1-23">})</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>C:\Users\wilde\.conda\envs\ANALITICA\Lib\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm</code></pre>
</div>
</div>
</section>
<section id="los-datos" class="level2">
<h2 class="anchored" data-anchor-id="los-datos">Los datos</h2>
<p>Mismo conjunto que en el artículo conceptual: 178 vinos, 13 variables químicas, 3 clases. Igual que siempre, estandarizamos antes de proyectar.</p>
<div id="889e8215" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:51:07.937351Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:51:07.936205Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:51:08.053711Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:51:08.051080Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">wine <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> load_wine(as_frame<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-2">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> wine.data.copy()</span>
<span id="cb3-3">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> wine.target.copy()</span>
<span id="cb3-4"></span>
<span id="cb3-5">escalador <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler()</span>
<span id="cb3-6">X_std <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> escalador.fit_transform(X)</span>
<span id="cb3-7"></span>
<span id="cb3-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Observaciones: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, variables: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Observaciones: 178, variables: 13</code></pre>
</div>
</div>
</section>
<section id="métrica-1-trustworthiness-preservación-local" class="level2">
<h2 class="anchored" data-anchor-id="métrica-1-trustworthiness-preservación-local">Métrica 1: <em>trustworthiness</em> (preservación local)</h2>
<p>El <em>trustworthiness</em> mide si los vecinos más cercanos de un punto <strong>en la proyección</strong> también eran sus vecinos más cercanos <strong>en el espacio original</strong>. Va de 0 a 1: 1 significa que la vecindad local se preservó perfectamente; valores bajos indican que la proyección “inventó” vecinos que no lo eran. Es la métrica natural para evaluar t-SNE y UMAP, porque es justo lo que esos métodos intentan optimizar — a diferencia del estrés de MDS o la varianza explicada de PCA, que miden preservación global.</p>
<div id="dfbf4637" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:51:08.060434Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:51:08.059647Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:51:33.985262Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:51:33.983019Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">proyecciones <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb5-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PCA'</span>: PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA).fit_transform(X_std),</span>
<span id="cb5-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'t-SNE'</span>: TSNE(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, perplexity<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA, init<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pca'</span>, learning_rate<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'auto'</span>).fit_transform(X_std),</span>
<span id="cb5-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'UMAP'</span>: umap.UMAP(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, n_neighbors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, min_dist<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA).fit_transform(X_std),</span>
<span id="cb5-5">}</span>
<span id="cb5-6"></span>
<span id="cb5-7">filas_confianza <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb5-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, proy <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> proyecciones.items():</span>
<span id="cb5-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>):</span>
<span id="cb5-10">        t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> trustworthiness(X_std, proy, n_neighbors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k)</span>
<span id="cb5-11">        filas_confianza.append({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'metodo'</span>: nombre, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k_vecinos'</span>: k, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'trustworthiness'</span>: t})</span>
<span id="cb5-12"></span>
<span id="cb5-13">tabla_confianza <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(filas_confianza).pivot(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'metodo'</span>, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k_vecinos'</span>, values<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'trustworthiness'</span>)</span>
<span id="cb5-14">display(tabla_confianza.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>C:\Users\wilde\.conda\envs\ANALITICA\Lib\site-packages\umap\umap_.py:1952: UserWarning: n_jobs value 1 overridden to 1 by setting random_state. Use no seed for parallelism.
  warn(</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th">k_vecinos</th>
<th data-quarto-table-cell-role="th">5</th>
<th data-quarto-table-cell-role="th">10</th>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">metodo</th>
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th"></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">PCA</th>
<td>0.871</td>
<td>0.888</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">UMAP</th>
<td>0.959</td>
<td>0.951</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">t-SNE</th>
<td>0.967</td>
<td>0.956</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-esta-tablacada-celda-es-el-trustworthiness-de-ese-método-con-ese-número-de-vecinos-considerados.-con-5-vecinos-t-sne-llega-a-0.967-umap-a-0.959-y-pca-a-0.871-con-10-vecinos-el-orden-se-mantiene-0.956-0.951-y-0.888.-en-este-dataset-los-no-lineales-sí-mejoran-la-vecindad-local-respecto-de-pca-y-la-brecha-unos-8-a-10-puntos-porcentuales-se-sostiene-tanto-con-5-como-con-10-vecinos-así-que-no-es-ruido-de-una-sola-elección-de-.-aun-así-con-solo-13-variables-de-partida-una-dimensionalidad-moderada-y-clases-ya-bastante-separables-de-forma-lineal-la-ventaja-de-los-métodos-no-lineales-acá-es-más-modesta-que-la-que-suelen-mostrar-en-datasets-de-miles-de-variables-con-estructura-fuertemente-curva-el-vino-no-fuerza-demasiado-los-límites-de-pca." class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-tablacada-celda-es-el-trustworthiness-de-ese-método-con-ese-número-de-vecinos-considerados.-con-5-vecinos-t-sne-llega-a-0.967-umap-a-0.959-y-pca-a-0.871-con-10-vecinos-el-orden-se-mantiene-0.956-0.951-y-0.888.-en-este-dataset-los-no-lineales-sí-mejoran-la-vecindad-local-respecto-de-pca-y-la-brecha-unos-8-a-10-puntos-porcentuales-se-sostiene-tanto-con-5-como-con-10-vecinos-así-que-no-es-ruido-de-una-sola-elección-de-.-aun-así-con-solo-13-variables-de-partida-una-dimensionalidad-moderada-y-clases-ya-bastante-separables-de-forma-lineal-la-ventaja-de-los-métodos-no-lineales-acá-es-más-modesta-que-la-que-suelen-mostrar-en-datasets-de-miles-de-variables-con-estructura-fuertemente-curva-el-vino-no-fuerza-demasiado-los-límites-de-pca.">Cómo leer esta tablaCada celda es el <em>trustworthiness</em> de ese método con ese número de vecinos considerados. Con 5 vecinos, t-SNE llega a <strong>0.967</strong>, UMAP a <strong>0.959</strong> y PCA a <strong>0.871</strong>; con 10 vecinos el orden se mantiene (<strong>0.956</strong>, <strong>0.951</strong> y <strong>0.888</strong>). En este dataset los no lineales sí mejoran la vecindad local respecto de PCA, y la brecha (unos 8 a 10 puntos porcentuales) se sostiene tanto con 5 como con 10 vecinos, así que no es ruido de una sola elección de $. Aun así, con solo 13 variables de partida (una dimensionalidad moderada) y clases ya bastante separables de forma lineal, la ventaja de los métodos no lineales acá es más modesta que la que suelen mostrar en datasets de miles de variables con estructura fuertemente curva — el vino no fuerza demasiado los límites de PCA.</h3>
</section>
</section>
<section id="métrica-2-correlación-de-distancias-preservación-global" class="level2">
<h2 class="anchored" data-anchor-id="métrica-2-correlación-de-distancias-preservación-global">Métrica 2: correlación de distancias (preservación global)</h2>
<p><em>Trustworthiness</em> mide vecindad local; para preservación <strong>global</strong> comparamos directamente las distancias por pares. Tomamos todas las distancias euclidianas entre pares de observaciones en el espacio original de 13 variables, las mismas distancias entre pares en cada proyección 2D, y calculamos la correlación de Spearman entre ambas listas: si vale 1, el orden de “quién está más lejos de quién” se preservó exactamente; si vale 0, no hay relación.</p>
<div id="d72e0a95" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:51:33.990553Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:51:33.989721Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:51:34.033440Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:51:34.031631Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">distancias_originales <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pdist(X_std)</span>
<span id="cb7-2"></span>
<span id="cb7-3">filas_correlacion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb7-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, proy <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> proyecciones.items():</span>
<span id="cb7-5">    distancias_proyectadas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pdist(proy)</span>
<span id="cb7-6">    rho, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> spearmanr(distancias_originales, distancias_proyectadas)</span>
<span id="cb7-7">    filas_correlacion.append({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'metodo'</span>: nombre, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'correlacion_spearman'</span>: rho})</span>
<span id="cb7-8"></span>
<span id="cb7-9">tabla_correlacion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(filas_correlacion).set_index(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'metodo'</span>)</span>
<span id="cb7-10">display(tabla_correlacion.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">correlacion_spearman</th>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">metodo</th>
<th data-quarto-table-cell-role="th"></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">PCA</th>
<td>0.824</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">t-SNE</th>
<td>0.780</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">UMAP</th>
<td>0.755</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-este-resultado" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado">Cómo leer este resultado</h3>
<p>PCA conserva mejor el orden global de distancias (<strong>0.824</strong>), delante de t-SNE (<strong>0.780</strong>) y UMAP (<strong>0.755</strong>). Es esperable que PCA puntúe más alto acá que en <em>trustworthiness</em>: está optimizado exactamente para este tipo de preservación global, mientras que t-SNE sacrifica distancia global a propósito para ganar nitidez en la vecindad local — las dos tablas de esta sección miden objetivos distintos, no la misma cosa con otra fórmula.</p>
</section>
</section>
<section id="la-pregunta-que-de-verdad-separa-visualizar-de-predecir" class="level2">
<h2 class="anchored" data-anchor-id="la-pregunta-que-de-verdad-separa-visualizar-de-predecir">La pregunta que de verdad separa “visualizar” de “predecir”</h2>
<p>Las dos métricas anteriores comparan qué tan fiel es cada proyección. Pero para usar una proyección dentro de un modelo predictivo hace falta algo más básico: poder aplicarle <strong>la misma transformación ya aprendida</strong> a observaciones nuevas, sin tener que volver a ajustar el método desde cero cada vez que llega un dato. Esto es justamente lo que distingue a <code>fit_transform</code> de <code>fit</code> + <code>transform</code> por separado:</p>
<ul>
<li><strong>PCA</strong>: aprende una matriz de proyección fija; <code>.transform()</code> sobre datos nuevos es directo.</li>
<li><strong>UMAP</strong>: también aprende una función reutilizable; soporta <code>.transform()</code> sobre datos nuevos (con alguna pérdida de fidelidad frente a reajustar todo, pero es una operación válida y rápida).</li>
<li><strong>MDS clásico</strong> y <strong>t-SNE</strong>: no aprenden una función reutilizable. Solo saben proyectar el conjunto exacto con el que fueron ajustados; no hay <code>.transform()</code> para datos nuevos sin reajustar todo el modelo con los datos viejos y nuevos juntos.</li>
</ul>
<p>Por esta razón, en la comparación predictiva que sigue solo entran <strong>PCA</strong> y <strong>UMAP</strong> — son los dos métodos de este artículo que se pueden meter dentro de un <code>Pipeline</code> de <code>scikit-learn</code> sin incurrir en fuga de información ni en tener que reajustar sobre el conjunto de prueba.</p>
</section>
<section id="comparación-predictiva-pca2d-frente-a-umap2d-frente-a-las-13-variables-originales" class="level2">
<h2 class="anchored" data-anchor-id="comparación-predictiva-pca2d-frente-a-umap2d-frente-a-las-13-variables-originales">Comparación predictiva: PCA(2D) frente a UMAP(2D) frente a las 13 variables originales</h2>
<p>Partimos los datos en entrenamiento y prueba, igual que en el capítulo de PCA, y comparamos tres pipelines de clasificación. Fijamos 2 componentes en los tres casos a propósito — no es un valor optimizado por validación cruzada, es el mismo número de dimensiones que usamos para graficar arriba, para que la comparación sea justa contra esas imágenes.</p>
<div id="05be798b" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-10-02T16:51:34.037262Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-10-02T16:51:34.036818Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-10-02T16:51:43.104082Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-10-02T16:51:43.102191Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">X_train, X_test, y_train, y_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(</span>
<span id="cb8-2">    X, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA, stratify<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y</span>
<span id="cb8-3">)</span>
<span id="cb8-4"></span>
<span id="cb8-5">modelo_completo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([</span>
<span id="cb8-6">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'escalador'</span>, StandardScaler()),</span>
<span id="cb8-7">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clasificador'</span>, LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>)),</span>
<span id="cb8-8">])</span>
<span id="cb8-9">modelo_pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([</span>
<span id="cb8-10">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'escalador'</span>, StandardScaler()),</span>
<span id="cb8-11">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pca'</span>, PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA)),</span>
<span id="cb8-12">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clasificador'</span>, LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>)),</span>
<span id="cb8-13">])</span>
<span id="cb8-14">modelo_umap <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([</span>
<span id="cb8-15">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'escalador'</span>, StandardScaler()),</span>
<span id="cb8-16">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'umap'</span>, umap.UMAP(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, n_neighbors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, min_dist<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA)),</span>
<span id="cb8-17">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clasificador'</span>, LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>)),</span>
<span id="cb8-18">])</span>
<span id="cb8-19"></span>
<span id="cb8-20">resultados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb8-21"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, modelo <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'13 variables'</span>, modelo_completo), (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PCA (2D)'</span>, modelo_pca), (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'UMAP (2D)'</span>, modelo_umap)]:</span>
<span id="cb8-22">    modelo.fit(X_train, y_train)</span>
<span id="cb8-23">    exactitud <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> accuracy_score(y_test, modelo.predict(X_test))</span>
<span id="cb8-24">    resultados.append({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'modelo'</span>: nombre, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dimensiones'</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> nombre <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'13 variables'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'exactitud_test'</span>: exactitud})</span>
<span id="cb8-25"></span>
<span id="cb8-26">tabla_resultados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(resultados)</span>
<span id="cb8-27">display(tabla_resultados.style.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">format</span>({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'exactitud_test'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{:.2%}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>}))</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>C:\Users\wilde\.conda\envs\ANALITICA\Lib\site-packages\umap\umap_.py:1952: UserWarning: n_jobs value 1 overridden to 1 by setting random_state. Use no seed for parallelism.
  warn(</code></pre>
</div>
<div class="cell-output cell-output-display">
<style type="text/css">
</style>

<table id="T_3d099" class="caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th class="blank level0" data-quarto-table-cell-role="th">&nbsp;</th>
<th id="T_3d099_level0_col0" class="col_heading level0 col0" data-quarto-table-cell-role="th">modelo</th>
<th id="T_3d099_level0_col1" class="col_heading level0 col1" data-quarto-table-cell-role="th">dimensiones</th>
<th id="T_3d099_level0_col2" class="col_heading level0 col2" data-quarto-table-cell-role="th">exactitud_test</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th id="T_3d099_level0_row0" class="row_heading level0 row0" data-quarto-table-cell-role="th">0</th>
<td id="T_3d099_row0_col0" class="data row0 col0">13 variables</td>
<td id="T_3d099_row0_col1" class="data row0 col1">13</td>
<td id="T_3d099_row0_col2" class="data row0 col2">98.15%</td>
</tr>
<tr class="even">
<th id="T_3d099_level0_row1" class="row_heading level0 row1" data-quarto-table-cell-role="th">1</th>
<td id="T_3d099_row1_col0" class="data row1 col0">PCA (2D)</td>
<td id="T_3d099_row1_col1" class="data row1 col1">2</td>
<td id="T_3d099_row1_col2" class="data row1 col2">94.44%</td>
</tr>
<tr class="odd">
<th id="T_3d099_level0_row2" class="row_heading level0 row2" data-quarto-table-cell-role="th">2</th>
<td id="T_3d099_row2_col0" class="data row2 col0">UMAP (2D)</td>
<td id="T_3d099_row2_col1" class="data row2 col1">2</td>
<td id="T_3d099_row2_col2" class="data row2 col2">96.30%</td>
</tr>
</tbody>
</table>
</div>
</div>
<section id="cómo-leer-esta-comparación" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-comparación">Cómo leer esta comparación</h3>
<p>En el conjunto de prueba, las 13 variables llegan a <strong>98.15%</strong> de exactitud; UMAP en 2D se queda en <strong>96.30%</strong> y PCA en 2D en <strong>94.44%</strong>. Pasar de 13 columnas a 2 cuesta unos pocos puntos: UMAP pierde menos que PCA en esta partición, y ninguno supera al modelo completo. Fijate que el modelo con las 13 variables originales es, por construcción, al menos tan bueno como cualquier proyección a 2D podría serlo en el mejor de los casos — reducir dimensiones nunca agrega información, como mucho la reorganiza de forma más compacta. La pregunta relevante no es “¿la proyección gana?”, sino “¿la pérdida de exactitud al proyectar es aceptable a cambio de trabajar con menos columnas?” — y esa respuesta depende del problema, no de una regla general.</p>
</section>
</section>
<section id="decisión-práctica-cuántas-dimensiones-retener" class="level2">
<h2 class="anchored" data-anchor-id="decisión-práctica-cuántas-dimensiones-retener">Decisión práctica: ¿cuántas dimensiones retener?</h2>
<p>En el capítulo de PCA, la pregunta “¿cuántas dimensiones?” tenía una respuesta basada en un número objetivo: la curva de varianza explicada acumulada. UMAP no ofrece un equivalente directo — no existe una noción de “varianza explicada por componente” para <code>n_neighbors</code> o <code>min_dist</code>, porque UMAP no está optimizando varianza, está optimizando preservación de vecindad. Esto tiene una consecuencia práctica importante: si tu objetivo final es <strong>predecir</strong>, PCA te da una forma principiada de decidir cuántos componentes retener (como en el capítulo anterior); si tu objetivo es <strong>visualizar</strong>, fijar 2 o 3 dimensiones en UMAP o t-SNE es razonable porque ahí el número lo impone la pantalla, no un criterio estadístico. Usar UMAP o t-SNE como paso de reducción dentro de un pipeline predictivo es posible — y UMAP, a diferencia de t-SNE, lo permite técnicamente — pero conviene tratarlo como una decisión de ingeniería a validar con la métrica final del modelo (como hicimos arriba), no como una optimización de varianza.</p>
</section>
<section id="qué-te-llevás-de-este-caso" class="level2">
<h2 class="anchored" data-anchor-id="qué-te-llevás-de-este-caso">Qué te llevás de este caso</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
</colgroup>
<thead>
<tr class="header">
<th>Método</th>
<th>Preserva mejor</th>
<th>Sirve para predecir datos nuevos</th>
<th>Criterio para elegir dimensiones</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>PCA</td>
<td>Estructura global (distancias/varianza)</td>
<td>Sí</td>
<td>Varianza explicada acumulada</td>
</tr>
<tr class="even">
<td>MDS</td>
<td>Distancias globales</td>
<td>No</td>
<td>Estrés frente a número de dimensiones</td>
</tr>
<tr class="odd">
<td>t-SNE</td>
<td>Vecindad local</td>
<td>No</td>
<td>No aplica — valor fijado por visualización</td>
</tr>
<tr class="even">
<td>UMAP</td>
<td>Vecindad local, algo de estructura global</td>
<td>Sí</td>
<td>No aplica — validar con la métrica final</td>
</tr>
</tbody>
</table>
<p>Si tenés que elegir uno solo para explorar datos nuevos sin mucho contexto previo, UMAP suele ser el mejor punto de partida: combina vecindad local razonable, rapidez y la posibilidad — poco común entre los métodos no lineales — de aplicarse a datos nuevos.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>reduccion-dimensionalidad</category>
  <category>caso-practico</category>
  <category>tsne</category>
  <category>umap</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/avanzado/14a-caso-comparacion-pca-tsne-umap/</guid>
  <pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Análisis Avanzado de Datos — 7. Métodos de kernel: estimación de densidades y regresión</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/</link>
  <description><![CDATA[ 




<section id="análisis-avanzado-de-datos-7.-métodos-de-kernel-estimación-de-densidades-y-regresión" class="level1">
<h1>Análisis Avanzado de Datos — 7. Métodos de kernel: estimación de densidades y regresión</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado convierte datos en decisiones. Científico de Datos, Arquitecto de IA y asesor tecnológico con más de 20 años de experiencia en analítica avanzada, machine learning, Big Data e IoT. Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), asesora a entidades gubernamentales y empresas privadas en Colombia y es referente en analítica y normatividad para los sectores postal y logístico del país. Una serie pensada para ir de la teoría a la práctica, con ejemplos concretos en cada paso.</p>
<p>📌 <em>Parte de la serie <strong>Análisis Avanzado de Datos</strong>.</em></p>
</section>
<section id="del-knot-a-la-ventana" class="level2">
<h2 class="anchored" data-anchor-id="del-knot-a-la-ventana">Del knot a la ventana</h2>
<p>En el artículo anterior de la serie construiste splines: elegías dónde poner los nodos (<em>knots</em>) y ajustabas polinomios por tramos que se conectan suavemente. Funciona muy bien, pero exige decidir una estructura. Ahora tomamos otro camino, todavía dentro de la suavización, con una idea más directa: <strong>estimar el comportamiento en cada punto a partir de los datos que están cerca</strong>, sin construir ninguna base polinómica ni colocar knots.</p>
<p>Esa idea sencilla —una ventana alrededor de cada punto y un peso que decae con la distancia— da lugar a dos herramientas: la <strong>estimación de densidades</strong> (¿cómo se distribuyen mis datos?) y la <strong>regresión por kernel</strong> (¿qué valor de <img src="https://latex.codecogs.com/png.latex?y"> espero para cada <img src="https://latex.codecogs.com/png.latex?x">?). Y esa misma idea trae de vuelta, con otro nombre, el compromiso sesgo-varianza que ya conoces.</p>
</section>
<section id="objetivos-de-aprendizaje" class="level2">
<h2 class="anchored" data-anchor-id="objetivos-de-aprendizaje">Objetivos de aprendizaje</h2>
<p>Al terminar este notebook vas a entender cómo funcionan los métodos de suavización por kernel y cuándo conviene usarlos. En concreto, vas a ser capaz de:</p>
<ul>
<li><strong>Definir</strong> formalmente una densidad de probabilidad, un kernel y el estimador de densidad por kernel (KDE), y reconocer los tipos más usados (gaussiano, Epanechnikov, uniforme).</li>
<li><strong>Explicar</strong> las limitaciones del histograma y <strong>estimar</strong> una densidad con el método de kernel (KDE), entendiendo su fórmula.</li>
<li><strong>Aplicar</strong> la regresión por kernel (estimador de Nadaraya–Watson) para suavizar una relación no lineal.</li>
<li><strong>Interpretar</strong> el papel del <strong>ancho de banda</strong> <img src="https://latex.codecogs.com/png.latex?h"> como el parámetro que regula el compromiso sesgo-varianza, y <strong>seleccionarlo</strong> por validación.</li>
<li><strong>Reconocer</strong> el sesgo de frontera y otras limitaciones prácticas, y <strong>comparar</strong> el suavizado por kernel con el spline y la recta.</li>
</ul>
</section>
<section id="preparación-del-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparación-del-entorno">Preparación del entorno</h2>
<div id="19a0915a" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T02:50:49.062025Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T02:50:49.061795Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T02:50:51.234897Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T02:50:51.234450Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy.stats <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> gaussian_kde</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.neighbors <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> KernelDensity</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> SplineTransformer</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LinearRegression</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.pipeline <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_pipeline</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split, GridSearchCV, KFold</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> r2_score, mean_squared_error</span>
<span id="cb1-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.nonparametric.smoothers_lowess <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> lowess</span>
<span id="cb1-11"></span>
<span id="cb1-12">SEMILLA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2026</span></span>
<span id="cb1-13">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'figure.figsize'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb1-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Librerías cargadas"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Librerías cargadas</code></pre>
</div>
</div>
</section>
<section id="parte-a-estimación-de-densidades" class="level2">
<h2 class="anchored" data-anchor-id="parte-a-estimación-de-densidades">Parte A — Estimación de densidades</h2>
<p>Antes de suavizar una relación entre variables, empecemos por suavizar algo más básico: la forma en que se distribuye <strong>una sola variable</strong>. Es el terreno donde la idea del kernel se ve con más claridad.</p>
</section>
<section id="qué-es-una-densidad-definición-formal" class="level2">
<h2 class="anchored" data-anchor-id="qué-es-una-densidad-definición-formal">Qué es una densidad (definición formal)</h2>
<p>Cuando la variable es continua —aquí, la desviación en horas—, un valor exacto tiene probabilidad cero: <img src="https://latex.codecogs.com/png.latex?P(X%20=%20-2.17)%20=%200">. Lo que sí tiene sentido es la probabilidad de un <strong>intervalo</strong>.</p>
<p>La <strong>función de densidad</strong> <img src="https://latex.codecogs.com/png.latex?f"> es una función no negativa que convierte el área bajo la curva en probabilidad:</p>
<p><img src="https://latex.codecogs.com/png.latex?P(a%20%5Cle%20X%20%5Cle%20b)%20=%20%5Cint_a%5Eb%20f(x)%5C,dx,%20%5Cqquad%20%5Cint_%7B-%5Cinfty%7D%5E%7B%5Cinfty%7D%20f(x)%5C,dx%20=%201."></p>
<p>El número <img src="https://latex.codecogs.com/png.latex?f(x)"> <strong>no es una probabilidad</strong>. Es cuánta probabilidad se concentra por unidad de <img src="https://latex.codecogs.com/png.latex?x"> alrededor de ese punto (en este ejemplo, por hora). Por eso, en las figuras, los puntos negros van sobre el eje: marcan <em>dónde</em> cayeron los datos. La altura de la curva es densidad, no un <img src="https://latex.codecogs.com/png.latex?y"> observado.</p>
<p>Un histograma de conteos responde «¿cuántos cayeron en este intervalo?». El mismo histograma con el eje en densidad —y, más adelante, el estimador por kernel— responde «¿qué tan concentrada está la probabilidad ahí?». El objetivo de esta parte es <strong>estimar</strong> <img src="https://latex.codecogs.com/png.latex?f"> a partir de una muestra, sin suponer de antemano que sea una gaussiana.</p>
</section>
<section id="el-histograma-engaña-más-de-lo-que-crees" class="level2">
<h2 class="anchored" data-anchor-id="el-histograma-engaña-más-de-lo-que-crees">El histograma engaña más de lo que crees</h2>
<p>El histograma es la primera herramienta para ver una distribución, pero su forma depende de decisiones arbitrarias: el ancho de los intervalos (<em>bins</em>) y <strong>dónde empiezan</strong>. La misma variable puede contar historias distintas.</p>
<p>Generemos una variable con <strong>dos grupos</strong>. Piensa, por ejemplo, en la <strong>desviación (en horas) frente a la hora prometida de entrega</strong> para envíos de dos rutas mezclados: los valores negativos son entregas que llegaron antes; los positivos, entregas tardías. Vamos a dibujarla dos veces con <strong>el mismo ancho de bin</strong>, cambiando solo el punto donde empiezan los intervalos.</p>
<div id="00b78ad4" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T02:50:51.236755Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T02:50:51.236498Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T02:50:51.414460Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T02:50:51.414086Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb3-2">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">600</span></span>
<span id="cb3-3">comp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span></span>
<span id="cb3-4">datos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(comp, rng.normal(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>, n), rng.normal(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, n))</span>
<span id="cb3-5"></span>
<span id="cb3-6">ancho <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span></span>
<span id="cb3-7">bordes_a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, ancho)      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># intervalos que empiezan en -4.5</span></span>
<span id="cb3-8">bordes_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> bordes_a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> ancho <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>             <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># mismos intervalos, corridos 0.625</span></span>
<span id="cb3-9"></span>
<span id="cb3-10">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), sharey<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-11">conteos_a, _, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].hist(datos, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>bordes_a, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'white'</span>)</span>
<span id="cb3-12">conteos_b, _, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].hist(datos, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>bordes_b, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'white'</span>)</span>
<span id="cb3-13">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Ancho </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>ancho<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, bordes desde </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>bordes_a[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb3-14">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Ancho </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>ancho<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, bordes desde </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>bordes_b[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb3-15"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> a <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> ax: a.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desviación frente a la hora prometida (horas)'</span>)</span>
<span id="cb3-16">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'frecuencia'</span>)</span>
<span id="cb3-17">plt.tight_layout()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span>
<span id="cb3-18"></span>
<span id="cb3-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Conteos, bordes desde -4.5  :'</span>, conteos_a.astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>))</span>
<span id="cb3-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Conteos, bordes desde -3.875:'</span>, conteos_b.astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>))</span>
<span id="cb3-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Media global:'</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(datos.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-3-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Conteos, bordes desde -4.5  : [153 149 210  88]
Conteos, bordes desde -3.875: [261  57 244  38]
Media global: 0.25</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado">Cómo leer este resultado</h3>
<p>Los dos gráficos usan <strong>exactamente los mismos datos y el mismo ancho de bin</strong>; solo se corrieron los bordes 0.625 horas. A la izquierda, los conteos son 153, 149, 210 y 88: se ve una meseta irregular, sin un valle claro. A la derecha, 261, 57, 244 y 38: aparecen dos grupos nítidos separados por un valle. La conclusión cambió por una decisión de dibujo que nada tiene que ver con los datos.</p>
<p>¿Por qué pasa? A la izquierda, un borde cae en −2, justo en el centro del primer grupo, y lo parte en dos barras de altura parecida. A la derecha, ese grupo cae casi entero dentro de un solo intervalo.</p>
<p>Fíjate además en la <strong>media global: 0.25</strong>, que cae en el valle <em>entre</em> los dos grupos, donde casi no hay envíos. Un resumen puede describir un punto que ningún dato ocupa. Para entender la variable necesitas su <strong>forma completa</strong>, y el histograma es demasiado frágil para dártela.</p>
</section>
<section id="la-misma-trampa-en-la-avenida" class="level3">
<h3 class="anchored" data-anchor-id="la-misma-trampa-en-la-avenida">La misma trampa, en la avenida</h3>
<p>En el artículo anterior el flujo de esa avenida se grafica contra la hora, y se ven dos picos: uno a las 8 y otro cerca de las 18. Ese gráfico conserva la hora. El histograma hace otra pregunta: si anotas solo la hora a la que pasa cada vehículo, ¿siguen viéndose las dos horas pico?</p>
<p>Abajo hay 12 000 vehículos repartidos con la misma curva de flujo: pasan más donde el flujo es más alto. Los dos paneles usan intervalos de 4 horas. Solo cambia dónde empiezan, a las 0 o a las 2. La línea roja es el flujo real, en vehículos por hora, para ver dónde cae cada corte. Las líneas punteadas marcan las 8:00 y las 18:12, el centro de cada pico.</p>
<div id="2a320af2" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T02:50:51.416235Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T02:50:51.416068Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T02:50:51.609469Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T02:50:51.608997Z&quot;}}" data-execution_count="28">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> flujo_verdadero(hora):</span>
<span id="cb5-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Vehículos por minuto según la hora. La misma curva del artículo anterior."""</span></span>
<span id="cb5-3">    ritmo_base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.sin((hora <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.pi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb5-4">    pico_manana <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> ((hora <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb5-5">    pico_tarde <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">92</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> ((hora <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">18.2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.15</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb5-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> ritmo_base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> pico_manana <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> pico_tarde</span>
<span id="cb5-7"></span>
<span id="cb5-8"></span>
<span id="cb5-9">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb5-10">minutos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>, endpoint<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb5-11">peso <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.clip(flujo_verdadero(minutos), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>)</span>
<span id="cb5-12">peso <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> peso <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> peso.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()</span>
<span id="cb5-13">n_vehiculos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12000</span></span>
<span id="cb5-14">hora_paso <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.choice(minutos, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_vehiculos, p<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>peso)</span>
<span id="cb5-15"></span>
<span id="cb5-16">t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>)</span>
<span id="cb5-17">flujo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.clip(flujo_verdadero(t), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>)</span>
<span id="cb5-18">curva <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> n_vehiculos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> flujo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.trapezoid(flujo, t)</span>
<span id="cb5-19"></span>
<span id="cb5-20">ancho <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb5-21">inicios_a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>, ancho))          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># bordes en 0, 4, 8, 12, 16, 20</span></span>
<span id="cb5-22">inicios_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>, ancho))         <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># los mismos intervalos, corridos 2 horas</span></span>
<span id="cb5-23"></span>
<span id="cb5-24">fig, ejes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>), sharey<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb5-25">paneles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb5-26">    (ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], inicios_a, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Ancho 4 h, bordes desde las 0'</span>),</span>
<span id="cb5-27">    (ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], inicios_b, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Ancho 4 h, bordes desde las 2'</span>),</span>
<span id="cb5-28">)</span>
<span id="cb5-29">tasas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb5-30"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> eje, inicios, titulo <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> paneles:</span>
<span id="cb5-31">    tasas_panel <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb5-32">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> inicio <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> inicios:</span>
<span id="cb5-33">        lo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(inicio, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb5-34">        hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(inicio <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> ancho, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>)</span>
<span id="cb5-35">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> lo:</span>
<span id="cb5-36">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">continue</span></span>
<span id="cb5-37">        conteo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>((hora_paso <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> lo) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (hora_paso <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> hi))</span>
<span id="cb5-38">        tasa <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> conteo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> lo)</span>
<span id="cb5-39">        tasas_panel.append(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(tasa))</span>
<span id="cb5-40">        eje.bar(</span>
<span id="cb5-41">            lo, tasa, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> lo, align<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'edge'</span>,</span>
<span id="cb5-42">            color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'white'</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb5-43">        )</span>
<span id="cb5-44">    eje.plot(t, curva, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, lw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'-'</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb5-45">    eje.axvline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'0.35'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, lw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb5-46">    eje.axvline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">18.2</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'0.35'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, lw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb5-47">    eje.set_xlim(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>)</span>
<span id="cb5-48">    eje.set_xticks(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb5-49">    eje.set_title(titulo)</span>
<span id="cb5-50">    eje.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'hora del día'</span>)</span>
<span id="cb5-51">    tasas.append(tasas_panel)</span>
<span id="cb5-52"></span>
<span id="cb5-53">ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'vehículos por hora'</span>)</span>
<span id="cb5-54">fig.legend([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'flujo real'</span>], loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'upper right'</span>, frameon<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, bbox_to_anchor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.99</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.98</span>))</span>
<span id="cb5-55">fig.suptitle(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Misma avenida, mismos vehículos: solo se corren los bordes 2 horas'</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.03</span>)</span>
<span id="cb5-56">plt.tight_layout()</span>
<span id="cb5-57">plt.show()</span>
<span id="cb5-58"></span>
<span id="cb5-59"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Bordes desde las 0:'</span>, tasas[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb5-60"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Bordes desde las 2:'</span>, tasas[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-4-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Bordes desde las 0: [206, 574, 642, 351, 958, 271]
Bordes desde las 2: [194, 261, 867, 361, 637, 673, 208]</code></pre>
</div>
</div>
</section>
<section id="cómo-leer-este-resultado-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-1">Cómo leer este resultado</h3>
<p>A la izquierda, con bordes en 0, 4, 8, 12, 16 y 20, las tasas son 206, 574, 642, 351, 958 y 271 vehículos por hora. El corte de las 8 parte la mañana en dos barras parecidas, 574 y 642. La tarde cae entera entre las 16 y las 20 y queda en 958, la barra más alta. Se lee un pico de tarde y una meseta de mañana, de 4 a 12.</p>
<p>A la derecha, con los bordes corridos 2 horas, los intervalos completos de 4 horas dan 261, 867, 361, 637 y 673. La mañana cae entera entre las 6 y las 10: 867, la barra más alta. El corte de las 18 parte la tarde en 637 y 673. Se lee lo contrario: un pico de mañana y una meseta de tarde, de 14 a 22.</p>
<p>Los extremos del panel derecho, 194 y 208, cubren solo dos horas (de 0 a 2 y de 22 a 24) porque el día se acaba. Su altura ya está en vehículos por hora, así que se comparan con las demás.</p>
<p>Los vehículos son los mismos. Cambia sobre qué pico cae el borde.</p>
</section>
</section>
<section id="qué-es-un-kernel-definición-formal" class="level2">
<h2 class="anchored" data-anchor-id="qué-es-un-kernel-definición-formal">Qué es un kernel (definición formal)</h2>
<p>Un <strong>kernel</strong> <img src="https://latex.codecogs.com/png.latex?K"> es una función de ponderación: asigna a cada punto un peso según su distancia. En este artículo trabajaremos con kernels de suavización no negativos, normalizados y simétricos. Estas son las propiedades de los tres ejemplos siguientes; no son una definición universal para todos los métodos que usan la palabra kernel:</p>
<ul>
<li><strong>No negatividad:</strong> <img src="https://latex.codecogs.com/png.latex?K(u)%20%5Cge%200"> para todo <img src="https://latex.codecogs.com/png.latex?u">.</li>
<li><strong>Integra uno:</strong> <img src="https://latex.codecogs.com/png.latex?%5Cint_%7B-%5Cinfty%7D%5E%7B%5Cinfty%7D%20K(u)%5C,du%20=%201"> (su área vale 1, como una densidad de probabilidad).</li>
<li><strong>Simetría:</strong> <img src="https://latex.codecogs.com/png.latex?K(-u)%20=%20K(u)"> (pesa igual a izquierda y derecha).</li>
</ul>
<p>Hay muchos kernels válidos. Los tres más comunes:</p>
<ul>
<li><strong>Gaussiano:</strong> <img src="https://latex.codecogs.com/png.latex?K(u)%20=%20%5Cfrac%7B1%7D%7B%5Csqrt%7B2%5Cpi%7D%7D%20e%5E%7B-u%5E2/2%7D">. Suave, con soporte infinito (todo punto recibe algún peso).</li>
<li><strong>Epanechnikov:</strong> <img src="https://latex.codecogs.com/png.latex?K(u)%20=%20%5Cfrac%7B3%7D%7B4%7D(1-u%5E2)"> para <img src="https://latex.codecogs.com/png.latex?%7Cu%7C%5Cle%201">. Tiene soporte finito y es óptimo en un sentido teórico preciso: entre los kernels no negativos y simétricos, y usando para cada uno su ancho de banda óptimo, minimiza el error integrado cuadrático medio asintótico (AMISE) en el marco habitual de estimación de densidades de segundo orden. Es un resultado asintótico bajo condiciones de regularidad, no una garantía de menor error en cualquier muestra.</li>
<li><strong>Uniforme:</strong> <img src="https://latex.codecogs.com/png.latex?K(u)%20=%20%5Cfrac%7B1%7D%7B2%7D"> para <img src="https://latex.codecogs.com/png.latex?%7Cu%7C%5Cle%201">. Una caja: todos los vecinos dentro de la ventana pesan igual.</li>
</ul>
<div id="7e944110" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:03.733209Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:03.733019Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:03.825500Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:03.824664Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">u <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>)</span>
<span id="cb7-2">gauss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>u<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.pi)</span>
<span id="cb7-3">epan <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(u) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.75</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> u<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb7-4">unif <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(u) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb7-5"></span>
<span id="cb7-6">plt.plot(u, gauss, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Gaussiano'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb7-7">plt.plot(u, epan, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Epanechnikov'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb7-8">plt.plot(u, unif, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Uniforme'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb7-9">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'u'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'K(u)'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()</span>
<span id="cb7-10">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Tres kernels válidos'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-5-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-2" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-2">Cómo leer este resultado</h3>
<p>Los tres tienen la misma misión —dar más peso a lo cercano— pero con perfiles distintos. El <strong>gaussiano</strong> decae suavemente y nunca llega a cero: hasta los puntos lejanos aportan algo. El <strong>Epanechnikov</strong> y el <strong>uniforme</strong> tienen soporte finito: fuera de la ventana <img src="https://latex.codecogs.com/png.latex?%7Cu%7C%5Cle%201">, el peso es exactamente cero. El uniforme es una caja (todos los vecinos pesan igual, como en un histograma móvil); el Epanechnikov es un compromiso suave con soporte acotado. Entre estos kernels habituales, la elección del ancho de banda suele influir más que la forma del kernel. La comparación teórica requiere optimizar el ancho para cada kernel y fijar un criterio de error; no significa que sean intercambiables con cualquier valor de h.</p>
</section>
</section>
<section id="qué-es-el-kde-definición-formal" class="level2">
<h2 class="anchored" data-anchor-id="qué-es-el-kde-definición-formal">Qué es el KDE (definición formal)</h2>
<p>La densidad <img src="https://latex.codecogs.com/png.latex?f"> de la población <strong>no la observas</strong>. Observas una muestra <img src="https://latex.codecogs.com/png.latex?x_1,%5Cldots,x_n">. El <strong>estimador de densidad por kernel</strong> (KDE, <em>kernel density estimator</em>) es una curva <img src="https://latex.codecogs.com/png.latex?%5Chat%20f"> que estima esa <img src="https://latex.codecogs.com/png.latex?f"> desconocida:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%7Bf%7D(x)%20=%20%5Cfrac%7B1%7D%7Bn%5C,h%7D%20%5Csum_%7Bi=1%7D%5E%7Bn%7D%20K%5C!%5Cleft(%5Cfrac%7Bx%20-%20x_i%7D%7Bh%7D%5Cright)."></p>
<p>En palabras: colocas sobre <strong>cada dato</strong> una campana (el kernel <img src="https://latex.codecogs.com/png.latex?K">) de ancho <img src="https://latex.codecogs.com/png.latex?h">, las sumas y divides por <img src="https://latex.codecogs.com/png.latex?n"> para que el área siga siendo 1. <img src="https://latex.codecogs.com/png.latex?%5Chat%20f(x)"> no es la densidad verdadera ni el valor de un dato: es una estimación, y cambia si cambian la muestra o el ancho de banda <img src="https://latex.codecogs.com/png.latex?h">.</p>
<p>La diferencia con el histograma es que no partes el eje en intervalos fijos: cada observación lleva su propia campana centrada en ella.</p>
</section>
<section id="construyamos-el-kde-paso-a-paso" class="level2">
<h2 class="anchored" data-anchor-id="construyamos-el-kde-paso-a-paso">Construyamos el KDE paso a paso</h2>
<p>La muestra tiene <strong>600 entregas</strong>. El KDE pone una campana sobre cada una, así que el estimador de verdad son 600 campanas promediadas. Si las dibujáramos todas a la vez, se fundirían y no verías el ladrillo. Por eso vamos en tres tomas, de menos a más:</p>
<ol type="1">
<li><strong>Un dato.</strong> Una sola campana, para ver la pieza básica: el kernel centrado en un punto.</li>
<li><strong>Ocho datos.</strong> Los primeros 8 de la muestra (<code>datos[:8]</code>), cada uno con su campana, <strong>sin sumarlas</strong>. Es una lupa: se distinguen los solapes y los huecos. No es el KDE todavía; es un recorte para que el ojo alcance.</li>
<li><strong>Los 600.</strong> Ahí sí se suman y se promedian todas las campanas. Esa curva ya es el KDE, en la misma escala que el histograma.</li>
</ol>
<p>Para dibujar, no usamos los 600 datos como eje horizontal. Evaluamos cada campana en una <strong>malla</strong> de 500 valores de <img src="https://latex.codecogs.com/png.latex?x"> entre <img src="https://latex.codecogs.com/png.latex?-6"> y <img src="https://latex.codecogs.com/png.latex?7"> horas (<code>grid = np.linspace(-6, 7, 500)</code>). Esas 500 columnas son puntos de dibujo, no observaciones: si pusieras 200 o 1000, la curva sería la misma idea, solo más tosca o más suave al trazarla.</p>
<p>Empezamos por la primera toma.</p>
<div id="25170372" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:03.828122Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:03.827620Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:03.914770Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:03.914132Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> campana(x, centro, h):</span>
<span id="cb8-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Kernel gaussiano centrado en 'centro' con ancho h (ya normalizado)."""</span></span>
<span id="cb8-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> ((x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> centro) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> h) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.sqrt(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.pi))</span>
<span id="cb8-4"></span>
<span id="cb8-5">grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># malla de dibujo: 500 valores de x, no 500 datos</span></span>
<span id="cb8-6">punto <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> datos[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb8-7">h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span></span>
<span id="cb8-8">altura <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> campana(punto, punto, h)</span>
<span id="cb8-9"></span>
<span id="cb8-10">plt.plot(grid, campana(grid, punto, h), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb8-11">plt.vlines(punto, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, altura, colors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'0.4'</span>, linestyles<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb8-12">plt.plot([punto], [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ko'</span>, markersize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, clip_on<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb8-13">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'un dato (x=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>punto<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb8-14">plt.xlim(punto <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, punto <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb8-15">plt.ylim(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span>, altura <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.12</span>)</span>
<span id="cb8-16">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desviación (horas)'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'aporte'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()</span>
<span id="cb8-17">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Una campana (kernel) sobre un solo dato'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-6-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-3" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-3">Cómo leer este resultado</h3>
<p>Cada dato aporta una campana centrada en él. El punto negro vive sobre el eje —es el dato, no el valor de la densidad—. La línea punteada sube hasta el pico: ahí el aporte es máximo; a los lados, decae. Un solo punto genera un solo pico: la unidad básica con la que se construye toda la densidad.</p>
<p>Esta celda repite la campana, pero ya no sobre un solo dato: toma los <strong>primeros 8</strong> de la muestra de entregas y dibuja una por cada uno.</p>
<ol type="1">
<li><code>sub = datos[:8]</code> se queda con esas ocho desviaciones, en horas.</li>
<li>Cada punto negro es uno de esos datos, puesto sobre el eje en altura 0. El primer <code>plot</code> solo sirve para que la leyenda diga «datos» una vez; el bucle dibuja el resto.</li>
<li>Para cada dato, <code>campana(grid, xi, 0.3)</code> es la misma gaussiana de antes, centrada en ese punto y con ancho <img src="https://latex.codecogs.com/png.latex?h%20=%200.3">. Dividir por <code>len(sub)</code> (por 8) deja el aporte que ese dato tendría en el promedio: un octavo de la campana, no la campana entera. Por eso el eje se llama «aporte (escalado)».</li>
<li>Las ocho curvas se dibujan por separado, sin sumarlas. Donde dos datos están cerca, las campanas se cruzan; donde hay un hueco, queda espacio vacío. En el siguiente paso ya no usamos este recorte: sumamos las campanas de <strong>los 600 datos</strong>.</li>
</ol>
<div id="fa3b394d" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:03.916676Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:03.916497Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:04.019570Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:04.018677Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Los primeros 8 datos de la muestra de entregas.</span></span>
<span id="cb9-2">sub <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> datos[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>]</span>
<span id="cb9-3"></span>
<span id="cb9-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Un solo punto con etiqueta, para que la leyenda no repita «datos» ocho veces.</span></span>
<span id="cb9-5">plt.plot([sub[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]], [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ko'</span>, markersize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'datos'</span>)</span>
<span id="cb9-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> xi <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> sub:</span>
<span id="cb9-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Campana centrada en xi, ancho 0.3, dividida por 8: el aporte de un dato al promedio.</span></span>
<span id="cb9-8">    plt.plot(grid, campana(grid, xi, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(sub), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb9-9">    plt.plot([xi], [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ko'</span>, markersize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>)</span>
<span id="cb9-10">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desviación (horas)'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'aporte (escalado)'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()</span>
<span id="cb9-11">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cada dato aporta su propia campana'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-7-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="cómo-leer-este-resultado-4" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-4">Cómo leer este resultado</h3>
<p>Con varios puntos, cada uno pone su campana. Donde los datos se agolpan, las campanas se solapan y se apilan; donde hay huecos, apenas hay aporte. El siguiente paso es <strong>sumarlas todas</strong>.</p>
<p>Esta celda termina la construcción: suma las campanas de <strong>los 600 datos</strong> y las dibuja junto al histograma.</p>
<ol type="1">
<li>Fija el ancho de cada campana en <img src="https://latex.codecogs.com/png.latex?h%20=%200.3"> horas, el mismo de las figuras anteriores.</li>
<li>Recorre cada dato y evalúa <code>campana</code> sobre la malla <code>grid</code> de <strong>500</strong> valores de <img src="https://latex.codecogs.com/png.latex?x"> (la misma de las figuras anteriores: <code>np.linspace(-6, 7, 500)</code>). Sale una matriz de <strong>600 filas × 500 columnas</strong>: una fila por entrega, una columna por cada punto donde se dibuja la curva. Las 500 no son datos; son el eje horizontal del gráfico.</li>
<li>Promedia las filas. <code>mean(axis=0)</code> es <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B1%7D%7Bn%7D"> por la suma de las campanas. Como <code>campana</code> ya divide por <img src="https://latex.codecogs.com/png.latex?h">, la curva integra uno: es una densidad. Esa curva es el KDE armado a mano.</li>
<li>Dibuja el histograma con <code>density=True</code>, para que el eje sea densidad y no conteos, y superpone la curva. Así las dos estimaciones se leen en la misma escala.</li>
</ol>
<div id="00c4eb76" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:04.021961Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:04.021776Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:04.146203Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:04.145319Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># h: ancho de cada campana, en horas. El mismo de las figuras anteriores.</span></span>
<span id="cb10-2">h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span></span>
<span id="cb10-3"></span>
<span id="cb10-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Una fila por cada uno de los 600 datos; 500 columnas = la malla de dibujo (grid), no 500 entregas.</span></span>
<span id="cb10-5">aportes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([campana(grid, xi, h) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> xi <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> datos])</span>
<span id="cb10-6"></span>
<span id="cb10-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Promedio de las 600 filas = (1/n) * suma. Eso es el KDE, y ya integra uno.</span></span>
<span id="cb10-8">kde_manual <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> aportes.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb10-9"></span>
<span id="cb10-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># density=True pone el histograma en la misma escala que la curva (densidad, no conteos).</span></span>
<span id="cb10-11">plt.hist(datos, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>, density<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lightsteelblue'</span>,</span>
<span id="cb10-12">         edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'white'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'histograma'</span>)</span>
<span id="cb10-13">plt.plot(grid, kde_manual, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'suma de campanas (KDE)'</span>)</span>
<span id="cb10-14">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desviación (horas)'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'densidad'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()</span>
<span id="cb10-15">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'El KDE es la suma (promediada) de todas las campanas'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="antes-de-seguir-pregúntate" class="level3">
<h3 class="anchored" data-anchor-id="antes-de-seguir-pregúntate">Antes de seguir, pregúntate</h3>
<p>Mirando la curva roja, ¿cuántos grupos (modas) muestra la variable? ¿Y esa forma dependió de dónde empezaban los intervalos, como pasaba con el histograma?</p>
</section>
<section id="cómo-leer-este-resultado-5" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-5">Cómo leer este resultado</h3>
<p>Esa curva roja <strong>es</strong> el KDE: la suma de las 600 campanas, dividida por el número de datos para que integre uno. Cada campana está centrada en su propio dato, no en intervalos fijados de antemano, así que desaparece la arbitrariedad del punto de inicio que vimos en el histograma. Y la estructura real emerge sola: las <strong>dos modas</strong> que mezclamos. Acabas de construir un estimador de densidad desde cero. Lo que sí sigue por decidir es el ancho de cada campana, <img src="https://latex.codecogs.com/png.latex?h">, que cumple el papel del ancho del bin; a eso volvemos enseguida.</p>
<p>En el ejemplo de las entregas, esos dos picos serían <strong>dos rutas</strong>: una que suele llegar unas dos horas antes de lo prometido, muy concentrada, y otra que llega unas dos horas y media tarde, más dispersa. La media global (0.25) no describe a ninguna de las dos: cae en el valle, donde casi no hay envíos. Mezclarlas en un solo número borra justo lo que te importa: que hay dos operaciones distintas.</p>
</section>
</section>
<section id="la-fórmula-del-kde-ahora-en-código" class="level2">
<h2 class="anchored" data-anchor-id="la-fórmula-del-kde-ahora-en-código">La fórmula del KDE, ahora en código</h2>
<p>La definición de arriba es lo que acabas de armar a mano:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%7Bf%7D(x)%20=%20%5Cfrac%7B1%7D%7Bn%5C,h%7D%20%5Csum_%7Bi=1%7D%5E%7Bn%7D%20K%5C!%5Cleft(%5Cfrac%7Bx%20-%20x_i%7D%7Bh%7D%5Cright)"></p>
<p>donde <img src="https://latex.codecogs.com/png.latex?K"> es el kernel, <img src="https://latex.codecogs.com/png.latex?n"> el número de datos y <img src="https://latex.codecogs.com/png.latex?h"> el <strong>ancho de banda</strong>. En la práctica no la programas a mano: <code>scipy</code> y <code>scikit-learn</code> la traen lista. Pero no hacen lo mismo con <img src="https://latex.codecogs.com/png.latex?h">. <code>scipy.gaussian_kde</code> <strong>elige el ancho de banda por ti</strong> (regla de Scott por defecto, o Silverman si se lo pides con <code>bw_method='silverman'</code>).</p>
<p>Las <strong>reglas de Scott y de Silverman</strong> son fórmulas cerradas para elegir <img src="https://latex.codecogs.com/png.latex?h"> sin validar. En una dimensión las dos son del tipo <img src="https://latex.codecogs.com/png.latex?h%20=%20c%5C,%5Chat%5Csigma%5C,%20n%5E%7B-1/5%7D">: miran el tamaño de muestra y la dispersión de los datos. El <img src="https://latex.codecogs.com/png.latex?n%5E%7B-1/5%7D"> no es un número mágico: sale de minimizar el <strong>AMISE</strong> (<em>asymptotic mean integrated squared error</em>), un error teórico de <strong>toda</strong> la curva cuando <img src="https://latex.codecogs.com/png.latex?n"> es grande —promedio, a lo largo de <img src="https://latex.codecogs.com/png.latex?x">, de <img src="https://latex.codecogs.com/png.latex?(%5Chat%20f%20-%20f)%5E2">—. Lo usan suponiendo que <img src="https://latex.codecogs.com/png.latex?f"> se parece a una gaussiana (referencia normal). Scott, en <code>scipy</code>, usa el factor <img src="https://latex.codecogs.com/png.latex?n%5E%7B-1/5%7D"> (<img src="https://latex.codecogs.com/png.latex?c%20=%201">). Silverman usa un factor distinto: en <code>scipy</code> es <img src="https://latex.codecogs.com/png.latex?(3n/4)%5E%7B-1/5%7D">; en la versión de los libros a veces entra también el rango intercuartílico, más resistente a valores extremos. Ninguna de las dos inspecciona si hay dos grupos o un pico raro: si la forma no es gaussiana, el <img src="https://latex.codecogs.com/png.latex?h"> que entregan no es un óptimo para esa muestra, solo un atajo rápido. La fórmula del AMISE la desglosamos en la sección del compromiso sesgo-varianza.</p>
<p>En <code>sklearn</code> normalmente fijas <img src="https://latex.codecogs.com/png.latex?h"> tú, y si le pides una regla automática hay un detalle que conviene conocer. Veamos esa diferencia.</p>
<div id="8d6a59a3" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:04.148589Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:04.148384Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:04.283077Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:04.282538Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1">kde_scipy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gaussian_kde(datos)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># bw_method='scott' por defecto</span></span>
<span id="cb11-2">h_scott <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.sqrt(np.asarray(kde_scipy.covariance).squeeze()))</span>
<span id="cb11-3"></span>
<span id="cb11-4">kde_sk_scott <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KernelDensity(bandwidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'scott'</span>).fit(datos.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb11-5">h_sk <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(kde_sk_scott.bandwidth_)</span>
<span id="cb11-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># score_samples devuelve log-densidad; exp la pasa a la misma escala que scipy.</span></span>
<span id="cb11-7">dens_sk <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(kde_sk_scott.score_samples(grid.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)))</span>
<span id="cb11-8"></span>
<span id="cb11-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'scipy.gaussian_kde elige el ancho de banda solo (regla de Scott).'</span>)</span>
<span id="cb11-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  h de scipy:                  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h_scott<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb11-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  h de sklearn con "scott":    </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h_sk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb11-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  desviación estándar datos:   </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>datos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb11-13"></span>
<span id="cb11-14">plt.hist(datos, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>, density<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lightsteelblue'</span>,</span>
<span id="cb11-15">         edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'white'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'histograma'</span>)</span>
<span id="cb11-16">plt.plot(grid, kde_scipy(grid), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb11-17">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'scipy (Scott, h=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h_scott<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb11-18">plt.plot(grid, dens_sk, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb11-19">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'sklearn (Scott, h=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h_sk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb11-20">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desviación (horas)'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'densidad'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()</span>
<span id="cb11-21">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'El mismo nombre Scott, dos anchos distintos'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>scipy.gaussian_kde elige el ancho de banda solo (regla de Scott).
  h de scipy:                  0.660
  h de sklearn con "scott":    0.278
  desviación estándar datos:   2.373</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-9-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-6" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-6">Cómo leer este resultado</h3>
<p>En el gráfico se ven las dos curvas con el mismo nombre «Scott». La roja (<code>scipy</code>, h = <strong>0.660</strong>) es más ancha y aplana los dos grupos; la azul (<code>sklearn</code>, h = <strong>0.278</strong>) se pega más a los datos y deja las dos modas más marcadas. No es que una librería «haga mejor Scott»: <code>sklearn</code> solo aplica el factor <img src="https://latex.codecogs.com/png.latex?n%5E%7B-1/5%7D"> y <strong>no lo multiplica por la dispersión</strong> (desviación estándar de 2.373). <img src="https://latex.codecogs.com/png.latex?0.278%20%5Ctimes%202.373%20%5Capprox%200.660">: el de scipy es el de sklearn por la escala de los datos. Solo equivalen si antes estandarizas la variable.</p>
<p>Fíjate en lo que <strong>no</strong> tuviste que decidir: el ancho de banda. <code>scipy.gaussian_kde</code> aplicó la regla de Scott que acabas de ver. Ese 0.660 es más ancho que el 0.3 que usamos a mano. Es esperable: estas reglas son de <em>referencia normal</em>, una aproximación asintótica basada en una forma gaussiana, no un óptimo garantizado para esta muestra. Con <strong>dos grupos</strong>, esa suposición falla y tienden a suavizar de más.</p>
<p>Por eso, con <code>sklearn</code>, lo habitual es fijar <code>bandwidth=...</code> explícitamente y elegirlo por validación, como haremos enseguida.</p>
</section>
</section>
<section id="el-ancho-de-banda-y-el-compromiso-sesgo-varianza" class="level2">
<h2 class="anchored" data-anchor-id="el-ancho-de-banda-y-el-compromiso-sesgo-varianza">El ancho de banda y el compromiso sesgo-varianza</h2>
<p>El KDE tiene un único parámetro crítico: el ancho de banda <img src="https://latex.codecogs.com/png.latex?h">. Aquí el compromiso sesgo-varianza toma forma concreta:</p>
<ul>
<li>Con <img src="https://latex.codecogs.com/png.latex?h"> <strong>pequeño</strong>, cada campana es estrecha; la estimación se pega a cada dato y <strong>fluctúa mucho de una muestra a otra</strong> (varianza alta, sesgo bajo).</li>
<li>Con <img src="https://latex.codecogs.com/png.latex?h"> <strong>grande</strong>, las campanas son anchas; la estimación es estable pero <strong>aplana los detalles reales</strong> (sesgo alto, varianza baja).</li>
</ul>
<p>El error total se mide con el MISE (<em>mean integrated squared error</em>), <img src="https://latex.codecogs.com/png.latex?%5Ctext%7BMISE%7D(h)%20=%20E%5Cint%20(%5Chat%20f(x)%20-%20f(x))%5E2%5C,dx">. En una dimensión, para una densidad suficientemente suave y un kernel simétrico de segundo orden, con <img src="https://latex.codecogs.com/png.latex?h%20%5Cto%200"> y <img src="https://latex.codecogs.com/png.latex?nh%20%5Cto%20%5Cinfty">, su aproximación asintótica es</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Ctext%7BAMISE%7D(h)%20%5Capprox%20%5Cunderbrace%7B%5Cfrac%7BR(K)%7D%7Bn%5C,h%7D%7D_%7B%5Ctext%7Bvarianza%7D%7D%20+%20%5Cunderbrace%7B%5Cfrac%7Bh%5E4%7D%7B4%7D%5C,%5Cmu_2(K)%5E2%5C,R(f'')%7D_%7B%5Ctext%7Bsesgo%7D%5E2%7D,"></p>
<p>donde <img src="https://latex.codecogs.com/png.latex?R(g)%20=%20%5Cint%20g%5E2"> y <img src="https://latex.codecogs.com/png.latex?%5Cmu_2(K)%20=%20%5Cint%20u%5E2%20K(u)%5C,du">. El primer término baja cuando <img src="https://latex.codecogs.com/png.latex?h"> crece; el segundo sube. El mínimo está en un punto intermedio, <img src="https://latex.codecogs.com/png.latex?h%5E%5Cast%20%5Cpropto%20n%5E%7B-1/5%7D">, y de ahí sale el factor <img src="https://latex.codecogs.com/png.latex?n%5E%7B-1/5%7D"> de la regla de Scott. Veámoslo con tres anchos.</p>
<div id="9b11b35a" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:04.285776Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:04.285587Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:04.603702Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:04.602834Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">anchos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>]</span>
<span id="cb13-2">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb13-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> a, hb <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(ax, anchos):</span>
<span id="cb13-4">    kde_h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KernelDensity(kernel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gaussian'</span>, bandwidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>hb).fit(datos.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb13-5">    dens <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(kde_h.score_samples(grid.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)))</span>
<span id="cb13-6">    a.hist(datos, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>, density<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lightsteelblue'</span>, edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'white'</span>)</span>
<span id="cb13-7">    a.plot(grid, dens, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb13-8">    a.set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'h = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>hb<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> a.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desviación (horas)'</span>)</span>
<span id="cb13-9">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'densidad'</span>)</span>
<span id="cb13-10">plt.tight_layout()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-10-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-7" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-7">Cómo leer este resultado</h3>
<ul>
<li><strong>h = 0.1 (demasiado pequeño):</strong> curva ruidosa, con picos artificiales. Sobreajusta el ruido: varianza alta.</li>
<li><strong>h = 0.3 (equilibrado):</strong> las dos modas se ven limpias, sin ruido espurio visible.</li>
<li><strong>h = 2.0 (demasiado grande):</strong> las campanas anchas funden los dos grupos en una sola curva ancha, casi plana. Suaviza de más y borra la estructura: sesgo alto.</li>
</ul>
<p>El principio es el mismo que con los knots del spline; solo cambia el parámetro que lo controla.</p>
</section>
</section>
<section id="elegir-el-ancho-de-banda-por-validación-densidad" class="level2">
<h2 class="anchored" data-anchor-id="elegir-el-ancho-de-banda-por-validación-densidad">Elegir el ancho de banda por validación (densidad)</h2>
<p>No queremos elegir <img src="https://latex.codecogs.com/png.latex?h"> a simple vista. Como el KDE es una densidad, podemos medir qué tan bien predice datos nuevos mediante la <strong>log-verosimilitud</strong> en validación cruzada: buscamos el <img src="https://latex.codecogs.com/png.latex?h"> que hace más probables los datos que el modelo no vio. <code>GridSearchCV</code> lo automatiza.</p>
<p>La <strong>verosimilitud</strong> es «qué tan creíbles se ven estos puntos si esta curva fuera la densidad verdadera»: se evalúa <img src="https://latex.codecogs.com/png.latex?%5Chat%20f"> en cada dato y se multiplican esos valores. Como el producto de muchos números pequeños se va a cero, se toma el <strong>logaritmo</strong> y se suman: esa es la <strong>log-verosimilitud</strong>. Más alta = la curva coloca más densidad donde sí cayeron entregas nuevas. Más baja = las puso en el lugar equivocado. En validación cruzada se calcula con puntos que no se usaron para armar el KDE, para no premiar a un <img src="https://latex.codecogs.com/png.latex?h"> que solo memoriza la muestra.</p>
<div id="847fa0ba" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:04.605802Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:04.605624Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:05.198611Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:05.197842Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">params <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'bandwidth'</span>: np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>)}</span>
<span id="cb14-2">busqueda <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> GridSearchCV(KernelDensity(kernel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gaussian'</span>), params, cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb14-3">busqueda.fit(datos.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb14-4">h_dens <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> busqueda.best_params_[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'bandwidth'</span>]</span>
<span id="cb14-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Ancho de banda óptimo por validación: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h_dens<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Ancho de banda óptimo por validación: 0.295</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-8" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-8">Cómo leer este resultado</h3>
<p>La validación elige un ancho de banda de <strong>0.295</strong>, muy cerca del panel central (h = 0.3) que a simple vista se veía equilibrado, y menos de la mitad del 0.660 que proponía la regla de Scott. En este ejemplo, el criterio de validación favorece menos suavizado que la regla de Scott; no demuestra que ocurra así en toda distribución bimodal. Que el método basado en datos coincida con el juicio visual da confianza; además, a diferencia de la inspección visual, este procedimiento sigue un criterio explícito y reproducible. Ese es el <img src="https://latex.codecogs.com/png.latex?h"> que usarías.</p>
</section>
</section>
<section id="parte-b-regresión-por-kernel" class="level2">
<h2 class="anchored" data-anchor-id="parte-b-regresión-por-kernel">Parte B — Regresión por kernel</h2>
<p>La misma idea de “mirar lo cercano” sirve para regresión. En vez de estimar una densidad, queremos estimar la función de regresión <img src="https://latex.codecogs.com/png.latex?m(x)%20=%20E%5BY%20%5Cmid%20X%20=%20x%5D">, es decir, el valor esperado de <img src="https://latex.codecogs.com/png.latex?y"> para cada <img src="https://latex.codecogs.com/png.latex?x">. Lo haremos promediando los <img src="https://latex.codecogs.com/png.latex?y"> de los puntos vecinos, con más peso para los más próximos.</p>
</section>
<section id="la-intuición-los-pesos-en-un-punto" class="level2">
<h2 class="anchored" data-anchor-id="la-intuición-los-pesos-en-un-punto">La intuición: los pesos en un punto</h2>
<p>Antes de la fórmula, veamos qué significa “promediar lo cercano”. Fijemos un punto <img src="https://latex.codecogs.com/png.latex?x_0"> y miremos cuánto pesa cada dato según su distancia, usando el kernel gaussiano. Los cercanos deben pesar mucho; los lejanos, casi nada.</p>
<div id="3d2fc8e0" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:05.201000Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:05.200801Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:05.513498Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:05.512753Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb16-2">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span></span>
<span id="cb16-3">x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sort(rng.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, n))</span>
<span id="cb16-4">m_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sin(x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x</span>
<span id="cb16-5">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> m_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, n)</span>
<span id="cb16-6"></span>
<span id="cb16-7">x0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.0</span></span>
<span id="cb16-8">h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span></span>
<span id="cb16-9">pesos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> ((x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> x0) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> h) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb16-10"></span>
<span id="cb16-11">plt.scatter(x, y, c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>pesos, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Reds'</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>)</span>
<span id="cb16-12">plt.axvline(x0, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'black'</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">rf'</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">x_0</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>x0<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb16-13">plt.colorbar(label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'peso del kernel'</span>)</span>
<span id="cb16-14">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()</span>
<span id="cb16-15">plt.title(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r'Peso de cada dato al predecir en </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">x_0</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> = 5'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-12-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-9" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-9">Cómo leer este resultado</h3>
<p>El color muestra el peso: los puntos junto a la línea <img src="https://latex.codecogs.com/png.latex?x_0=5"> están en rojo intenso (pesan mucho), y el peso se desvanece rápido al alejarse. La predicción en <img src="https://latex.codecogs.com/png.latex?x_0"> será un <strong>promedio de los <img src="https://latex.codecogs.com/png.latex?y"></strong>, pero uno donde dominan los vecinos inmediatos. Cambiar <img src="https://latex.codecogs.com/png.latex?x_0"> mueve la ventana; recorrer todos los <img src="https://latex.codecogs.com/png.latex?x_0"> traza la curva suavizada.</p>
</section>
</section>
<section id="el-estimador-de-nadarayawatson" class="level2">
<h2 class="anchored" data-anchor-id="el-estimador-de-nadarayawatson">El estimador de Nadaraya–Watson</h2>
<p>Esa idea tiene fórmula: la predicción en <img src="https://latex.codecogs.com/png.latex?x"> es el promedio de los <img src="https://latex.codecogs.com/png.latex?y_i"> ponderado por el kernel según la distancia a <img src="https://latex.codecogs.com/png.latex?x">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%7Bm%7D(x)%20=%20%5Cfrac%7B%5Csum_%7Bi=1%7D%5E%7Bn%7D%20K%5C!%5Cleft(%5Cfrac%7Bx%20-%20x_i%7D%7Bh%7D%5Cright)%20y_i%7D%7B%5Csum_%7Bi=1%7D%5E%7Bn%7D%20K%5C!%5Cleft(%5Cfrac%7Bx%20-%20x_i%7D%7Bh%7D%5Cright)%7D"></p>
<p>El numerador suma los <img src="https://latex.codecogs.com/png.latex?y"> pesados; el denominador normaliza. No hay knots ni coeficientes: solo el ancho de banda <img src="https://latex.codecogs.com/png.latex?h">. Lo implementamos a mano.</p>
<div id="b92ec3d4" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:05.515729Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:05.515538Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:05.606702Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:05.605963Z&quot;}}" data-execution_count="13">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> _entradas_kernel(x_train, y_train, x_query, h):</span>
<span id="cb17-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Validar datos unidimensionales y un ancho de banda positivo."""</span></span>
<span id="cb17-3">    x_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(x_train, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb17-4">    y_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(y_train, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb17-5">    x_query <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.atleast_1d(np.asarray(x_query, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>))</span>
<span id="cb17-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> x_train.ndim <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> y_train.ndim <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> x_query.ndim <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:</span>
<span id="cb17-7">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">raise</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">ValueError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Usa vectores unidimensionales; x_query también puede ser escalar."</span>)</span>
<span id="cb17-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> x_train.size <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> x_train.size <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> y_train.size:</span>
<span id="cb17-9">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">raise</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">ValueError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x_train e y_train deben tener la misma longitud no nula."</span>)</span>
<span id="cb17-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">all</span>(np.isfinite(v).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">all</span>() <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> v <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> (x_train, y_train, x_query)):</span>
<span id="cb17-11">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">raise</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">ValueError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Los datos y las consultas deben ser finitos."</span>)</span>
<span id="cb17-12">    h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(h, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb17-13">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> h.ndim <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> np.isfinite(h) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb17-14">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">raise</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">ValueError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"h debe ser un escalar finito y positivo."</span>)</span>
<span id="cb17-15">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> x_train, y_train, x_query, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(h)</span>
<span id="cb17-16"></span>
<span id="cb17-17"></span>
<span id="cb17-18"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> _pesos_gaussianos(x_train, xq, h):</span>
<span id="cb17-19">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Restar el mayor log-peso evita que todos los pesos se redondeen a cero.</span></span>
<span id="cb17-20">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># El factor común se cancela al normalizar y no cambia el estimador.</span></span>
<span id="cb17-21">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">with</span> np.errstate(over<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ignore"</span>, invalid<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ignore"</span>):</span>
<span id="cb17-22">        log_w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> ((x_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> xq) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> h) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb17-23">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> np.isfinite(log_w).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">any</span>():</span>
<span id="cb17-24">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">raise</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">ValueError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La escala de distancias es extrema: reescala X o revisa h."</span>)</span>
<span id="cb17-25">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.exp(log_w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(log_w))</span>
<span id="cb17-26"></span>
<span id="cb17-27"></span>
<span id="cb17-28"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> nadaraya_watson(x_train, y_train, x_query, h):</span>
<span id="cb17-29">    x_train, y_train, x_query, h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> _entradas_kernel(x_train, y_train, x_query, h)</span>
<span id="cb17-30">    pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.empty(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(x_query))</span>
<span id="cb17-31">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, xq <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(x_query):</span>
<span id="cb17-32">        w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> _pesos_gaussianos(x_train, xq, h)</span>
<span id="cb17-33">        pred[i] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>((w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> w.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> y_train)</span>
<span id="cb17-34">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> pred</span>
<span id="cb17-35"></span>
<span id="cb17-36">grid_x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>)</span>
<span id="cb17-37">ajuste <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nadaraya_watson(x, y, grid_x, h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)</span>
<span id="cb17-38"></span>
<span id="cb17-39">plt.scatter(x, y, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'datos'</span>)</span>
<span id="cb17-40">plt.plot(grid_x, np.sin(grid_x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> grid_x, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k--'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'relación real'</span>)</span>
<span id="cb17-41">plt.plot(grid_x, ajuste, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'kernel (h=0.5)'</span>)</span>
<span id="cb17-42">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()</span>
<span id="cb17-43">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Regresión por kernel (Nadaraya–Watson)'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-13-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-10" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-10">Cómo leer este resultado</h3>
<p>La curva roja sigue de cerca la relación real, <img src="https://latex.codecogs.com/png.latex?m(x)%20=%20%5Csin(x)%20+%200.3x"> (línea negra), sin que le dijéramos que era un seno ni le ajustáramos un polinomio: solo promedió los <img src="https://latex.codecogs.com/png.latex?y"> vecinos en cada punto. Eso es lo notable del suavizado por kernel: <strong>se adapta sin fijar una familia paramétrica global para la relación</strong>. El kernel y el ancho de banda sí introducen supuestos sobre la proximidad y la suavidad.</p>
<p>La implementación valida las entradas y estabiliza los pesos gaussianos para evitar divisiones 0/0 por redondeo numérico. Obtener una predicción finita lejos de los datos no vuelve confiable la extrapolación.</p>
</section>
</section>
<section id="el-ancho-de-banda-controla-la-flexibilidad" class="level2">
<h2 class="anchored" data-anchor-id="el-ancho-de-banda-controla-la-flexibilidad">El ancho de banda controla la flexibilidad</h2>
<p>Igual que en densidades, <img src="https://latex.codecogs.com/png.latex?h"> decide cuánto suaviza. Cumple el papel que tenía el número de knots en el spline, pero <strong>en sentido inverso</strong>: más knots dan una curva más flexible; un <img src="https://latex.codecogs.com/png.latex?h"> más grande da una curva <strong>más rígida</strong>.</p>
<div id="05ad800f" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:05.609314Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:05.609109Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:05.707768Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:05.707046Z&quot;}}" data-execution_count="14">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">anchos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>]</span>
<span id="cb18-2">plt.scatter(x, y, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'datos'</span>)</span>
<span id="cb18-3">plt.plot(grid_x, np.sin(grid_x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> grid_x, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k--'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'relación real'</span>)</span>
<span id="cb18-4">colores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'darkorange'</span>]</span>
<span id="cb18-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> hb, c <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(anchos, colores):</span>
<span id="cb18-6">    plt.plot(grid_x, nadaraya_watson(x, y, grid_x, hb), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>c, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'h=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>hb<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb18-7">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()</span>
<span id="cb18-8">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Efecto del ancho de banda'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-14-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="antes-de-seguir-pregúntate-1" class="level3">
<h3 class="anchored" data-anchor-id="antes-de-seguir-pregúntate-1">Antes de seguir, pregúntate</h3>
<p>¿Cuál de las tres curvas sigue el ruido punto por punto y cuál aplana las ondulaciones reales? ¿Con cuál te quedarías?</p>
</section>
<section id="cómo-leer-este-resultado-11" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-11">Cómo leer este resultado</h3>
<ul>
<li><strong>h = 0.1 (verde):</strong> zigzaguea persiguiendo el ruido de cada dato. Sobreajuste.</li>
<li><strong>h = 0.5 (rojo):</strong> sigue las ondulaciones reales sin copiar el ruido. Equilibrio.</li>
<li><strong>h = 2.5 (naranja):</strong> aplana las ondas y casi vuelve a una recta. Subajuste.</li>
</ul>
<p>Mismo compromiso: <img src="https://latex.codecogs.com/png.latex?h"> pequeño = varianza alta; <img src="https://latex.codecogs.com/png.latex?h"> grande = sesgo alto.</p>
</section>
</section>
<section id="el-sesgo-de-frontera-boundary-bias" class="level2">
<h2 class="anchored" data-anchor-id="el-sesgo-de-frontera-boundary-bias">El sesgo de frontera (boundary bias)</h2>
<p>Nadaraya–Watson tiene una debilidad conocida en los <strong>extremos del rango</strong>. En el interior, cada punto tiene vecinos a ambos lados y el promedio queda centrado. Pero en la frontera (el primer y el último tramo de <img src="https://latex.codecogs.com/png.latex?x">) solo hay vecinos de <strong>un lado</strong>. Si la relación tiene pendiente, esos vecinos están todos más arriba (o más abajo) y el promedio se sesga hacia el interior: la curva se “dobla”.</p>
<p>La solución clásica es cambiar el promedio local por una <strong>recta local</strong>. Nadaraya–Watson es una regresión polinómica local de <strong>grado 0</strong>: en cada punto ajusta una constante (el promedio ponderado). La <strong>regresión lineal local</strong> es de <strong>grado 1</strong>: en cada punto ajusta una recta por mínimos cuadrados ponderados con el mismo kernel, y usa su valor en ese punto como predicción.</p>
<p>Para que la comparación sea justa, usemos una relación lineal, <img src="https://latex.codecogs.com/png.latex?y%20=%200.5x"> más ruido, y el <strong>mismo kernel gaussiano con el mismo <img src="https://latex.codecogs.com/png.latex?h%20=%201"></strong> en ambos métodos.</p>
<div id="0aecd264" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:05.709847Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:05.709660Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:05.822347Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:05.821582Z&quot;}}" data-execution_count="15">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> lineal_local(x_train, y_train, x_query, h):</span>
<span id="cb19-2">    x_train, y_train, x_query, h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> _entradas_kernel(x_train, y_train, x_query, h)</span>
<span id="cb19-3">    pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.empty(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(x_query))</span>
<span id="cb19-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, xq <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(x_query):</span>
<span id="cb19-5">        w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> _pesos_gaussianos(x_train, xq, h)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># mismo kernel gaussiano estabilizado</span></span>
<span id="cb19-6">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># recta ponderada centrada en xq: el intercepto es la predicción en xq</span></span>
<span id="cb19-7">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> np.unique(x_train[w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]).size <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>:</span>
<span id="cb19-8">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">raise</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">ValueError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La recta local necesita dos valores distintos de X con peso positivo."</span>)</span>
<span id="cb19-9">        pendiente, intercepto <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.polyfit(x_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> xq, y_train, deg<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, w<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>np.sqrt(w))</span>
<span id="cb19-10">        pred[i] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> intercepto</span>
<span id="cb19-11">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> pred</span>
<span id="cb19-12"></span>
<span id="cb19-13">rng2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb19-14">xb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sort(rng2.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>))</span>
<span id="cb19-15">mb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xb</span>
<span id="cb19-16">yb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng2.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>)</span>
<span id="cb19-17"></span>
<span id="cb19-18">gx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>)</span>
<span id="cb19-19">fit_nw <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nadaraya_watson(xb, yb, gx, h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>)</span>
<span id="cb19-20">fit_ll <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lineal_local(xb, yb, gx, h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>)</span>
<span id="cb19-21"></span>
<span id="cb19-22">plt.scatter(xb, yb, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'datos'</span>)</span>
<span id="cb19-23">plt.plot(gx, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> gx, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k--'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'relación real (recta)'</span>)</span>
<span id="cb19-24">plt.plot(gx, fit_nw, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb19-25">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Nadaraya–Watson (grado 0)'</span>)</span>
<span id="cb19-26">plt.plot(gx, fit_ll, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb19-27">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lineal local (grado 1)'</span>)</span>
<span id="cb19-28">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()</span>
<span id="cb19-29">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Sesgo de frontera: promedio local vs recta local (mismo h)'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-15-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-12" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-12">Cómo leer este resultado</h3>
<p>Fíjate en los <strong>extremos</strong>. Nadaraya–Watson (rojo) se separa de la recta real cerca de <img src="https://latex.codecogs.com/png.latex?x%5Capprox%200"> y <img src="https://latex.codecogs.com/png.latex?x%5Capprox%2010">: en el borde solo hay vecinos de un lado, el promedio se sesga hacia el interior y la curva se dobla. En el centro la sigue bien.</p>
<p>La lineal local (verde) usa el mismo kernel y el mismo <img src="https://latex.codecogs.com/png.latex?h">; la única diferencia es que ajusta una recta en lugar de una constante. Esa pendiente extra le permite seguir la tendencia hasta el borde. Midamos cuánto mejora.</p>
</section>
<section id="cuánto-se-equivoca-cada-método-en-el-borde" class="level3">
<h3 class="anchored" data-anchor-id="cuánto-se-equivoca-cada-método-en-el-borde">Cuánto se equivoca cada método en el borde</h3>
<p>Como aquí conocemos la relación real, podemos medir el error de cada curva por zonas con la raíz del error cuadrático medio (RMSE, por sus siglas en inglés): los bordes (<img src="https://latex.codecogs.com/png.latex?x%20%3C%201"> o <img src="https://latex.codecogs.com/png.latex?x%20%3E%209">) y el interior. Sumamos un tercer método, <strong>LOWESS</strong> de <code>statsmodels</code>: es una regresión lineal local con tres cambios prácticos (kernel tricúbico, una ventana definida por la fracción <code>frac</code> de vecinos más cercanos en lugar de un <img src="https://latex.codecogs.com/png.latex?h"> fijo, e iteraciones que restan peso a los datos atípicos). Es la implementación de uso cotidiano de la idea de la recta local.</p>
<div id="bc905bb7" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:05.824331Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:05.824151Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:05.832839Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:05.832003Z&quot;}}" data-execution_count="16">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">fit_low <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lowess(yb, xb, frac<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, it<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, return_sorted<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb20-2">fit_low_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.interp(gx, fit_low[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], fit_low[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb20-3"></span>
<span id="cb20-4">borde <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (gx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> (gx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span>
<span id="cb20-5">m_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> gx</span>
<span id="cb20-6">ajustes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Nadaraya–Watson'</span>: fit_nw,</span>
<span id="cb20-7">           <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Lineal local'</span>:    fit_ll,</span>
<span id="cb20-8">           <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LOWESS'</span>:          fit_low_grid}</span>
<span id="cb20-9"></span>
<span id="cb20-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'RMSE frente a la relación real'</span>)</span>
<span id="cb20-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"método"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&lt;17}{</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bordes"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&gt;8}{</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"interior"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&gt;10}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb20-12"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, f <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> ajustes.items():</span>
<span id="cb20-13">    rmse_borde <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sqrt(np.mean((f[borde] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> m_grid[borde]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb20-14">    rmse_int <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sqrt(np.mean((f[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>borde] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> m_grid[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>borde]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb20-15">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&lt;17}{</span>rmse_borde<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&gt;8.3f}{</span>rmse_int<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&gt;10.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>RMSE frente a la relación real
método             bordes  interior
Nadaraya–Watson     0.283     0.091
Lineal local        0.020     0.038
LOWESS              0.058     0.065</code></pre>
</div>
</div>
</section>
<section id="cómo-leer-este-resultado-13" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-13">Cómo leer este resultado</h3>
<p>Los números confirman lo que se ve. En los bordes, Nadaraya–Watson tiene un RMSE de <strong>0.283</strong> frente a <strong>0.091</strong> en el interior: su error se triplica al llegar a los extremos. La lineal local, con el mismo kernel y el mismo <img src="https://latex.codecogs.com/png.latex?h">, baja el error de borde a <strong>0.020</strong>, y LOWESS a <strong>0.058</strong>. Que en esta muestra la lineal local tenga incluso menos error en el borde que en el interior (0.038) es azar de la muestra, no una propiedad general.</p>
<p>Conviene separar <strong>sesgo</strong> y <strong>varianza</strong>. En este ejemplo la relación verdadera es exactamente lineal: si el ajuste está bien definido y el ruido tiene media condicional cero, la recta local reproduce esa tendencia sin sesgo condicional, incluso en el borde. El error observado en una sola muestra no es una medición directa del sesgo. Para una relación curva puede persistir sesgo de aproximación; además, disponer de información solo de un lado suele aumentar la incertidumbre. La recta local mejora el comportamiento en la frontera, pero no garantiza un menor error en toda muestra.</p>
</section>
</section>
<section id="elegir-el-ancho-de-banda-por-validación-regresión" class="level2">
<h2 class="anchored" data-anchor-id="elegir-el-ancho-de-banda-por-validación-regresión">Elegir el ancho de banda por validación (regresión)</h2>
<p>No queremos elegir <img src="https://latex.codecogs.com/png.latex?h"> mirando el conjunto de prueba: dejaría de ser una medida honesta, porque habría participado en la decisión (una fuga de información). Reservamos los datos de prueba y elegimos <img src="https://latex.codecogs.com/png.latex?h"> por <strong>validación cruzada</strong> (CV, por <em>cross-validation</em>) <strong>solo sobre el entrenamiento</strong>: el entrenamiento se divide en 5 partes (<em>folds</em>); cada una se usa por turnos para validar mientras las otras cuatro ajustan el modelo, y se promedia el error cuadrático medio (MSE). El conjunto de prueba solo se usa al final, para reportar.</p>
<div id="b517083b" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:05.834930Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:05.834738Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:06.055378Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:06.054582Z&quot;}}" data-execution_count="17">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> x.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb22-2">Xtr, Xte, ytr, yte, xtr, xte <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(</span>
<span id="cb22-3">    X, y, x, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA</span>
<span id="cb22-4">)</span>
<span id="cb22-5"></span>
<span id="cb22-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># K-Fold SOLO sobre el entrenamiento: el conjunto de prueba no entra a elegir h</span></span>
<span id="cb22-7">kf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KFold(n_splits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA)</span>
<span id="cb22-8">hs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>)</span>
<span id="cb22-9">errores_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb22-10"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> h <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> hs:</span>
<span id="cb22-11">    mse_folds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb22-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> tr, va <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> kf.split(xtr):</span>
<span id="cb22-13">        pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nadaraya_watson(xtr[tr], ytr[tr], xtr[va], h)</span>
<span id="cb22-14">        mse_folds.append(mean_squared_error(ytr[va], pred))</span>
<span id="cb22-15">    errores_cv.append(np.mean(mse_folds))</span>
<span id="cb22-16"></span>
<span id="cb22-17">h_opt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> hs[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmin(errores_cv))]</span>
<span id="cb22-18"></span>
<span id="cb22-19">plt.plot(hs, errores_cv, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb22-20">plt.axvline(h_opt, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>,</span>
<span id="cb22-21">            label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'h óptimo = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb22-22">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ancho de banda h'</span>)</span>
<span id="cb22-23">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MSE de validación (K-Fold)'</span>)</span>
<span id="cb22-24">plt.legend()</span>
<span id="cb22-25">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Selección de h por CV (solo entrenamiento)'</span>)</span>
<span id="cb22-26">plt.show()</span>
<span id="cb22-27"></span>
<span id="cb22-28"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'h óptimo (CV en entrenamiento): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | MSE de validación: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(errores_cv)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-17-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>h óptimo (CV en entrenamiento): 0.30 | MSE de validación: 0.254</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-14" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-14">Cómo leer este resultado</h3>
<p>Esta curva muestra el MSE de <strong>validación cruzada</strong> (promedio de 5 folds sobre el entrenamiento), no el error de prueba. El mínimo entre los candidatos está en <strong>h = 0.30</strong>, con un MSE de <strong>0.254</strong>.</p>
<p>La varianza del ruido es <img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2%20=%200.5%5E2%20=%200.25">. Bajo este modelo generador y pérdida cuadrática, es el error irreducible <strong>en esperanza</strong> al predecir una nueva respuesta. No es una cota para cada MSE observado: por azar, una muestra puede producir un valor menor que 0.25, incluso al usar la función verdadera. La descomposición en ruido, sesgo al cuadrado y varianza describe promedios sobre nuevas observaciones y muestras de entrenamiento.</p>
<p>El valor 0.254 está cerca de esa referencia, pero no permite afirmar por sí solo que recuperamos casi toda la señal. Es el mínimo elegido entre varios candidatos y puede ser optimista por la propia selección; tampoco hemos cuantificado su incertidumbre. El conjunto de prueba reservado aporta la evaluación posterior.</p>
<p>A simple vista, <img src="https://latex.codecogs.com/png.latex?h%20=%200.5"> parecía razonable. La CV favorece <strong>0.30</strong> dentro del rango explorado. El conjunto de prueba se usará para comparar recta, spline y kernel, sin volver a ajustar los parámetros a partir de ese resultado.</p>
</section>
</section>
<section id="comparación-recta-spline-y-kernel" class="level2">
<h2 class="anchored" data-anchor-id="comparación-recta-spline-y-kernel">Comparación: recta, spline y kernel</h2>
<p>Cerremos poniendo a competir los tres enfoques sobre los mismos datos de prueba, que <strong>no se usaron para elegir nada</strong>. El spline elige su número de knots por el mismo K-Fold sobre el entrenamiento; el kernel ya trajo su <img src="https://latex.codecogs.com/png.latex?h">. Primero la gráfica; después el <img src="https://latex.codecogs.com/png.latex?R%5E2"> en prueba.</p>
<div id="adcbc236" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-27T20:38:06.057773Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-27T20:38:06.057584Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-27T20:38:06.255100Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-27T20:38:06.254453Z&quot;}}" data-execution_count="18">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1">candidatos_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>))</span>
<span id="cb24-2">errores_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb24-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> candidatos_k:</span>
<span id="cb24-4">    mse_folds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb24-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> tr, va <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> kf.split(Xtr):</span>
<span id="cb24-6">        modelo_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_pipeline(</span>
<span id="cb24-7">            SplineTransformer(n_knots<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k, degree<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, include_bias<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>),</span>
<span id="cb24-8">            LinearRegression(),</span>
<span id="cb24-9">        ).fit(Xtr[tr], ytr[tr])</span>
<span id="cb24-10">        mse_folds.append(mean_squared_error(ytr[va], modelo_k.predict(Xtr[va])))</span>
<span id="cb24-11">    errores_k.append(np.mean(mse_folds))</span>
<span id="cb24-12">k_opt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> candidatos_k[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmin(errores_k))]</span>
<span id="cb24-13"></span>
<span id="cb24-14">recta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression().fit(Xtr, ytr)</span>
<span id="cb24-15">spline <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_pipeline(</span>
<span id="cb24-16">    SplineTransformer(n_knots<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k_opt, degree<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, include_bias<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>),</span>
<span id="cb24-17">    LinearRegression(),</span>
<span id="cb24-18">).fit(Xtr, ytr)</span>
<span id="cb24-19"></span>
<span id="cb24-20">r2_lineal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> r2_score(yte, recta.predict(Xte))</span>
<span id="cb24-21">r2_spline <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> r2_score(yte, spline.predict(Xte))</span>
<span id="cb24-22">r2_kernel <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> r2_score(yte, nadaraya_watson(xtr, ytr, xte, h_opt))</span>
<span id="cb24-23"></span>
<span id="cb24-24">plt.scatter(xte, yte, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'datos de prueba'</span>)</span>
<span id="cb24-25">plt.plot(grid_x, recta.predict(grid_x.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb24-26">         color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'recta'</span>)</span>
<span id="cb24-27">plt.plot(grid_x, spline.predict(grid_x.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb24-28">         color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'spline (k=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb24-29">plt.plot(grid_x, nadaraya_watson(xtr, ytr, grid_x, h_opt),</span>
<span id="cb24-30">         color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'kernel (h=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb24-31">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()</span>
<span id="cb24-32">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Tres formas de ajustar la misma relación'</span>)</span>
<span id="cb24-33">plt.show()</span>
<span id="cb24-34"></span>
<span id="cb24-35"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'n_knots óptimo (CV en entrenamiento): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb24-36"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'R2 en prueba (no usado para elegir h ni knots)'</span>)</span>
<span id="cb24-37"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  Recta (lineal):     </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_lineal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb24-38"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  Spline cúbico:      </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_spline<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb24-39"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  Kernel (NW, h opt): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_kernel<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/index_files/figure-html/cell-18-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>n_knots óptimo (CV en entrenamiento): 11
R2 en prueba (no usado para elegir h ni knots)
  Recta (lineal):     0.474
  Spline cúbico:      0.783
  Kernel (NW, h opt): 0.780</code></pre>
</div>
</div>
<section id="cómo-leer-esta-comparación" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-comparación">Cómo leer esta comparación</h3>
<p>En el gráfico se ve de un vistazo lo que los números confirman. La <strong>recta gris</strong> atraviesa las ondas y se queda a media altura. El <strong>spline verde</strong> y el <strong>kernel rojo</strong> casi se superponen: ambos recuperan las ondulaciones sin copiar el ruido punto a punto.</p>
<ul>
<li><strong>Recta: 0.474.</strong> Deja más de la mitad de la variabilidad sin explicar.</li>
<li><strong>Spline: 0.783</strong> (con <strong>11 knots</strong> elegidos por K-Fold en el entrenamiento) y <strong>Kernel: 0.780</strong> (con <strong>h = 0.30</strong>, también por CV en el entrenamiento). Suben el <img src="https://latex.codecogs.com/png.latex?R%5E2"> de 0.47 a cerca de 0.78: pasan de explicar menos de la mitad de la variabilidad a explicar casi cuatro quintas partes.</li>
</ul>
<p>Importa el protocolo: <img src="https://latex.codecogs.com/png.latex?h"> y el número de knots se eligieron <strong>sin mirar el conjunto de prueba</strong>, así que el <img src="https://latex.codecogs.com/png.latex?R%5E2"> de prueba es una medida honesta. Pero es una medida con ruido: la prueba tiene solo 60 puntos, y una diferencia de 0.003 entre spline y kernel no permite declarar un ganador. La conclusión es que <strong>en esta partición muestran desempeños muy similares</strong>: no hay evidencia suficiente aquí para establecer una superioridad clara, pero tampoco se ha demostrado equivalencia estadística.</p>
<p>Que lleguen tan cerca no es casualidad: son <strong>dos caminos hacia el mismo objetivo</strong>, capturar una relación no lineal sin imponer de antemano una forma funcional. El spline usa una base de funciones y knots: una vez ajustado es un modelo lineal en esa base, predecir es barato y se integra de forma natural en modelos más grandes (como los GAM). El kernel promedia localmente: es más simple de entender y no exige decidir una estructura, pero necesita todos los datos de entrenamiento para cada predicción y sufre sesgo de frontera (la recta local lo reduce). Ninguno de los dos extrapola bien fuera del rango de los datos: fíjate en el tramo final del spline verde, a partir de <img src="https://latex.codecogs.com/png.latex?x%20%5Capprox%209.8"> (el último dato de entrenamiento), donde se vuelve plano porque <code>SplineTransformer</code> extrapola como una constante.</p>
</section>
</section>
<section id="errores-comunes-al-trabajar-con-kernels" class="level2">
<h2 class="anchored" data-anchor-id="errores-comunes-al-trabajar-con-kernels">Errores comunes al trabajar con kernels</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Síntoma</th>
<th>Causa probable</th>
<th>Solución</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>La densidad se ve llena de picos</td>
<td>ancho de banda demasiado pequeño</td>
<td>súbelo; elígelo por validación</td>
</tr>
<tr class="even">
<td>Se pierde una moda o la asimetría</td>
<td>ancho de banda demasiado grande</td>
<td>bájalo; desconfía de las reglas automáticas con datos multimodales</td>
</tr>
<tr class="odd">
<td>La curva se dobla en los extremos</td>
<td>sesgo de frontera</td>
<td>usa regresión lineal local (LOWESS); interpreta los bordes con cautela</td>
</tr>
<tr class="even">
<td>La curva se vuelve errática o queda indefinida donde hay pocos datos</td>
<td>ventana sin vecinos suficientes; con soporte finito puede aparecer 0/0 y con un gaussiano los pesos pueden redondearse a cero</td>
<td>limita el rango de predicción; estabiliza los pesos gaussianos y revisa <img src="https://latex.codecogs.com/png.latex?h"> mediante validación</td>
</tr>
<tr class="odd">
<td>Resultados raros con varias variables en escalas distintas</td>
<td>el kernel usa distancias</td>
<td>estandariza las variables antes</td>
</tr>
<tr class="even">
<td><code>bandwidth='scott'</code> en sklearn da un <img src="https://latex.codecogs.com/png.latex?h"> muy distinto al de scipy</td>
<td>sklearn no reescala por la dispersión</td>
<td>estandariza antes o fija <code>bandwidth</code> y valídalo</td>
</tr>
<tr class="odd">
<td>Muy lento con muchos datos</td>
<td>el promedio recorre todos los puntos</td>
<td>usa implementaciones optimizadas (árboles, FFT)</td>
</tr>
</tbody>
</table>
</section>
<section id="lo-que-debes-llevarte-de-este-artículo" class="level2">
<h2 class="anchored" data-anchor-id="lo-que-debes-llevarte-de-este-artículo">Lo que debes llevarte de este artículo</h2>
<ul>
<li>Los <strong>kernels de suavización usados aquí</strong> son funciones de ponderación no negativas, normalizadas y simétricas que favorecen la proximidad; hay varios (gaussiano, Epanechnikov, uniforme) y la elección importa poco frente al ancho de banda.</li>
<li>El <strong>KDE</strong> estima una densidad sumando una campana por dato; el estimador de <strong>Nadaraya–Watson</strong> estima una regresión promediando los <img src="https://latex.codecogs.com/png.latex?y"> vecinos.</li>
<li>El <strong>ancho de banda <img src="https://latex.codecogs.com/png.latex?h"></strong> es el parámetro que controla el compromiso sesgo-varianza y se elige por <strong>validación</strong>, igual que el número de knots del spline (pero en sentido inverso: más <img src="https://latex.codecogs.com/png.latex?h">, menos flexibilidad).</li>
<li>El promedio local sufre <strong>sesgo de frontera</strong>; la recta local (lineal local, LOWESS) lo reduce. Interpreta los extremos con cautela.</li>
<li>Spline y regresión por kernel abordan la estimación de una relación no lineal por caminos distintos. En este ejemplo rinden de forma similar; en otros datos el resultado debe comprobarse mediante evaluación.</li>
</ul>
</section>
<section id="qué-sigue" class="level2">
<h2 class="anchored" data-anchor-id="qué-sigue">¿Qué sigue?</h2>
<p>Con esto cierras el tema de <strong>suavización</strong>: splines y kernels, dos formas de modelar relaciones no lineales sin imponer de antemano una forma funcional. La pregunta del próximo tema abre un frente nuevo:</p>
<blockquote class="blockquote">
<p>¿Y si la variable que quieres predecir no es un número continuo, sino una categoría (sí/no) o un conteo?</p>
</blockquote>
<p>Ahí entran los <strong>modelos lineales generalizados (GLM)</strong> —regresión logística, Poisson— y su extensión, los <strong>modelos aditivos (GAM)</strong>, que combinan el GLM con suavizadores como los splines que ya conoces (y, en su versión clásica, también con suavizadores locales como los de este artículo). Todo lo que aprendiste sobre suavización reaparece ahí.</p>
</section>
<section id="referencias-para-profundizar" class="level2">
<h2 class="anchored" data-anchor-id="referencias-para-profundizar">Referencias para profundizar</h2>
<ul>
<li><a href="https://nchenderson.github.io/elements-nonpar-stat/kernel-regression-and-local-regression.html">Henderson, <em>Elements of Nonparametric Statistics</em>, capítulo 12</a>: regresión por kernel y regresión local.</li>
<li><a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.gaussian_kde.html">SciPy: gaussian_kde</a>: reglas de ancho de banda, limitaciones y bibliografía de estimación de densidades.</li>
<li><a href="https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KernelDensity.html">scikit-learn: KernelDensity</a>: ancho de banda y evaluación por log-verosimilitud.</li>
<li><a href="https://www.statsmodels.org/stable/generated/statsmodels.nonparametric.smoothers_lowess.lowess.html">statsmodels: LOWESS</a>: ventana de vecinos, kernel tricúbico e iteraciones robustas.</li>
<li><a href="https://numpy.org/doc/stable/reference/generated/numpy.polyfit.html">NumPy: polyfit</a>: convención de pesos usada para mínimos cuadrados ponderados.</li>
</ul>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>suavizacion</category>
  <category>kernel</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/avanzado/07-metodos-kernel/</guid>
  <pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Análisis Avanzado de Datos — Caso aplicado: mapas de entrega con kernels</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/avanzado/07a-caso-entregas-kernel/</link>
  <description><![CDATA[ 




<section id="análisis-avanzado-de-datos-caso-aplicado-mapas-de-entrega-con-kernels" class="level1">
<h1>Análisis Avanzado de Datos — Caso aplicado: mapas de entrega con kernels</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado convierte datos en decisiones. Científico de Datos, Arquitecto de IA y asesor tecnológico con más de 20 años de experiencia en analítica avanzada, machine learning, Big Data e IoT. Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), asesora a entidades gubernamentales y empresas privadas en Colombia y es referente en analítica y normatividad para los sectores postal y logístico del país. Una serie pensada para ir de la teoría a la práctica, con ejemplos concretos en cada paso.</p>
<p>📌 <em>Parte de la serie <strong>Análisis Avanzado de Datos</strong>.</em></p>
</section>
<section id="el-problema-no-todos-los-barrios-entregan-igual" class="level2">
<h2 class="anchored" data-anchor-id="el-problema-no-todos-los-barrios-entregan-igual">El problema: no todos los barrios entregan igual</h2>
<p>Una empresa de mensajería tiene miles de entregas registradas, cada una con su <strong>ubicación</strong> (latitud, longitud) y el <strong>tiempo</strong> que tardó. La pregunta operativa es sencilla y valiosa: <em>dada una dirección cualquiera de la ciudad, ¿cuánto tardará una entrega ahí?</em> La respuesta es un <strong>mapa de calor</strong>: zonas rápidas y zonas lentas.</p>
<p>Este es un problema donde la variable de entrada tiene <strong>dos dimensiones</strong> (la posición en el mapa), y donde —como veremos— las técnicas que sirvieron en una dimensión fracasan, mientras que el <strong>suavizado por kernel</strong> resuelve el problema de forma natural. La razón es intuitiva: para saber cuánto tarda una entrega en un punto, lo más sensato es mirar las entregas <strong>cercanas</strong> en el mapa. Eso es exactamente lo que hace un kernel.</p>
</section>
<section id="objetivos" class="level2">
<h2 class="anchored" data-anchor-id="objetivos">Objetivos</h2>
<p>Al terminar este caso vas a ser capaz de:</p>
<ul>
<li><strong>Reconocer</strong> cuándo un problema tiene estructura espacial (dos dimensiones) y por qué eso rompe a los modelos globales.</li>
<li><strong>Aplicar</strong> la regresión por kernel en dos dimensiones para construir un mapa de calor de predicción.</li>
<li><strong>Comparar</strong> de forma justa el kernel con la regresión lineal, el polinomio bidimensional y los k-vecinos, con validación, sin fuga de información y repitiendo el reparto de los datos con varias semillas.</li>
<li><strong>Interpretar</strong> el ancho de banda como el radio de influencia en el mapa y elegirlo por validación.</li>
</ul>
</section>
<section id="preparación-del-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparación-del-entorno">Preparación del entorno</h2>
<div id="01f4858a" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-20T22:13:49.222220Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-20T22:13:49.221969Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-20T22:13:52.362168Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-20T22:13:52.360518Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split, KFold</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LinearRegression</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PolynomialFeatures</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.pipeline <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_pipeline</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.neighbors <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> KNeighborsRegressor</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> r2_score, mean_squared_error</span>
<span id="cb1-9"></span>
<span id="cb1-10">SEMILLA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2026</span></span>
<span id="cb1-11">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb1-12">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'figure.figsize'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>)</span>
<span id="cb1-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"librerias cargadas"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>librerias cargadas</code></pre>
</div>
</div>
</section>
<section id="los-datos-entregas-en-la-ciudad" class="level2">
<h2 class="anchored" data-anchor-id="los-datos-entregas-en-la-ciudad">Los datos: entregas en la ciudad</h2>
<p>Simulamos una ciudad en una cuadrícula de 10×10. Cada entrega ocurre en una posición <code>(lon, lat)</code> y tarda un tiempo que depende de la zona: hay un <strong>centro congestionado</strong> (lento) y otra <strong>zona lenta</strong> al noroeste; el resto es más rápido. Añadimos ruido para simular la variabilidad real (un día con más tráfico, un repartidor más ágil, etc.). En la práctica no conocemos la fórmula: solo tenemos los puntos.</p>
<div id="f9d640cc" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-20T22:13:52.367775Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-20T22:13:52.367109Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-20T22:13:52.779408Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-20T22:13:52.777831Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">600</span></span>
<span id="cb3-2">lon <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, n)</span>
<span id="cb3-3">lat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, n)</span>
<span id="cb3-4"></span>
<span id="cb3-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> tiempo_real(lon, lat):</span>
<span id="cb3-6">    base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span></span>
<span id="cb3-7">    centro <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">35</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (((lon <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.6</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> ((lat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.6</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb3-8">    zona_lenta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">22</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (((lon <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> ((lat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.5</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb3-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> centro <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> zona_lenta</span>
<span id="cb3-10"></span>
<span id="cb3-11">tiempo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tiempo_real(lon, lat) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, n)</span>
<span id="cb3-12">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([lon, lat])</span>
<span id="cb3-13">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tiempo</span>
<span id="cb3-14"></span>
<span id="cb3-15">plt.scatter(lon, lat, c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'RdYlGn_r'</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>)</span>
<span id="cb3-16">plt.colorbar(label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo de entrega (min)'</span>)</span>
<span id="cb3-17">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'latitud'</span>)</span>
<span id="cb3-18">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cada punto es una entrega, coloreada por su tiempo'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span>
<span id="cb3-19"></span>
<span id="cb3-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> entregas | tiempo medio: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> min | rango: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">-</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> min'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07a-caso-entregas-kernel/index_files/figure-html/cell-3-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>600 entregas | tiempo medio: 19.2 min | rango: 3.5-49.9 min</code></pre>
</div>
</div>
<section id="cómo-leer-este-mapa" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-mapa">Cómo leer este mapa</h3>
<p>Cada punto es una entrega; el color es el tiempo (verde = rápido, rojo = lento). A simple vista se ve una <strong>mancha roja en el centro</strong> y otra hacia el noroeste: son las zonas congestionadas. El resto de la ciudad es más verde. El objetivo es convertir esta nube de puntos en un <strong>mapa continuo</strong> que prediga el tiempo en cualquier dirección, incluso donde no hay una entrega registrada.</p>
</section>
</section>
<section id="preparación-para-evaluar" class="level2">
<h2 class="anchored" data-anchor-id="preparación-para-evaluar">Preparación para evaluar</h2>
<p>Separamos entrenamiento y prueba, y definimos una malla que cubre toda la ciudad para dibujar los mapas de calor de cada modelo. El conjunto de prueba no se usará para elegir ningún parámetro: solo para medir, al final, qué modelo generaliza mejor.</p>
<div id="fdbb2d82" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-20T22:13:52.785634Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-20T22:13:52.785095Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-20T22:13:52.799520Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-20T22:13:52.797587Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">Xtr, Xte, ytr, yte <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA)</span>
<span id="cb5-2"></span>
<span id="cb5-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Malla para pintar los mapas de calor</span></span>
<span id="cb5-4">gx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>)</span>
<span id="cb5-5">gy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>)</span>
<span id="cb5-6">GX, GY <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.meshgrid(gx, gy)</span>
<span id="cb5-7">malla <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([GX.ravel(), GY.ravel()])</span>
<span id="cb5-8"></span>
<span id="cb5-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> mapa(valores, titulo):</span>
<span id="cb5-10">    plt.contourf(GX, GY, valores.reshape(GX.shape), levels<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'RdYlGn_r'</span>)</span>
<span id="cb5-11">    plt.colorbar(label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo estimado (min)'</span>)</span>
<span id="cb5-12">    plt.scatter(Xtr[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], Xtr[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'black'</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>)</span>
<span id="cb5-13">    plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'latitud'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.title(titulo)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
</div>
</section>
<section id="intento-1-regresión-lineal" class="level2">
<h2 class="anchored" data-anchor-id="intento-1-regresión-lineal">Intento 1: regresión lineal</h2>
<p>Empecemos por lo más simple, lo que ya conoces: una regresión lineal. En dos dimensiones, ajusta un <strong>plano</strong> — el tiempo sube de forma constante en alguna dirección. ¿Podrá un plano representar una ciudad con un centro lento rodeado de zonas rápidas?</p>
<div id="f06dc12b" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-20T22:13:52.805521Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-20T22:13:52.804985Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-20T22:13:53.164452Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-20T22:13:53.163076Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">lin <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression().fit(Xtr, ytr)</span>
<span id="cb6-2">r2_lin <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> r2_score(yte, lin.predict(Xte))</span>
<span id="cb6-3">mapa(lin.predict(malla), <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Regresión lineal — R2 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_lin<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb6-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'R2 en prueba (lineal): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_lin<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07a-caso-entregas-kernel/index_files/figure-html/cell-5-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>R2 en prueba (lineal): 0.030</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado">Cómo leer este resultado</h3>
<p>El mapa es un <strong>gradiente plano</strong>: el modelo solo puede decir “el tiempo aumenta hacia tal esquina”, y pinta la ciudad con una rampa de color uniforme. No hay rastro de la mancha central ni de la zona noroeste. El <strong>R² de 0.030</strong> lo confirma: el plano explica prácticamente <strong>nada</strong> de la variabilidad. Es el fracaso esperado — la relación no es lineal ni monótona, y un plano no puede doblarse para envolver un punto caliente en el centro.</p>
</section>
</section>
<section id="intento-2-polinomio-bidimensional" class="level2">
<h2 class="anchored" data-anchor-id="intento-2-polinomio-bidimensional">Intento 2: polinomio bidimensional</h2>
<p>Si un plano no basta, subamos la flexibilidad con un polinomio en dos variables (términos como <img src="https://latex.codecogs.com/png.latex?lon%5E2">, <img src="https://latex.codecogs.com/png.latex?lat%5E2">, <img src="https://latex.codecogs.com/png.latex?lon%5Ccdot%20lat">, etc.). Elegimos el grado por validación cruzada para no hacer trampa.</p>
<div id="bfabe078" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-20T22:13:53.169042Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-20T22:13:53.168581Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-20T22:13:53.826678Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-20T22:13:53.825490Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">grados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>))</span>
<span id="cb8-2">kf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KFold(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA)</span>
<span id="cb8-3"></span>
<span id="cb8-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Para cada grado candidato, medimos el error de validación en cada fold</span></span>
<span id="cb8-5">cv_g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb8-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> grados:</span>
<span id="cb8-7">    errores_folds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb8-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> idx_tr, idx_va <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> kf.split(Xtr):</span>
<span id="cb8-9">        modelo_g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_pipeline(PolynomialFeatures(g), LinearRegression())</span>
<span id="cb8-10">        modelo_g.fit(Xtr[idx_tr], ytr[idx_tr])</span>
<span id="cb8-11">        pred_va <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_g.predict(Xtr[idx_va])</span>
<span id="cb8-12">        errores_folds.append(mean_squared_error(ytr[idx_va], pred_va))</span>
<span id="cb8-13">    cv_g.append(np.mean(errores_folds))</span>
<span id="cb8-14"></span>
<span id="cb8-15">g_opt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> grados[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmin(cv_g))]</span>
<span id="cb8-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MSE de validación por grado:'</span>)</span>
<span id="cb8-17"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g, e <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(grados, cv_g):</span>
<span id="cb8-18">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  grado </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>g<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:2d}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>e<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:10.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb8-19"></span>
<span id="cb8-20">poli <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_pipeline(PolynomialFeatures(g_opt), LinearRegression()).fit(Xtr, ytr)</span>
<span id="cb8-21">r2_pol <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> r2_score(yte, poli.predict(Xte))</span>
<span id="cb8-22">mapa(poli.predict(malla), <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Polinomio 2D grado </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>g_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> — R2 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_pol<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb8-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Grado óptimo: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>g_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | R2 en prueba (polinomio): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_pol<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>MSE de validación por grado:
  grado  1:      91.26
  grado  2:      48.56
  grado  3:      45.90
  grado  4:      22.94
  grado  5:      21.65
  grado  6:      15.95
  grado  7:      17.81
  grado  8:      14.02
  grado  9:      12.07
  grado 10:      16.15</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07a-caso-entregas-kernel/index_files/figure-html/cell-6-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Grado óptimo: 9 | R2 en prueba (polinomio): 0.851</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-1">Cómo leer este resultado</h3>
<p>Ampliamos la búsqueda hasta grado 10 para no quedar pegados al borde del rango, y esta vez el mínimo cae <strong>dentro</strong> de lo probado: la validación cruzada elige <strong>grado 9</strong>, con un MSE de validación cercano a 12 (frente a 16 del grado 6, 14 del grado 8 y 16 del grado 10). Fíjate en que la curva no es una U limpia: sube y baja con altibajos y vuelve a empeorar en el grado 10, señal de que el polinomio se vuelve inestable a medida que crece.</p>
<p>Con grado 9 el R² en prueba sube a <strong>0.851</strong>, muy por encima del plano. Pero mira el mapa con calma: el polinomio capta el centro caliente y <strong>funde la zona noroeste en un solo lóbulo alargado</strong>, sin separarla del centro. Y en los <strong>bordes</strong> aparecen ondulaciones que no están en los datos; en la esquina inferior derecha el color se dispara y la barra llega a marcar <strong>tiempos negativos</strong>, algo imposible para una entrega. Es el equivalente en dos dimensiones del fenómeno de Runge que viste con los polinomios de una variable. Además, necesita 55 coeficientes para llegar hasta aquí. Mejor que la recta, pero costoso e inestable en los extremos.</p>
</section>
</section>
<section id="la-idea-local-kernel-en-dos-dimensiones" class="level2">
<h2 class="anchored" data-anchor-id="la-idea-local-kernel-en-dos-dimensiones">La idea local: kernel en dos dimensiones</h2>
<p>Volvamos a la intuición del problema: para estimar el tiempo en un punto del mapa, lo natural es <strong>promediar las entregas cercanas</strong>, dándoles más peso cuanto más cerca estén. Eso es la regresión por kernel, ahora con la distancia medida en el plano:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%7Bm%7D(x)%20=%20%5Cfrac%7B%5Csum_%7Bi%7D%20K%5C!%5Cleft(%5Cfrac%7B%5ClVert%20x%20-%20x_i%20%5CrVert%7D%7Bh%7D%5Cright)%20y_i%7D%7B%5Csum_%7Bi%7D%20K%5C!%5Cleft(%5Cfrac%7B%5ClVert%20x%20-%20x_i%20%5CrVert%7D%7Bh%7D%5Cright)%7D"></p>
<p>donde <img src="https://latex.codecogs.com/png.latex?%5ClVert%20x%20-%20x_i%20%5CrVert"> es la distancia entre dos puntos del mapa y <img src="https://latex.codecogs.com/png.latex?h"> es el <strong>radio de influencia</strong> (el ancho de banda). No hay que decidir estructuras ni grados: solo ese radio.</p>
<div id="ec2836bb" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-20T22:13:53.830602Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-20T22:13:53.830227Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-20T22:13:54.354449Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-20T22:13:54.353292Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> kernel_2d(Xtr, ytr, Xq, h):</span>
<span id="cb11-2">    out <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.empty(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(Xq))</span>
<span id="cb11-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, q <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(Xq):</span>
<span id="cb11-4">        d2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>((Xtr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> q) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)     <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># distancia al cuadrado en el mapa</span></span>
<span id="cb11-5">        w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> d2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># peso: decae con la distancia</span></span>
<span id="cb11-6">        s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> w.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()</span>
<span id="cb11-7">        out[i] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> ytr).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> s <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> np.nan</span>
<span id="cb11-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> out</span>
<span id="cb11-9"></span>
<span id="cb11-10">mapa_kernel <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> kernel_2d(Xtr, ytr, malla, h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>)</span>
<span id="cb11-11">mapa(mapa_kernel, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Kernel 2D (h=0.45)'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07a-caso-entregas-kernel/index_files/figure-html/cell-7-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-2" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-2">Cómo leer este resultado</h3>
<p>Con un radio de <strong>0.45</strong>, el mapa del kernel muestra la mancha central bien definida y un <strong>lóbulo hacia el noroeste</strong>, que es la segunda zona lenta; el resto de la ciudad queda en verde. No inventó una rampa ni se disparó en los bordes: simplemente promedió lo cercano. La zona noroeste aparece como un “hombro” naranja pegado al centro y no como una isla aparte, porque en la realidad ambas zonas se solapan y el suavizado las une en parte. Esta es la ventaja del método local en un mapa: se adapta a la forma real sin imponer una fórmula global.</p>
</section>
</section>
<section id="el-ancho-de-banda-es-el-radio-de-influencia" class="level2">
<h2 class="anchored" data-anchor-id="el-ancho-de-banda-es-el-radio-de-influencia">El ancho de banda es el radio de influencia</h2>
<p>En dos dimensiones, <img src="https://latex.codecogs.com/png.latex?h"> tiene una lectura muy física: <strong>cuán lejos alcanza la vecindad</strong> que se promedia para cada punto. Comparemos tres radios; el del medio, 0.45, es el que la validación elegirá un poco más adelante.</p>
<div id="e378d777" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-20T22:13:54.358698Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-20T22:13:54.358410Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-20T22:13:55.645564Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-20T22:13:55.644302Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb12-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> a, h <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(ax, [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.15</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.0</span>]):</span>
<span id="cb12-3">    val <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> kernel_2d(Xtr, ytr, malla, h).reshape(GX.shape)</span>
<span id="cb12-4">    cf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> a.contourf(GX, GY, val, levels<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'RdYlGn_r'</span>)</span>
<span id="cb12-5">    a.set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'h = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> a.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud'</span>)</span>
<span id="cb12-6">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'latitud'</span>)</span>
<span id="cb12-7">plt.tight_layout()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07a-caso-entregas-kernel/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-3" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-3">Cómo leer este resultado</h3>
<ul>
<li><strong>h = 0.15 (radio pequeño):</strong> el mapa se ve manchado y lleno de parches sueltos, incluso en zonas donde no pasa nada; cada punto promedia muy pocos vecinos, así que el ruido pasa directo al mapa. Sobreajuste.</li>
<li><strong>h = 0.45 (equilibrado):</strong> la mancha central y el lóbulo del noroeste se ven limpios y suaves, sin parches espurios. Es el radio que la validación cruzada elegirá enseguida.</li>
<li><strong>h = 3.0 (radio grande):</strong> el promedio abarca buena parte de la ciudad y el mapa se reduce a <strong>una sola mancha borrosa</strong>, desplazada hacia el noroeste, donde ya no distingues el centro de la otra zona. Subajuste.</li>
</ul>
<p>El mismo compromiso sesgo-varianza de siempre, ahora como un <strong>radio en el mapa</strong>.</p>
</section>
</section>
<section id="elegir-el-radio-por-validación" class="level2">
<h2 class="anchored" data-anchor-id="elegir-el-radio-por-validación">Elegir el radio por validación</h2>
<p>Como siempre, no elegimos <img src="https://latex.codecogs.com/png.latex?h"> a simple vista: probamos varios por validación cruzada sobre el entrenamiento y nos quedamos con el que mejor generaliza.</p>
<div id="55f3b809" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-20T22:13:55.650054Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-20T22:13:55.649381Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-20T22:13:56.554486Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-20T22:13:56.553115Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">hs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>)</span>
<span id="cb13-2"></span>
<span id="cb13-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Para cada radio candidato, medimos el error de validación en cada fold</span></span>
<span id="cb13-4">cv_h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb13-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> h <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> hs:</span>
<span id="cb13-6">    errores_folds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb13-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> idx_tr, idx_va <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> kf.split(Xtr):</span>
<span id="cb13-8">        pred_va <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> kernel_2d(Xtr[idx_tr], ytr[idx_tr], Xtr[idx_va], h)</span>
<span id="cb13-9">        errores_folds.append(mean_squared_error(ytr[idx_va], pred_va))</span>
<span id="cb13-10">    cv_h.append(np.mean(errores_folds))</span>
<span id="cb13-11"></span>
<span id="cb13-12">h_opt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> hs[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmin(cv_h))]</span>
<span id="cb13-13"></span>
<span id="cb13-14">plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb13-15">plt.plot(hs, cv_h, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb13-16">plt.axvline(h_opt, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'h óptimo = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb13-17">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'radio h'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MSE de validación'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()</span>
<span id="cb13-18">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Selección del radio de influencia'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span>
<span id="cb13-19"></span>
<span id="cb13-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'h óptimo (validación cruzada): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | MSE de validación: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(cv_h)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07a-caso-entregas-kernel/index_files/figure-html/cell-9-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>h óptimo (validación cruzada): 0.45 | MSE de validación: 11.89</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-4" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-4">Cómo leer este resultado</h3>
<p>La curva vuelve a tener forma de <strong>U</strong>: radios muy pequeños sobreajustan, radios muy grandes difuminan (el error sube sin parar), y el mínimo queda en <strong>h = 0.45</strong>, con un MSE de validación cercano a 12. Ese es el mismo valor que usamos como caso “equilibrado” en el panel de tres radios, así que lo que viste a simple vista coincide con lo que elige la validación. Fíjate también en que el fondo de la U es plano entre 0.45 y 0.6: valores cercanos rinden casi igual, de modo que no necesitas afinar el radio al milímetro. El punto de la izquierda (h = 0.3) ya sube, señal de que el mínimo es real y no un efecto del borde del rango. Ese es el radio que usaremos en la comparación final.</p>
</section>
</section>
<section id="comparación-final-los-cuatro-modelos-lado-a-lado" class="level2">
<h2 class="anchored" data-anchor-id="comparación-final-los-cuatro-modelos-lado-a-lado">Comparación final: los cuatro modelos, lado a lado</h2>
<p>Ponemos a competir los cuatro enfoques sobre datos de prueba que no se usaron para elegir nada. Añadimos los <strong>k-vecinos</strong> (kNN), otro método local, para una comparación completa. Primero miramos los cuatro mapas de un mismo reparto de datos; después repetimos todo con varios repartos para ver cuánto de lo que observamos es real y cuánto es azar.</p>
<div id="5916a4a0" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-20T22:13:56.558990Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-20T22:13:56.558641Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-20T22:13:58.008524Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-20T22:13:58.007462Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1">ks <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">31</span>))</span>
<span id="cb15-2"></span>
<span id="cb15-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Para cada número de vecinos k, medimos el error de validación en cada fold</span></span>
<span id="cb15-4">cv_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb15-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> ks:</span>
<span id="cb15-6">    errores_folds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb15-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> idx_tr, idx_va <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> kf.split(Xtr):</span>
<span id="cb15-8">        modelo_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KNeighborsRegressor(n_neighbors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k)</span>
<span id="cb15-9">        modelo_k.fit(Xtr[idx_tr], ytr[idx_tr])</span>
<span id="cb15-10">        pred_va <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_k.predict(Xtr[idx_va])</span>
<span id="cb15-11">        errores_folds.append(mean_squared_error(ytr[idx_va], pred_va))</span>
<span id="cb15-12">    cv_k.append(np.mean(errores_folds))</span>
<span id="cb15-13"></span>
<span id="cb15-14">k_opt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ks[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmin(cv_k))]</span>
<span id="cb15-15">knn <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KNeighborsRegressor(n_neighbors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k_opt).fit(Xtr, ytr)</span>
<span id="cb15-16"></span>
<span id="cb15-17">r2_knn <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> r2_score(yte, knn.predict(Xte))</span>
<span id="cb15-18">r2_ker <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> r2_score(yte, kernel_2d(Xtr, ytr, Xte, h_opt))</span>
<span id="cb15-19"></span>
<span id="cb15-20">modelos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb15-21">    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Lineal (R2=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_lin<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>: lin.predict(malla),</span>
<span id="cb15-22">    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Polinomio g</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>g_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> (R2=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_pol<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>: poli.predict(malla),</span>
<span id="cb15-23">    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'kNN k</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> (R2=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_knn<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>: knn.predict(malla),</span>
<span id="cb15-24">    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Kernel h</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>h_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> (R2=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_ker<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>: kernel_2d(Xtr, ytr, malla, h_opt),</span>
<span id="cb15-25">}</span>
<span id="cb15-26">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>))</span>
<span id="cb15-27"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> a, (titulo, val) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(ax.ravel(), modelos.items()):</span>
<span id="cb15-28">    a.contourf(GX, GY, val.reshape(GX.shape), levels<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'RdYlGn_r'</span>)</span>
<span id="cb15-29">    a.set_title(titulo)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> a.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> a.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'latitud'</span>)</span>
<span id="cb15-30">plt.tight_layout()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07a-caso-entregas-kernel/index_files/figure-html/cell-10-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<div id="55991ca0" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-20T22:13:58.012873Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-20T22:13:58.012478Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-20T22:13:58.019245Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-20T22:13:58.018334Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'R2 en prueba, split con semilla </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>SEMILLA<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> (no usado para elegir parámetros)'</span>)</span>
<span id="cb16-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  Lineal:          </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_lin<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb16-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  Polinomio 2D:    </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_pol<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb16-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  kNN:             </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_knn<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb16-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  Kernel 2D:       </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>r2_ker<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>R2 en prueba, split con semilla 2026 (no usado para elegir parámetros)
  Lineal:          0.030
  Polinomio 2D:    0.851
  kNN:             0.855
  Kernel 2D:       0.867</code></pre>
</div>
</div>
</section>
<section id="y-si-cambia-el-reparto-la-comparación-con-varias-semillas" class="level2">
<h2 class="anchored" data-anchor-id="y-si-cambia-el-reparto-la-comparación-con-varias-semillas">¿Y si cambia el reparto? La comparación con varias semillas</h2>
<p>Los R² de arriba salen de <strong>un solo</strong> reparto entrenamiento/prueba. Si otra semilla mandara otros puntos al conjunto de prueba, ¿el orden de los modelos seguiría igual? Diferencias de un centésimo pueden ser puro azar del reparto.</p>
<p>Para saberlo, repetimos todo el protocolo con <strong>10 semillas</strong> distintas. En cada una: separamos, elegimos <img src="https://latex.codecogs.com/png.latex?g">, <img src="https://latex.codecogs.com/png.latex?k"> y <img src="https://latex.codecogs.com/png.latex?h"> por validación cruzada <strong>solo con el entrenamiento</strong> de esa semilla, y medimos el R² en su prueba. Al final reportamos el promedio y la desviación de cada modelo. Para que no tarde demasiado, aquí usamos rejillas de hiperparámetros algo más gruesas que en las secciones anteriores.</p>
<div id="ms3d4e5f" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-20T22:13:58.024083Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-20T22:13:58.023619Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-20T22:14:05.290901Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-20T22:14:05.289854Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">semillas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>))</span>
<span id="cb18-2">grados_m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>))</span>
<span id="cb18-3">ks_m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">31</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb18-4">hs_m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb18-5"></span>
<span id="cb18-6">r2_por_modelo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Lineal'</span>: [], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Polinomio 2D'</span>: [], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'kNN'</span>: [], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Kernel 2D'</span>: []}</span>
<span id="cb18-7"></span>
<span id="cb18-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> semilla <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> semillas:</span>
<span id="cb18-9">    Xtr_s, Xte_s, ytr_s, yte_s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>semilla)</span>
<span id="cb18-10">    kf_s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KFold(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>semilla)</span>
<span id="cb18-11"></span>
<span id="cb18-12">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Lineal: no tiene hiperparámetros</span></span>
<span id="cb18-13">    lin_s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression().fit(Xtr_s, ytr_s)</span>
<span id="cb18-14">    r2_por_modelo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Lineal'</span>].append(r2_score(yte_s, lin_s.predict(Xte_s)))</span>
<span id="cb18-15"></span>
<span id="cb18-16">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Polinomio: elegir el grado por validación cruzada</span></span>
<span id="cb18-17">    cv_grados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb18-18">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> grados_m:</span>
<span id="cb18-19">        errores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb18-20">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i_tr, i_va <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> kf_s.split(Xtr_s):</span>
<span id="cb18-21">            m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_pipeline(PolynomialFeatures(g), LinearRegression())</span>
<span id="cb18-22">            m.fit(Xtr_s[i_tr], ytr_s[i_tr])</span>
<span id="cb18-23">            errores.append(mean_squared_error(ytr_s[i_va], m.predict(Xtr_s[i_va])))</span>
<span id="cb18-24">        cv_grados.append(np.mean(errores))</span>
<span id="cb18-25">    g_s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> grados_m[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmin(cv_grados))]</span>
<span id="cb18-26">    poli_s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_pipeline(PolynomialFeatures(g_s), LinearRegression()).fit(Xtr_s, ytr_s)</span>
<span id="cb18-27">    r2_por_modelo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Polinomio 2D'</span>].append(r2_score(yte_s, poli_s.predict(Xte_s)))</span>
<span id="cb18-28"></span>
<span id="cb18-29">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># kNN: elegir k por validación cruzada</span></span>
<span id="cb18-30">    cv_ks <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb18-31">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> ks_m:</span>
<span id="cb18-32">        errores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb18-33">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i_tr, i_va <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> kf_s.split(Xtr_s):</span>
<span id="cb18-34">            m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KNeighborsRegressor(n_neighbors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k).fit(Xtr_s[i_tr], ytr_s[i_tr])</span>
<span id="cb18-35">            errores.append(mean_squared_error(ytr_s[i_va], m.predict(Xtr_s[i_va])))</span>
<span id="cb18-36">        cv_ks.append(np.mean(errores))</span>
<span id="cb18-37">    k_s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ks_m[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmin(cv_ks))]</span>
<span id="cb18-38">    knn_s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KNeighborsRegressor(n_neighbors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k_s).fit(Xtr_s, ytr_s)</span>
<span id="cb18-39">    r2_por_modelo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'kNN'</span>].append(r2_score(yte_s, knn_s.predict(Xte_s)))</span>
<span id="cb18-40"></span>
<span id="cb18-41">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Kernel: elegir el radio h por validación cruzada</span></span>
<span id="cb18-42">    cv_hs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb18-43">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> h <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> hs_m:</span>
<span id="cb18-44">        errores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb18-45">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i_tr, i_va <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> kf_s.split(Xtr_s):</span>
<span id="cb18-46">            pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> kernel_2d(Xtr_s[i_tr], ytr_s[i_tr], Xtr_s[i_va], h)</span>
<span id="cb18-47">            errores.append(mean_squared_error(ytr_s[i_va], pred))</span>
<span id="cb18-48">        cv_hs.append(np.mean(errores))</span>
<span id="cb18-49">    h_s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> hs_m[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmin(cv_hs))]</span>
<span id="cb18-50">    r2_por_modelo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Kernel 2D'</span>].append(r2_score(yte_s, kernel_2d(Xtr_s, ytr_s, Xte_s, h_s)))</span>
<span id="cb18-51"></span>
<span id="cb18-52"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'R2 en prueba con </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(semillas)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> semillas (promedio ± desviación)'</span>)</span>
<span id="cb18-53"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, valores <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> r2_por_modelo.items():</span>
<span id="cb18-54">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&lt;14s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean(valores)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> ± </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>std(valores, ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb18-55"></span>
<span id="cb18-56"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Diferencia kernel - kNN, semilla por semilla (mismo reparto para ambos)</span></span>
<span id="cb18-57">dif <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(r2_por_modelo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Kernel 2D'</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> np.array(r2_por_modelo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'kNN'</span>])</span>
<span id="cb18-58"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">Kernel - kNN: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>dif<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:+.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> ± </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>dif<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> '</span></span>
<span id="cb18-59">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'| el kernel gana en </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>((dif <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> de </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(semillas)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> semillas'</span>)</span>
<span id="cb18-60">dif_pol <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(r2_por_modelo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Kernel 2D'</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> np.array(r2_por_modelo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Polinomio 2D'</span>])</span>
<span id="cb18-61"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Kernel - Polinomio: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>dif_pol<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:+.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> ± </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>dif_pol<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> '</span></span>
<span id="cb18-62">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'| el kernel gana en </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>((dif_pol <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> de </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(semillas)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> semillas'</span>)</span>
<span id="cb18-63"></span>
<span id="cb18-64">plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb18-65">plt.boxplot(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(r2_por_modelo.values()))</span>
<span id="cb18-66">plt.xticks(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>), <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(r2_por_modelo.keys()))</span>
<span id="cb18-67">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'R2 en prueba'</span>)</span>
<span id="cb18-68">plt.title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'R2 en prueba con </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(semillas)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> repartos distintos'</span>)</span>
<span id="cb18-69">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>R2 en prueba con 10 semillas (promedio ± desviación)
  Lineal         0.030 ± 0.018
  Polinomio 2D   0.843 ± 0.031
  kNN            0.871 ± 0.011
  Kernel 2D      0.876 ± 0.012

Kernel - kNN: +0.005 ± 0.005 | el kernel gana en 8 de 10 semillas
Kernel - Polinomio: +0.034 ± 0.035 | el kernel gana en 8 de 10 semillas</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/07a-caso-entregas-kernel/index_files/figure-html/cell-12-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-esta-comparación" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-comparación">Cómo leer esta comparación</h3>
<p>Los mapas (un solo reparto) ya cuentan la historia cualitativa: el plano lineal es ciego a las zonas lentas, el polinomio capta el centro pero se distorsiona en los bordes, el kNN reconoce las zonas con un mapa algo “escalonado” y el kernel da el mapa más suave. Pero para decidir con números conviene mirar el promedio de las 10 semillas:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Modelo</th>
<th>R² en prueba (promedio ± desviación)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Lineal</td>
<td>0.030 ± 0.018</td>
</tr>
<tr class="even">
<td>Polinomio 2D</td>
<td>0.843 ± 0.031</td>
</tr>
<tr class="odd">
<td>kNN</td>
<td>0.871 ± 0.011</td>
</tr>
<tr class="even">
<td>Kernel 2D</td>
<td>0.876 ± 0.012</td>
</tr>
</tbody>
</table>
<p>Cómo separar lo real del ruido:</p>
<ul>
<li><strong>Lineal frente a todos los demás: diferencia real y enorme.</strong> Está a más de 0.8 de distancia, decenas de veces su variabilidad. Un plano no sirve para este problema, cambie la semilla que cambie.</li>
<li><strong>Kernel frente a polinomio: diferencia real, pero moderada.</strong> El kernel promedia 0.034 más y gana en 8 de las 10 semillas. Además, el polinomio es el modelo <strong>más inestable</strong> (desviación de 0.031, casi el triple que los métodos locales): su resultado depende mucho de qué puntos caen en el entrenamiento, y ya viste que en los bordes produce valores imposibles.</li>
<li><strong>Kernel frente a kNN: cae dentro de la variabilidad.</strong> La ventaja promedio es de apenas 0.005, menos de la mitad de lo que cada modelo se mueve de una semilla a otra (alrededor de 0.012). El kernel gana en 8 de 10 repartos, así que la dirección es consistente, pero la magnitud es tan pequeña que en la práctica es un <strong>empate en R²</strong>. En el reparto con semilla 2026, en cambio, la brecha era 0.012 (0.867 frente a 0.855), más del doble que el promedio: un buen ejemplo de por qué un solo split puede exagerar una diferencia.</li>
</ul>
<p>¿Con cuál te quedas entre kernel y kNN? No por el R², que no los separa, sino por lo que sí los distingue: el kernel entrega un mapa continuo y suave, y el kNN uno con escalones. Si vas a usar el mapa para decidir, esa suavidad importa.</p>
<p>Un último aviso honesto: las 10 semillas reparten los <strong>mismos 600 datos</strong>, así que esta variabilidad refleja el azar del reparto, no lo que pasaría con entregas nuevas. Con datos frescos la incertidumbre sería algo mayor.</p>
</section>
</section>
<section id="por-qué-el-2d-cambió-el-resultado" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-el-2d-cambió-el-resultado">Por qué el 2D cambió el resultado</h2>
<p>En una sola dimensión, un spline bien afinado suele igualar al kernel; no hay un ganador claro. Pero al pasar a <strong>dos dimensiones</strong> la balanza se inclina: los métodos globales (polinomios) se vuelven inestables y necesitan muchísimos términos, y los splines requieren productos entre dimensiones que se complican rápido. El <strong>suavizado por kernel</strong>, en cambio, apenas cambia: sigue siendo “promedia lo cercano”, solo que ahora la cercanía se mide en el plano. Esa simplicidad que no se degrada al subir de dimensión es su gran fortaleza — y por eso los métodos de kernel son un pilar en problemas espaciales, de imágenes y de datos de alta dimensión.</p>
</section>
<section id="errores-comunes-en-problemas-espaciales-con-kernels" class="level2">
<h2 class="anchored" data-anchor-id="errores-comunes-en-problemas-espaciales-con-kernels">Errores comunes en problemas espaciales con kernels</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Síntoma</th>
<th>Causa probable</th>
<th>Solución</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>El mapa se ve manchado y ruidoso</td>
<td>radio h demasiado pequeño</td>
<td>súbelo; elígelo por validación</td>
</tr>
<tr class="even">
<td>Las zonas se funden en una mancha</td>
<td>radio h demasiado grande</td>
<td>bájalo</td>
</tr>
<tr class="odd">
<td>Predicciones raras lejos de los datos</td>
<td>zonas del mapa sin entregas cercanas</td>
<td>no predigas donde no hay soporte</td>
</tr>
<tr class="even">
<td>Una variable domina la distancia</td>
<td>lon y lat en escalas distintas</td>
<td>estandariza las coordenadas antes</td>
</tr>
<tr class="odd">
<td>Muy lento con muchos datos</td>
<td>el promedio recorre todos los puntos</td>
<td>usa estructuras de vecindad (árboles KD)</td>
</tr>
</tbody>
</table>
</section>
<section id="lo-que-debes-llevarte-de-este-caso" class="level2">
<h2 class="anchored" data-anchor-id="lo-que-debes-llevarte-de-este-caso">Lo que debes llevarte de este caso</h2>
<ul>
<li>Cuando el problema tiene <strong>estructura espacial</strong> (dos o más variables de entrada), los modelos globales —recta, polinomio— fracasan o se vuelven inestables.</li>
<li>El <strong>suavizado por kernel</strong> resuelve el problema con la misma idea de siempre (promediar lo cercano), y su simplicidad <strong>no se degrada al subir de dimensión</strong>.</li>
<li>El <strong>ancho de banda</strong> es, literalmente, el radio de influencia en el mapa, y se elige por validación.</li>
<li>Los métodos <strong>locales</strong> (kernel, kNN) superan con claridad a la recta y con margen moderado al polinomio, que además es el más inestable. Entre kernel y kNN el R² no decide (diferencia de 0.005 con 10 semillas); el kernel gana por dar el mapa más suave.</li>
<li>Antes de declarar un ganador, <strong>repite la comparación con varias semillas</strong>: una diferencia de un centésimo en un solo reparto puede ser puro azar.</li>
</ul>
</section>
<section id="qué-sigue" class="level2">
<h2 class="anchored" data-anchor-id="qué-sigue">¿Qué sigue?</h2>
<p>Has visto la suavización por kernel llevar un problema real de una y dos dimensiones a un mapa útil para decidir. El siguiente tema cambia de pregunta: ¿y si lo que quieres predecir no es un número, sino una <strong>categoría</strong> (entrega a tiempo sí/no) o un <strong>conteo</strong> (número de incidencias)? Ahí entran los <strong>modelos lineales generalizados (GLM)</strong> y su extensión, los <strong>modelos aditivos (GAM)</strong>, que combinan estas ideas con la regresión.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>suavizacion</category>
  <category>kernel</category>
  <category>caso-practico</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/avanzado/07a-caso-entregas-kernel/</guid>
  <pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Análisis Avanzado de Datos — 8. Modelos lineales generalizados (GLM): regresión logística</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/avanzado/09-glm/</link>
  <description><![CDATA[ 




<section id="análisis-avanzado-de-datos-8.-modelos-lineales-generalizados-glm-regresión-logística" class="level1">
<h1>Análisis Avanzado de Datos — 8. Modelos lineales generalizados (GLM): regresión logística</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado convierte datos en decisiones. Científico de Datos, Arquitecto de IA y asesor tecnológico con más de 20 años de experiencia en analítica avanzada, machine learning, Big Data e IoT. Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), asesora a entidades gubernamentales y empresas privadas en Colombia y es referente en analítica y normatividad para los sectores postal y logístico del país. Una serie pensada para ir de la teoría a la práctica, con ejemplos concretos en cada paso.</p>
<p>📌 <em>Parte de la serie <strong>Análisis Avanzado de Datos</strong>.</em></p>
</section>
<section id="cuando-la-respuesta-es-sí-o-no" class="level2">
<h2 class="anchored" data-anchor-id="cuando-la-respuesta-es-sí-o-no">Cuando la respuesta es sí o no</h2>
<p>Hasta ahora, de la regresión lineal a los splines y los kernels, predijiste <strong>números continuos</strong>: un tiempo, un flujo, un costo. Pero muchas de las preguntas más importantes tienen respuesta <strong>binaria</strong>: ¿esta entrega llegará a tiempo o no? ¿este cliente se irá o se quedará? ¿esta transacción es fraude o no? Para eso, la regresión lineal no sirve: podría predecir una “probabilidad” de 1.4 o de −0.3, que no significan nada.</p>
<p>La <strong>regresión logística</strong> resuelve esto. Es el primer paso hacia los <strong>modelos lineales generalizados (GLM)</strong>: en vez de predecir el valor directamente, predice la <strong>probabilidad</strong> de que ocurra el sí, garantizando que quede siempre entre 0 y 1. En este artículo la construimos sobre un caso de logística de entregas con datos simulados, la pregunta que dejó planteada el caso aplicado de entregas: predecir si una entrega llegará a tiempo.</p>
</section>
<section id="objetivos-de-aprendizaje" class="level2">
<h2 class="anchored" data-anchor-id="objetivos-de-aprendizaje">Objetivos de aprendizaje</h2>
<p>Al terminar este notebook vas a ser capaz de:</p>
<ul>
<li><strong>Reconocer</strong> cuándo una variable respuesta es binaria y por qué una regresión lineal no respeta su distribución.</li>
<li><strong>Describir</strong> las tres piezas de un GLM logístico: respuesta Bernoulli, predictor lineal y función de enlace logit.</li>
<li><strong>Distinguir</strong> probabilidad, odds y log-odds, y convertir coeficientes en <strong>odds ratios</strong>.</li>
<li><strong>Ajustar</strong> una regresión logística y obtener probabilidades para observaciones nuevas.</li>
<li><strong>Explicar</strong> cómo un umbral convierte probabilidades en clases y cómo afecta los tipos de error.</li>
<li><strong>Evaluar</strong> el modelo con matriz de confusión, exactitud y área bajo la curva ROC (AUC).</li>
<li><strong>Distinguir</strong> el uso de <code>scikit-learn</code> para predicción y de <code>statsmodels</code> para inferencia.</li>
</ul>
</section>
<section id="preparación-del-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparación-del-entorno">Preparación del entorno</h2>
<p>Cargamos las librerías y fijamos una semilla global, <code>SEMILLA = 2026</code>, de la que salen la simulación de los datos y la partición en entrenamiento y prueba.</p>
<div id="3a40894b" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:28.578316Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:28.578112Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:31.130014Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:31.129012Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LinearRegression, LogisticRegression</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> accuracy_score, roc_auc_score, confusion_matrix, roc_curve</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> statsmodels.api <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sm</span>
<span id="cb1-8"></span>
<span id="cb1-9">SEMILLA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2026</span></span>
<span id="cb1-10">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb1-11">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'figure.figsize'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span></code></pre></div></div>
</div>
</section>
<section id="los-datos-la-entrega-llega-a-tiempo" class="level2">
<h2 class="anchored" data-anchor-id="los-datos-la-entrega-llega-a-tiempo">Los datos: ¿la entrega llega a tiempo?</h2>
<p>Simulamos 800 entregas. De cada una conocemos la <strong>distancia</strong> (km) y si se hizo en <strong>hora pico</strong>, y queremos predecir si llegó <strong>a tiempo</strong> (1) o no (0). Por construcción, la probabilidad de llegar a tiempo baja con la distancia y baja también en hora pico. En la práctica no conocemos esa regla: la inferimos de los datos.</p>
<div id="ffac59fa" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:31.131991Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:31.131694Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:31.147350Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:31.146286Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">800</span></span>
<span id="cb2-2">distancia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, n)          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># km</span></span>
<span id="cb2-3">hora_pico <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.integers(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, n)          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 1 = hora pico</span></span>
<span id="cb2-4"></span>
<span id="cb2-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Regla oculta (log-odds de llegar a tiempo): baja con distancia y en hora pico</span></span>
<span id="cb2-6">logit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> distancia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> hora_pico</span>
<span id="cb2-7">prob <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>logit))</span>
<span id="cb2-8">a_tiempo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.binomial(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, prob)</span>
<span id="cb2-9"></span>
<span id="cb2-10">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([distancia, hora_pico])</span>
<span id="cb2-11">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> a_tiempo</span>
<span id="cb2-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> entregas | llegaron a tiempo: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-13">pd.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia'</span>: distancia[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'hora_pico'</span>: hora_pico[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'a_tiempo'</span>: y[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]})</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>800 entregas | llegaron a tiempo: 56.4%</code></pre>
</div>
<div class="cell-output cell-output-display" data-execution_count="2">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">distancia</th>
<th data-quarto-table-cell-role="th">hora_pico</th>
<th data-quarto-table-cell-role="th">a_tiempo</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>5.294436</td>
<td>0</td>
<td>1</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>16.357916</td>
<td>1</td>
<td>0</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>12.214442</td>
<td>0</td>
<td>0</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>9.892013</td>
<td>1</td>
<td>0</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>9.518016</td>
<td>0</td>
<td>1</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-este-resultado" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado">Cómo leer este resultado</h3>
<p>El <strong>56.4%</strong> de las entregas llega a tiempo, así que las clases están razonablemente equilibradas (ni todo sí ni todo no). La variable objetivo es 0 o 1: no hay valores intermedios. Ese es precisamente el problema que la regresión lineal no sabe manejar, como veremos ahora.</p>
</section>
</section>
<section id="por-qué-la-regresión-lineal-no-sirve-aquí" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-la-regresión-lineal-no-sirve-aquí">Por qué la regresión lineal no sirve aquí</h2>
<p>Antes de buscar una solución, veamos el fracaso de la herramienta conocida. Para aislar el problema, usaremos únicamente las entregas realizadas <strong>fuera de hora pico</strong> y ajustaremos una regresión lineal de <code>a_tiempo</code> contra distancia. Así, la demostración es univariada y la forma del gráfico no mezcla el efecto de la segunda variable.</p>
<div id="6125dda0" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:31.149321Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:31.149095Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:31.312091Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:31.311312Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">mascara_normal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> hora_pico <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb4-2">distancia_normal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> distancia[mascara_normal]</span>
<span id="cb4-3">y_normal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y[mascara_normal]</span>
<span id="cb4-4"></span>
<span id="cb4-5">lin <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression().fit(distancia_normal.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), y_normal)</span>
<span id="cb4-6">grid_lineal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">250</span>).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb4-7">pred_grid_lineal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lin.predict(grid_lineal)</span>
<span id="cb4-8"></span>
<span id="cb4-9">plt.scatter(distancia_normal, y_normal, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'entregas fuera de hora pico'</span>)</span>
<span id="cb4-10">plt.plot(grid_lineal, pred_grid_lineal, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'regresión lineal'</span>)</span>
<span id="cb4-11">plt.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb4-12">plt.axvline(distancia_normal.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'máximo observado'</span>)</span>
<span id="cb4-13">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia (km)'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'¿llegó a tiempo?'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend(loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'center right'</span>)</span>
<span id="cb4-14">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'La recta produce "probabilidades" fuera de [0, 1]'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span>
<span id="cb4-15"></span>
<span id="cb4-16"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> km <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>]:</span>
<span id="cb4-17">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Predicción de la recta a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>km<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&gt;2}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> km: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>lin<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>predict([[km]])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb4-18"></span>
<span id="cb4-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Distancias observadas: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>distancia_normal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>distancia_normal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> km'</span>)</span>
<span id="cb4-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'La recta cruza 1 a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> lin.intercept_) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> lin<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>coef_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> km y 0 a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>lin<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>intercept_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> lin<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>coef_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> km'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/09-glm/index_files/figure-html/cell-4-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Predicción de la recta a  0 km: 1.10
Predicción de la recta a 30 km: 0.14
Predicción de la recta a 40 km: -0.17
Distancias observadas: 1.0 a 24.9 km
La recta cruza 1 a 3.0 km y 0 a 34.5 km</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-1">Cómo leer este resultado</h3>
<p>La recta resume una tendencia descendente, pero no respeta los límites de una probabilidad. <strong>Ya dentro del rango observado (1.0 a 24.9 km) supera 1</strong>: cruza ese valor a 3.0 km, así que para las entregas más cortas predice más de 1 (1.10 si se prolonga hasta 0 km). <strong>Más allá de los datos sigue bajando</strong> y cruza 0 a 34.5 km: a 40 km predice −0.17. Ninguno de esos valores puede interpretarse como una probabilidad.</p>
<p>Ese es el fallo más visible, pero no el único. Cuando <img src="https://latex.codecogs.com/png.latex?Y"> solo puede valer 0 o 1, su distribución es Bernoulli y su varianza depende de la probabilidad:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AY%5Csim%5Coperatorname%7BBernoulli%7D(p),%0A%5Cqquad%20%5Cmathbb%7BE%7D(Y)=p,%0A%5Cqquad%20%5Coperatorname%7BVar%7D(Y)=p(1-p).%0A"></p>
<p>La varianza no es constante: es máxima en <img src="https://latex.codecogs.com/png.latex?p=0.5"> y se reduce hacia los extremos, lo que contradice el supuesto de varianza constante (homocedasticidad) de la regresión lineal. Necesitamos un modelo que respete la distribución binaria y garantice <img src="https://latex.codecogs.com/png.latex?0%5Cleq%20p%5Cleq1">. Antes de construirlo, separemos formalmente sus piezas.</p>
</section>
</section>
<section id="la-arquitectura-formal-del-glm-logístico" class="level2">
<h2 class="anchored" data-anchor-id="la-arquitectura-formal-del-glm-logístico">La arquitectura formal del GLM logístico</h2>
<p>Una regresión logística combina tres piezas:</p>
<ol type="1">
<li><strong>Distribución de la respuesta:</strong> cada entrega es un ensayo Bernoulli.</li>
<li><strong>Predictor lineal:</strong> las variables se combinan en una cantidad sin restricciones.</li>
<li><strong>Función de enlace:</strong> el logit conecta la media de la respuesta con el predictor.</li>
</ol>
<p><img src="https://latex.codecogs.com/png.latex?%0AY_i%5Csim%5Coperatorname%7BBernoulli%7D(p_i),%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ceta_i=%5Cbeta_0+%5Cbeta_1x_%7Bi1%7D+%5Ccdots+%5Cbeta_kx_%7Bik%7D=X_i%5Cbeta,%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Coperatorname%7Blogit%7D(p_i)=%5Clog%5C!%5Cleft(%5Cfrac%7Bp_i%7D%7B1-p_i%7D%5Cright)=%5Ceta_i.%0A"></p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Pieza</th>
<th>Regresión logística</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Respuesta</td>
<td>Bernoulli</td>
</tr>
<tr class="even">
<td>Media</td>
<td><img src="https://latex.codecogs.com/png.latex?p_i"></td>
</tr>
<tr class="odd">
<td>Predictor lineal</td>
<td><img src="https://latex.codecogs.com/png.latex?X_i%5Cbeta"></td>
</tr>
<tr class="even">
<td>Enlace</td>
<td>logit</td>
</tr>
<tr class="odd">
<td>Función inversa</td>
<td>sigmoide</td>
</tr>
</tbody>
</table>
<p>La parte lineal sigue ahí, pero ya no intenta predecir directamente un cero o un uno. Predice en la escala logit y después regresa a una probabilidad. Construyamos esa transformación paso a paso.</p>
</section>
<section id="paso-1-de-la-probabilidad-a-las-odds" class="level2">
<h2 class="anchored" data-anchor-id="paso-1-de-la-probabilidad-a-las-odds">Paso 1: de la probabilidad a las odds</h2>
<p>Las <strong><em>odds</em></strong> (en español, momios) expresan cuántas veces esperamos el evento por cada no evento:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Coperatorname%7Bodds%7D(p)=%5Cfrac%7Bp%7D%7B1-p%7D.%0A"></p>
<p>Si <img src="https://latex.codecogs.com/png.latex?p=0.5">, las odds son 1: uno a uno. Si <img src="https://latex.codecogs.com/png.latex?p=0.8">, las odds son 4: cuatro entregas puntuales por cada entrega tardía. Mientras <img src="https://latex.codecogs.com/png.latex?p"> vive entre 0 y 1, las odds van de 0 a infinito.</p>
<div id="d6a72ddc" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:31.313727Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:31.313535Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:31.321213Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:31.320338Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">probs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.75</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span>])</span>
<span id="cb6-2">odds_ejemplo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> probs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> probs)</span>
<span id="cb6-3">pd.DataFrame({</span>
<span id="cb6-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>: probs,</span>
<span id="cb6-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'odds = p/(1-p)'</span>: odds_ejemplo,</span>
<span id="cb6-6">}).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display" data-execution_count="4">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">probabilidad</th>
<th data-quarto-table-cell-role="th">odds = p/(1-p)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>0.10</td>
<td>0.111</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>0.25</td>
<td>0.333</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>0.50</td>
<td>1.000</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>0.75</td>
<td>3.000</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>0.90</td>
<td>9.000</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-esta-tabla" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-tabla">Cómo leer esta tabla</h3>
<p>Cuando <img src="https://latex.codecogs.com/png.latex?p=0.5">, las odds valen 1. Por encima de 0.5 crecen con rapidez: <img src="https://latex.codecogs.com/png.latex?p=0.9"> equivale a odds de 9. Por debajo de 0.5 están entre 0 y 1. Nunca son negativas, así que no cubren todo el rango de valores que puede tomar un predictor lineal. Falta aplicar el logaritmo.</p>
</section>
</section>
<section id="paso-2-de-las-odds-a-los-log-odds" class="level2">
<h2 class="anchored" data-anchor-id="paso-2-de-las-odds-a-los-log-odds">Paso 2: de las odds a los log-odds</h2>
<p>El logaritmo de las odds se llama <strong><em>log-odds</em></strong> o <strong>logit</strong>. Aplicar el logaritmo transforma <img src="https://latex.codecogs.com/png.latex?(0,%5Cinfty)"> en toda la recta real:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Coperatorname%7Blogit%7D(p)=%5Clog%5C!%5Cleft(%5Cfrac%7Bp%7D%7B1-p%7D%5Cright).%0A"></p>
<p>Así, <img src="https://latex.codecogs.com/png.latex?p=0.5"> corresponde a log-odds 0; probabilidades mayores producen valores positivos y probabilidades menores, negativos. Esta es la escala donde el modelo puede usar una combinación lineal sin restricciones.</p>
<div id="0d507562" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:31.323115Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:31.322900Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:31.495505Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:31.494668Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">grid_p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.001</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.999</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>)</span>
<span id="cb7-2">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb7-3">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(grid_p, grid_p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> grid_p), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb7-4">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Odds (eje cortado en 20)'</span>, xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>, ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'p/(1-p)'</span>, ylim<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>))</span>
<span id="cb7-5">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(grid_p, np.log(grid_p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> grid_p)), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb7-6">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb7-7">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Log-odds o logit'</span>, xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>, ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'log(p/(1-p))'</span>)</span>
<span id="cb7-8">plt.tight_layout()</span>
<span id="cb7-9">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/09-glm/index_files/figure-html/cell-6-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-estas-transformaciones" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estas-transformaciones">Cómo leer estas transformaciones</h3>
<p>A la izquierda, las odds se disparan cuando <img src="https://latex.codecogs.com/png.latex?p"> se acerca a 1: en <img src="https://latex.codecogs.com/png.latex?p=0.999"> valen 999, por eso el eje se corta en 20. A la derecha, el logit reparte esa escala de forma simétrica alrededor de cero (<img src="https://latex.codecogs.com/png.latex?p"> y <img src="https://latex.codecogs.com/png.latex?1-p"> dan log-odds opuestos). El modelo trabaja en ese eje; falta el camino de vuelta a la probabilidad.</p>
</section>
</section>
<section id="paso-3-volver-a-la-probabilidad-con-la-sigmoide" class="level2">
<h2 class="anchored" data-anchor-id="paso-3-volver-a-la-probabilidad-con-la-sigmoide">Paso 3: volver a la probabilidad con la sigmoide</h2>
<p>La inversa del logit es la función logística:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ap_i=%5Coperatorname%7Blogit%7D%5E%7B-1%7D(%5Ceta_i)=%5Cfrac%7B1%7D%7B1+e%5E%7B-%5Ceta_i%7D%7D.%0A"></p>
<p>Esta transformación toma cualquier valor real de <img src="https://latex.codecogs.com/png.latex?%5Ceta_i=X_i%5Cbeta"> y lo devuelve al intervalo abierto <img src="https://latex.codecogs.com/png.latex?(0,1)">: se acerca a 0 y a 1 sin alcanzarlos. Esa es la curva en forma de S que reemplaza a la recta fallida del inicio.</p>
<div id="4f52f0a9" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:31.497552Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:31.497332Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:31.591960Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:31.591307Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>)</span>
<span id="cb8-2">plt.plot(z, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>z)), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb8-3">plt.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb8-4">plt.axhline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>)</span>
<span id="cb8-5">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'η = combinación lineal'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>)</span>
<span id="cb8-6">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'La función logística (sigmoide): siempre entre 0 y 1'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span>
<span id="cb8-7"></span>
<span id="cb8-8">eta_ejemplo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>])</span>
<span id="cb8-9">p_ejemplo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>eta_ejemplo))</span>
<span id="cb8-10">tabla_escalas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb8-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'η = log-odds'</span>: eta_ejemplo,</span>
<span id="cb8-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'odds = exp(η)'</span>: np.exp(eta_ejemplo),</span>
<span id="cb8-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>: p_ejemplo,</span>
<span id="cb8-14">})</span>
<span id="cb8-15">tabla_escalas.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/09-glm/index_files/figure-html/cell-7-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display" data-execution_count="6">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">η = log-odds</th>
<th data-quarto-table-cell-role="th">odds = exp(η)</th>
<th data-quarto-table-cell-role="th">probabilidad</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>-2.0</td>
<td>0.135</td>
<td>0.119</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>0.0</td>
<td>1.000</td>
<td>0.500</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>2.0</td>
<td>7.389</td>
<td>0.881</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-este-resultado-2" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-2">Cómo leer este resultado</h3>
<p>La curva en forma de S nunca sale del intervalo <img src="https://latex.codecogs.com/png.latex?(0,1)">. Cuando <img src="https://latex.codecogs.com/png.latex?%5Ceta=0">, las odds son <img src="https://latex.codecogs.com/png.latex?e%5E0=1">: el evento y el no evento tienen la misma posibilidad, por lo que <img src="https://latex.codecogs.com/png.latex?p=0.5">. Cuando <img src="https://latex.codecogs.com/png.latex?%5Ceta=2">, las odds son aproximadamente 7.39 a 1 y la probabilidad es cercana a 0.881. Cuando <img src="https://latex.codecogs.com/png.latex?%5Ceta=-2">, las odds son aproximadamente 0.135 y la probabilidad baja a 0.119.</p>
<p>Las tres escalas expresan la misma predicción, pero responden preguntas distintas:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Escala</th>
<th>Expresión</th>
<th>Lectura</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Probabilidad</td>
<td><img src="https://latex.codecogs.com/png.latex?p"></td>
<td>proporción esperada de eventos</td>
</tr>
<tr class="even">
<td>Odds</td>
<td><img src="https://latex.codecogs.com/png.latex?p/(1-p)"></td>
<td>eventos esperados por cada no evento</td>
</tr>
<tr class="odd">
<td>Log-odds</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Clog(p/(1-p))"></td>
<td>escala lineal donde actúan los coeficientes</td>
</tr>
</tbody>
</table>
<p>La probabilidad es la escala más natural para comunicar una predicción. Las odds y los log-odds son las escalas que permiten formular e interpretar el modelo.</p>
</section>
<section id="antes-de-seguir-pregúntate" class="level3">
<h3 class="anchored" data-anchor-id="antes-de-seguir-pregúntate">Antes de seguir, pregúntate</h3>
<p>Si el coeficiente que acompaña a una variable cambia de magnitud, ¿qué le ocurre a la inclinación de la sigmoide? ¿Y qué cambia cuando modificamos únicamente el intercepto? La siguiente figura aísla ambos efectos.</p>
<div id="a4212962" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:31.594070Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:31.593871Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.071483Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.070268Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1">z_param <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>)</span>
<span id="cb9-2">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb9-3"></span>
<span id="cb9-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> beta_1 <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.0</span>]:</span>
<span id="cb9-5">    ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(z_param, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>(beta_1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> z_param))), label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">rf'</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$\b</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">eta_1=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>beta_1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb9-6">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'La pendiente controla la transición'</span>, xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>, ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>)</span>
<span id="cb9-7">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].legend()</span>
<span id="cb9-8"></span>
<span id="cb9-9"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> beta_0 <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.0</span>]:</span>
<span id="cb9-10">    ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(z_param, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>(z_param <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> beta_0))), label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">rf'</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$\b</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">eta_0=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>beta_0<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb9-11">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'El intercepto desplaza el punto medio'</span>, xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>, ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>)</span>
<span id="cb9-12">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].legend()</span>
<span id="cb9-13"></span>
<span id="cb9-14">plt.tight_layout()</span>
<span id="cb9-15">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/09-glm/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="cómo-leer-esta-figura" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-figura">Cómo leer esta figura</h3>
<p>En un modelo con una sola variable, una mayor magnitud de <img src="https://latex.codecogs.com/png.latex?%5Cbeta_1"> hace más abrupta la transición; su signo determina si la probabilidad sube o baja. El intercepto <img src="https://latex.codecogs.com/png.latex?%5Cbeta_0"> desplaza el punto donde <img src="https://latex.codecogs.com/png.latex?p=0.5">. Ajustar la logística significa estimar esos parámetros en la escala logit por <strong>máxima verosimilitud</strong>: se eligen los valores de <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> que hacen más probables las respuestas 0/1 observadas. A diferencia de los mínimos cuadrados, no hay fórmula cerrada y la solución se obtiene de forma iterativa.</p>
</section>
</section>
<section id="ajustar-el-modelo-predictivo" class="level2">
<h2 class="anchored" data-anchor-id="ajustar-el-modelo-predictivo">Ajustar el modelo predictivo</h2>
<p>Separamos entrenamiento y prueba con estratificación para conservar aproximadamente la proporción de entregas puntuales en ambos conjuntos.</p>
<p>El modelo de <code>scikit-learn</code> tendrá un propósito <strong>predictivo</strong>: aprende únicamente con entrenamiento y se evalúa con probabilidades y decisiones sobre prueba. <code>LogisticRegression</code> aplica por defecto una penalización L2 (la misma de Ridge) con <code>C=1.0</code>, donde <code>C</code> es el inverso de la fuerza de la penalización; eso ayuda a estabilizar los coeficientes. Aquí no ajustamos <code>C</code> por validación cruzada porque el objetivo es ilustrar el modelo, no optimizarlo. Más adelante ajustaremos <code>statsmodels</code> sobre el mismo entrenamiento, pero con un propósito inferencial.</p>
<div id="473c2f42" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.074480Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.074158Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.094256Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.092682Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">X_tr, X_te, y_tr, y_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(</span>
<span id="cb10-2">    X, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA, stratify<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y</span>
<span id="cb10-3">)</span>
<span id="cb10-4"></span>
<span id="cb10-5">modelo_predictivo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LogisticRegression().fit(X_tr, y_tr)</span>
<span id="cb10-6">prob_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_predictivo.predict_proba(X_te)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb10-7">UMBRAL <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span></span>
<span id="cb10-8">pred_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (prob_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> UMBRAL).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)</span>
<span id="cb10-9"></span>
<span id="cb10-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Coeficientes predictivos (distancia, hora_pico):'</span>, modelo_predictivo.coef_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb10-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Intercepto predictivo:'</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(modelo_predictivo.intercept_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb10-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Probabilidades en prueba: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>prob_te<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>prob_te<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Coeficientes predictivos (distancia, hora_pico): [-0.171 -1.045]
Intercepto predictivo: 3.228
Probabilidades en prueba: 0.109 a 0.944</code></pre>
</div>
</div>
<section id="cómo-leer-estos-coeficientes" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estos-coeficientes">Cómo leer estos coeficientes</h3>
<p>Los signos son coherentes con el caso: una mayor distancia y estar en hora pico reducen el log-odds y, por tanto, la probabilidad de llegar a tiempo, manteniendo constante la otra variable.</p>
<p>No interpretes estos valores como puntos porcentuales. Además, son coeficientes del modelo predictivo regularizado. Para una lectura multiplicativa mediante odds ratios y para obtener p-valores ajustaremos después un modelo inferencial sobre el mismo conjunto de entrenamiento.</p>
</section>
</section>
<section id="visualizar-el-ajuste" class="level2">
<h2 class="anchored" data-anchor-id="visualizar-el-ajuste">Visualizar el ajuste</h2>
<p>Antes de interpretar los odds ratios, dibujemos la probabilidad estimada según la distancia para una entrega fuera de hora pico y para una entrega en hora pico. Las dos curvas proceden del mismo modelo; solo cambia el indicador <code>hora_pico</code>.</p>
<div id="e582e4e9" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.097172Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.096849Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.261719Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.260413Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">distancia_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>)</span>
<span id="cb12-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> indicador_pico, color, etiqueta <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [</span>
<span id="cb12-3">    (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'fuera de hora pico'</span>),</span>
<span id="cb12-4">    (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'hora pico'</span>),</span>
<span id="cb12-5">]:</span>
<span id="cb12-6">    X_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([distancia_grid, np.full_like(distancia_grid, indicador_pico)])</span>
<span id="cb12-7">    plt.plot(</span>
<span id="cb12-8">        distancia_grid,</span>
<span id="cb12-9">        modelo_predictivo.predict_proba(X_grid)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb12-10">        color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>etiqueta,</span>
<span id="cb12-11">    )</span>
<span id="cb12-12"></span>
<span id="cb12-13">plt.axhline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>)</span>
<span id="cb12-14">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia (km)'</span>)</span>
<span id="cb12-15">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad de llegar a tiempo'</span>)</span>
<span id="cb12-16">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Probabilidad estimada según distancia y hora pico'</span>)</span>
<span id="cb12-17">plt.legend()</span>
<span id="cb12-18">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/09-glm/index_files/figure-html/cell-10-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-estas-curvas" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estas-curvas">Cómo leer estas curvas</h3>
<p>Son dos sigmoides con la <strong>misma pendiente en la escala logit</strong> y distinto intercepto. En la escala de probabilidad se ven desplazadas, pero su separación vertical no es constante. A igual distancia, la curva de hora pico asigna una menor probabilidad de llegar a tiempo. La línea horizontal marca el umbral 0.5: fuera de hora pico la curva lo cruza cerca de los 18.8 km y en hora pico cerca de los 12.7 km. Esos 6.1 km de diferencia son el efecto de <code>hora_pico</code> expresado en distancia: <img src="https://latex.codecogs.com/png.latex?1.045/0.171%5Capprox6.1">.</p>
</section>
</section>
<section id="modelo-inferencial-y-odds-ratios" class="level2">
<h2 class="anchored" data-anchor-id="modelo-inferencial-y-odds-ratios">Modelo inferencial y odds ratios</h2>
<p>Ahora ajustamos <code>statsmodels</code> <strong>sobre el mismo conjunto de entrenamiento</strong>. Su propósito es inferencial: obtener coeficientes, odds ratios y p-valores.</p>
<p><code>LogisticRegression</code> usa regularización L2 por defecto; <code>sm.Logit</code> no regulariza. Por eso sus coeficientes pueden diferir aunque vean las mismas observaciones. Si necesitas coeficientes comparables, ajusta scikit-learn sin penalización con <code>LogisticRegression(C=np.inf)</code>: desde la versión 1.8 el parámetro <code>penalty</code> está obsoleto (emite un aviso y se eliminará en la 1.10).</p>
<p>Para una variable <img src="https://latex.codecogs.com/png.latex?x_j">, <img src="https://latex.codecogs.com/png.latex?e%5E%7B%5Cbeta_j%7D"> es el <strong>odds ratio</strong> (razón de odds): el factor por el que se multiplican las odds cuando <img src="https://latex.codecogs.com/png.latex?x_j"> aumenta una unidad, manteniendo constantes las demás variables. Para un cambio de <img src="https://latex.codecogs.com/png.latex?d"> unidades, el factor acumulado es <img src="https://latex.codecogs.com/png.latex?(e%5E%7B%5Cbeta_j%7D)%5Ed">.</p>
<div id="60c4b9c0" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.264257Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.263951Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.293983Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.292434Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">X_tr_sm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sm.add_constant(X_tr)</span>
<span id="cb13-2">modelo_inferencial <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sm.Logit(y_tr, X_tr_sm).fit(disp<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb13-3"></span>
<span id="cb13-4">nombres <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'intercepto'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'hora_pico'</span>]</span>
<span id="cb13-5">coeficientes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(modelo_inferencial.params, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres)</span>
<span id="cb13-6">odds_ratios <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(coeficientes)</span>
<span id="cb13-7">p_valores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(modelo_inferencial.pvalues, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres)</span>
<span id="cb13-8"></span>
<span id="cb13-9">ic_or <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(modelo_inferencial.conf_int())   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># IC 95% en escala de odds ratio</span></span>
<span id="cb13-10"></span>
<span id="cb13-11">tabla_inferencia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb13-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'coeficiente'</span>: coeficientes.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb13-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'odds ratio'</span>: odds_ratios.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb13-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'OR IC95</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">% i</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">nf'</span>: ic_or[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb13-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'OR IC95</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">% s</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">up'</span>: ic_or[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb13-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'p-valor'</span>: p_valores.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">map</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> v: <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>v<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1e}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>),</span>
<span id="cb13-17">})</span>
<span id="cb13-18">display(tabla_inferencia)</span>
<span id="cb13-19"></span>
<span id="cb13-20">or_distancia_10km <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> odds_ratios[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span></span>
<span id="cb13-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"OR acumulado para 10 km adicionales: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>or_distancia_10km<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb13-22"></span>
<span id="cb13-23">perfiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb13-24">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>: [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>],</span>
<span id="cb13-25">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'hora_pico'</span>: [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb13-26">})</span>
<span id="cb13-27">X_perfiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> perfiles[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'hora_pico'</span>]].to_numpy()</span>
<span id="cb13-28">perfiles[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad_llegar_a_tiempo'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_predictivo.predict_proba(X_perfiles)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb13-29">display(perfiles.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">coeficiente</th>
<th data-quarto-table-cell-role="th">odds ratio</th>
<th data-quarto-table-cell-role="th">OR IC95% inf</th>
<th data-quarto-table-cell-role="th">OR IC95% sup</th>
<th data-quarto-table-cell-role="th">p-valor</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">intercepto</th>
<td>3.2675</td>
<td>26.2451</td>
<td>14.257</td>
<td>48.315</td>
<td>9.2e-26</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">distancia</th>
<td>-0.1724</td>
<td>0.8416</td>
<td>0.814</td>
<td>0.870</td>
<td>1.2e-24</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">hora_pico</th>
<td>-1.0893</td>
<td>0.3364</td>
<td>0.225</td>
<td>0.504</td>
<td>1.3e-07</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>OR acumulado para 10 km adicionales: 0.178</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">distancia_km</th>
<th data-quarto-table-cell-role="th">hora_pico</th>
<th data-quarto-table-cell-role="th">probabilidad_llegar_a_tiempo</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>5</td>
<td>0</td>
<td>0.915</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>5</td>
<td>1</td>
<td>0.790</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>15</td>
<td>0</td>
<td>0.659</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>15</td>
<td>1</td>
<td>0.404</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>25</td>
<td>0</td>
<td>0.258</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">5</th>
<td>25</td>
<td>1</td>
<td>0.109</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-la-inferencia-y-los-perfiles" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-la-inferencia-y-los-perfiles">Cómo leer la inferencia y los perfiles</h3>
<ul>
<li>El odds ratio estimado para <strong>distancia</strong> es 0.8416 por kilómetro (IC 95%: 0.814 a 0.870): cada kilómetro adicional multiplica las odds de llegar a tiempo por 0.84, es decir, las reduce cerca de un 16%. Para 10 km, el efecto acumulado es <img src="https://latex.codecogs.com/png.latex?0.8416%5E%7B10%7D%5Capprox0.178">: las odds quedan en menos de una quinta parte.</li>
<li>A igual distancia, <strong>hora pico</strong> multiplica las odds de llegar a tiempo por 0.336 (IC 95%: 0.225 a 0.504), una reducción cercana al 66%. El efecto acumulado de distancia depende de cuántos kilómetros compares, así que no corresponde ordenar ambos factores usando cambios en unidades distintas.</li>
<li>Los <strong>p-valores</strong>, todos del orden de <img src="https://latex.codecogs.com/png.latex?10%5E%7B-7%7D"> o menores, aportan evidencia contra la hipótesis de que el coeficiente sea cero, bajo los supuestos del modelo; no demuestran causalidad ni importancia práctica.</li>
</ul>
<p>La tabla de perfiles, calculada con el modelo predictivo, devuelve la conversación a la escala más fácil de comunicar: a 5 km la probabilidad de llegar a tiempo es 0.915 fuera de hora pico y 0.790 en hora pico; a 25 km baja a 0.258 y 0.109. La brecha por hora pico es de 12.4 puntos porcentuales a 5 km, 25.4 a 15 km y 14.9 a 25 km: el mismo odds ratio produce diferencias distintas en la escala de probabilidad, como anticipaban las curvas. De paso, la penalización por defecto de scikit-learn casi no se nota con 560 observaciones de entrenamiento: su intercepto (3.228) y sus pendientes (−0.171 y −1.045) quedan muy cerca de los de statsmodels (3.268, −0.172 y −1.089).</p>
</section>
</section>
<section id="de-la-probabilidad-a-la-decisión" class="level2">
<h2 class="anchored" data-anchor-id="de-la-probabilidad-a-la-decisión">De la probabilidad a la decisión</h2>
<p>El modelo estima la <strong>probabilidad de que la entrega llegue a tiempo</strong>. Para convertirla en una decisión usamos un umbral: con 0.5, declaramos “llega a tiempo” cuando <img src="https://latex.codecogs.com/png.latex?%5Chat%20p%5Cgeq0.5">.</p>
<ul>
<li><strong>Falso positivo:</strong> prometimos “llega a tiempo”, pero llegó tarde. Es una <strong>falsa promesa</strong>.</li>
<li><strong>Falso negativo:</strong> predijimos “no llega a tiempo”, pero sí llegó. Es una <strong>alerta innecesaria</strong>.</li>
</ul>
<p>Un umbral alto exige más evidencia antes de prometer puntualidad: reduce falsas promesas, pero genera más alertas innecesarias. Un umbral bajo declara más entregas como puntuales: aumenta la cobertura de los casos que sí llegan, pero puede producir más falsas promesas.</p>
<p>Primero compararemos la <strong>exactitud</strong> (proporción de entregas clasificadas correctamente) con una <strong>línea base</strong> (<em>baseline</em>): la regla ingenua que siempre predice la clase mayoritaria. Después observaremos cómo cambian los errores al mover el umbral y usaremos el AUC (área bajo la curva ROC) para evaluar la capacidad de ordenar casos sin fijar un único corte.</p>
<div id="3f976743" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.296911Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.296437Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.327982Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.326524Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1">acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> accuracy_score(y_te, pred_te)</span>
<span id="cb15-2">auc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> roc_auc_score(y_te, prob_te)</span>
<span id="cb15-3">accuracy_base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(y_te.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y_te.mean())</span>
<span id="cb15-4"></span>
<span id="cb15-5">cm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> confusion_matrix(y_te, pred_te)</span>
<span id="cb15-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Matriz de confusión con umbral = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>UMBRAL<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">:'</span>)</span>
<span id="cb15-7">display(pd.DataFrame(cm, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'real: no'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'real: sí'</span>], columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pred: no'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pred: sí'</span>]))</span>
<span id="cb15-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Exactitud del modelo: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acc<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb15-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Línea base (siempre la clase mayoritaria): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>accuracy_base<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb15-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Mejora absoluta sobre la línea base: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> accuracy_base<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb15-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'AUC: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>auc<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb15-12"></span>
<span id="cb15-13">filas_umbral <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb15-14"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> umbral <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>]:</span>
<span id="cb15-15">    pred_umbral <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (prob_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> umbral).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)</span>
<span id="cb15-16">    tn, fp, fn, tp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> confusion_matrix(y_te, pred_umbral).ravel()</span>
<span id="cb15-17">    filas_umbral.append({</span>
<span id="cb15-18">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'umbral'</span>: umbral,</span>
<span id="cb15-19">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">% d</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">eclarado puntual'</span>: pred_umbral.mean(),</span>
<span id="cb15-20">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'falsas promesas (FP)'</span>: fp,</span>
<span id="cb15-21">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'alertas innecesarias (FN)'</span>: fn,</span>
<span id="cb15-22">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'exactitud'</span>: accuracy_score(y_te, pred_umbral),</span>
<span id="cb15-23">    })</span>
<span id="cb15-24"></span>
<span id="cb15-25">tabla_umbrales <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(filas_umbral)</span>
<span id="cb15-26">display(tabla_umbrales.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Matriz de confusión con umbral = 0.50:</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">pred: no</th>
<th data-quarto-table-cell-role="th">pred: sí</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">real: no</th>
<td>70</td>
<td>35</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">real: sí</th>
<td>35</td>
<td>100</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Exactitud del modelo: 0.708
Línea base (siempre la clase mayoritaria): 0.562
Mejora absoluta sobre la línea base: 0.146
AUC: 0.800</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">umbral</th>
<th data-quarto-table-cell-role="th">% declarado puntual</th>
<th data-quarto-table-cell-role="th">falsas promesas (FP)</th>
<th data-quarto-table-cell-role="th">alertas innecesarias (FN)</th>
<th data-quarto-table-cell-role="th">exactitud</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>0.3</td>
<td>0.804</td>
<td>64</td>
<td>6</td>
<td>0.708</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>0.5</td>
<td>0.562</td>
<td>35</td>
<td>35</td>
<td>0.708</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>0.7</td>
<td>0.333</td>
<td>14</td>
<td>69</td>
<td>0.654</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-la-línea-base-y-los-umbrales" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-la-línea-base-y-los-umbrales">Cómo leer la línea base y los umbrales</h3>
<p>La exactitud del modelo solo es informativa al compararla con una regla ingenua. La línea base responde: “¿qué lograría si siempre eligiera la clase más frecuente?”. Aquí el modelo acierta 0.708 frente a 0.562 de la línea base: 14.6 puntos porcentuales por encima de la regla ingenua.</p>
<p>La tabla de umbrales muestra que una misma exactitud puede esconder errores operativamente distintos: con umbral 0.3 y con umbral 0.5 el modelo acierta 0.708, pero el primero comete 64 falsas promesas y 6 alertas innecesarias, y el segundo 35 y 35. Subir el umbral reduce cuántas entregas declaramos puntuales (del 80.4% con 0.3 al 33.3% con 0.7) y nunca aumenta las falsas promesas (64 → 35 → 14), a costa de más alertas innecesarias (6 → 35 → 69). La elección debe reflejar cuál de esos errores cuesta más. Esta tabla se calcula sobre el conjunto de prueba solo para ilustrar: si quisieras elegir el umbral, hazlo con validación cruzada sobre el entrenamiento, como con cualquier hiperparámetro.</p>
</section>
</section>
<section id="evaluar-sin-fijar-un-único-umbral-roc-y-auc" class="level2">
<h2 class="anchored" data-anchor-id="evaluar-sin-fijar-un-único-umbral-roc-y-auc">Evaluar sin fijar un único umbral: ROC y AUC</h2>
<p>La curva ROC (<em>receiver operating characteristic</em>) recorre todos los umbrales y enfrenta dos tasas: la de <strong>verdaderos positivos</strong>, <img src="https://latex.codecogs.com/png.latex?%5Ctext%7BTP%7D/(%5Ctext%7BTP%7D+%5Ctext%7BFN%7D)">, que es la fracción de entregas puntuales que el modelo declara puntuales, y la de <strong>falsos positivos</strong>, <img src="https://latex.codecogs.com/png.latex?%5Ctext%7BFP%7D/(%5Ctext%7BFP%7D+%5Ctext%7BTN%7D)">, que es la fracción de entregas tardías que declara puntuales (las falsas promesas). Con umbral 0.5 valen 0.741 y 0.333. El <strong>AUC</strong> (área bajo esa curva) resume la capacidad del modelo para ordenar una entrega puntual por encima de una tardía según su probabilidad estimada.</p>
<div id="12ccc94a" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.330841Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.330378Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.462284Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.461102Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">fpr, tpr, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> roc_curve(y_te, prob_te)</span>
<span id="cb18-2">plt.plot(fpr, tpr, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'AUC = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>auc<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb18-3">plt.plot([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k--'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'azar'</span>)</span>
<span id="cb18-4">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa de falsos positivos'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa de verdaderos positivos'</span>)</span>
<span id="cb18-5">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Curva ROC'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.legend()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/09-glm/index_files/figure-html/cell-13-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-la-curva-roc" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-la-curva-roc">Cómo leer la curva ROC</h3>
<p>Un AUC de 0.800 significa que, al elegir una entrega puntual y una tardía, el modelo asigna una probabilidad mayor de llegar a tiempo a la entrega puntual aproximadamente el 80% de las veces. Un AUC de 0.5 corresponde a un ordenamiento sin capacidad discriminativa.</p>
<p>La exactitud evalúa una decisión concreta bajo un umbral; el AUC evalúa el ordenamiento a través de todos los umbrales. Ninguna de las dos determina qué umbral conviene al negocio, y ninguna mide la <strong>calibración</strong>. Discriminación y calibración son preguntas distintas: el AUC responde si el modelo <strong>ordena</strong> bien los casos; la calibración, si cuando el modelo anuncia 0.80 aproximadamente 80 de cada 100 casos comparables llegan a tiempo. En este artículo usamos el AUC para medir discriminación; evaluar la calibración sería un paso adicional antes de desplegar probabilidades operativas.</p>
</section>
</section>
<section id="errores-comunes-en-regresión-logística" class="level2">
<h2 class="anchored" data-anchor-id="errores-comunes-en-regresión-logística">Errores comunes en regresión logística</h2>
<ol type="1">
<li><strong>Interpretar un coeficiente como cambio directo en probabilidad.</strong> <img src="https://latex.codecogs.com/png.latex?%5Cbeta_j"> cambia los log-odds y <img src="https://latex.codecogs.com/png.latex?e%5E%7B%5Cbeta_j%7D"> multiplica las odds.</li>
<li><strong>Confundir la clase positiva.</strong> Aquí 1 significa “llega a tiempo”; una probabilidad alta no significa “mayor riesgo de retraso”.</li>
<li><strong>Confundir probabilidad con decisión.</strong> El umbral convierte una estimación continua en una clase y debe responder al costo de los errores.</li>
<li><strong>Evaluar solamente con exactitud.</strong> Compárala con una línea base y revisa qué tipos de error produce cada umbral.</li>
<li><strong>Interpretar asociación como causalidad.</strong> Un coeficiente ajustado no demuestra que intervenir sobre la variable cause el cambio.</li>
<li><strong>Leer un p-valor como tamaño o importancia del efecto.</strong> El p-valor y el odds ratio responden preguntas diferentes.</li>
<li><strong>Comparar coeficientes regularizados y no regularizados como si fueran idénticos.</strong> scikit-learn y statsmodels pueden estimar valores distintos aun usando el mismo entrenamiento.</li>
<li><strong>Confundir discriminación con calibración.</strong> Un AUC alto no garantiza probabilidades bien calibradas.</li>
</ol>
</section>
<section id="lo-que-debes-llevarte-de-este-artículo" class="level2">
<h2 class="anchored" data-anchor-id="lo-que-debes-llevarte-de-este-artículo">Lo que debes llevarte de este artículo</h2>
<p>La cadena completa es:</p>
<pre class="text"><code>respuesta binaria
→ distribución Bernoulli
→ predictor lineal η = Xβ
→ enlace logit
→ probabilidad mediante la sigmoide
→ umbral elegido según costos
→ decisión: llega a tiempo / no llega a tiempo</code></pre>
<p>Los coeficientes viven en log-odds; sus exponenciales son odds ratios. Para comunicar una predicción concreta usamos probabilidades por perfil. Para evaluar, comparamos contra una línea base, examinamos los errores del umbral y usamos AUC para medir discriminación.</p>
<p>La regresión logística conserva una estructura lineal, pero adapta la distribución y la función de enlace al tipo de respuesta. Esa es la idea general que reutilizaremos en los próximos artículos de la serie (Poisson y modelos aditivos): no forzar todas las respuestas a una recta gaussiana, sino elegir una distribución y un enlace coherentes con el fenómeno. De hecho, la regresión lineal de los primeros artículos es el GLM más simple: respuesta normal y enlace identidad.</p>
</section>
<section id="qué-sigue" class="level2">
<h2 class="anchored" data-anchor-id="qué-sigue">¿Qué sigue?</h2>
<p>El paralelo que prepara el siguiente artículo es directo:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Modelo</th>
<th>Distribución de la respuesta</th>
<th>Función de enlace</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Lineal</td>
<td>Normal</td>
<td>identidad</td>
</tr>
<tr class="even">
<td>Logística</td>
<td>Bernoulli</td>
<td>logit</td>
</tr>
<tr class="odd">
<td>Poisson</td>
<td>Poisson</td>
<td>log</td>
</tr>
</tbody>
</table>
<p>En logística preguntamos si una entrega llega a tiempo. En Poisson preguntaremos cuántos eventos ocurren. Cambian la distribución y el enlace; permanece la arquitectura GLM.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>glm</category>
  <category>regresion-logistica</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/avanzado/09-glm/</guid>
  <pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Análisis Avanzado de Datos — 9. GLM: regresión de Poisson</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/avanzado/10-regresion-poisson/</link>
  <description><![CDATA[ 




<section id="análisis-avanzado-de-datos-9.-glm-regresión-de-poisson" class="level1">
<h1>Análisis Avanzado de Datos — 9. GLM: regresión de Poisson</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado convierte datos en decisiones. Científico de Datos, Arquitecto de IA y asesor tecnológico con más de 20 años de experiencia en analítica avanzada, machine learning, Big Data e IoT. Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), asesora a entidades gubernamentales y empresas privadas en Colombia y es referente en analítica y normatividad para los sectores postal y logístico del país. Una serie pensada para ir de la teoría a la práctica, con ejemplos concretos en cada paso.</p>
<p>📌 <em>Parte de la serie <strong>Análisis Avanzado de Datos</strong>.</em></p>
</section>
<section id="cuando-lo-que-cuentas-son-eventos" class="level2">
<h2 class="anchored" data-anchor-id="cuando-lo-que-cuentas-son-eventos">Cuando lo que cuentas son eventos</h2>
<p>En el artículo anterior la respuesta era sí o no. Ahora la respuesta es un <strong>conteo</strong>: ¿cuántas incidencias tuvo una ruta? ¿cuántos pedidos llegaron en una hora? ¿cuántas llamadas recibió el centro de soporte? Son números enteros, nunca negativos, y a menudo con muchos ceros.</p>
<p>Usar una regresión lineal para conteos es un error clásico: puede predecir <strong>−1.5 incidencias</strong>, que es imposible. La <strong>regresión de Poisson</strong> —otro modelo lineal generalizado (GLM, por sus siglas en inglés)— está hecha justo para esto: modela la <strong>tasa</strong> a la que ocurren los eventos y garantiza predicciones positivas. La construimos sobre un caso de transporte: predecir el número de incidencias por ruta.</p>
</section>
<section id="objetivos-de-aprendizaje" class="level2">
<h2 class="anchored" data-anchor-id="objetivos-de-aprendizaje">Objetivos de aprendizaje</h2>
<p>Al terminar este notebook vas a ser capaz de:</p>
<ul>
<li><strong>Reconocer</strong> cuándo una respuesta es un conteo y por qué una regresión lineal puede producir predicciones imposibles.</li>
<li><strong>Describir</strong> las tres piezas de un GLM de Poisson: distribución, predictor lineal y enlace log.</li>
<li><strong>Explicar</strong> por qué la función exponencial garantiza una tasa esperada positiva.</li>
<li><strong>Ajustar</strong> un modelo predictivo con <code>PoissonRegressor</code>, elegir su regularización por validación cruzada y evaluarlo sobre datos de prueba.</li>
<li><strong>Interpretar</strong> coeficientes como cocientes de tasas de incidencia (IRR), incluidos cambios de varias unidades.</li>
<li><strong>Distinguir</strong> el propósito predictivo de scikit-learn del propósito inferencial de statsmodels.</li>
<li><strong>Comparar</strong> el modelo con un baseline de media constante mediante deviance de Poisson.</li>
<li><strong>Reconocer</strong> el supuesto de equidispersión y la señal básica de sobredispersión.</li>
</ul>
</section>
<section id="preparación-del-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparación-del-entorno">Preparación del entorno</h2>
<div id="dd982e6d" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:35.291336Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:35.291137Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:37.756621Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:37.755555Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy.stats <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> poisson <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> poisson_dist</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split, GridSearchCV, KFold</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.pipeline <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_pipeline</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> StandardScaler</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LinearRegression, PoissonRegressor</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> mean_absolute_error, mean_poisson_deviance</span>
<span id="cb1-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> statsmodels.api <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sm</span>
<span id="cb1-11"></span>
<span id="cb1-12">SEMILLA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span></span>
<span id="cb1-13">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb1-14">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'figure.figsize'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb1-15">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.top'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span></span>
<span id="cb1-16">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.right'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span></span></code></pre></div></div>
</div>
</section>
<section id="los-datos-incidencias-por-ruta" class="level2">
<h2 class="anchored" data-anchor-id="los-datos-incidencias-por-ruta">Los datos: incidencias por ruta</h2>
<p>Simulamos 700 rutas. De cada una conocemos su <strong>longitud</strong> (km) y si tuvo <strong>clima adverso</strong>, y contamos cuántas <strong>incidencias</strong> (retrasos, fallos, novedades) ocurrieron. Por construcción, la tasa de incidencias sube con la longitud y con el mal clima.</p>
<div id="1a06e065" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:37.759130Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:37.758793Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:37.777283Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:37.776549Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">700</span></span>
<span id="cb2-2">longitud <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>, n)</span>
<span id="cb2-3">clima_adverso <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.integers(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, n)</span>
<span id="cb2-4"></span>
<span id="cb2-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Regla oculta: la tasa media crece con longitud y clima adverso.</span></span>
<span id="cb2-6">tasa_real <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.045</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> longitud <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> clima_adverso)</span>
<span id="cb2-7">incidencias <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.poisson(tasa_real)</span>
<span id="cb2-8"></span>
<span id="cb2-9">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([longitud, clima_adverso])</span>
<span id="cb2-10">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> incidencias</span>
<span id="cb2-11"></span>
<span id="cb2-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Rutas: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Media de incidencias: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Varianza de incidencias: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>var(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Máximo observado: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Rutas sin incidencias: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean(y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-17">pd.DataFrame({</span>
<span id="cb2-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud_km'</span>: longitud[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>],</span>
<span id="cb2-19">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clima_adverso'</span>: clima_adverso[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>],</span>
<span id="cb2-20">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'incidencias'</span>: y[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>],</span>
<span id="cb2-21">}).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Rutas: 700
Media de incidencias: 2.934
Varianza de incidencias: 7.544
Máximo observado: 19
Rutas sin incidencias: 16.1%</code></pre>
</div>
<div class="cell-output cell-output-display" data-execution_count="2">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">longitud_km</th>
<th data-quarto-table-cell-role="th">clima_adverso</th>
<th data-quarto-table-cell-role="th">incidencias</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>39.38</td>
<td>1</td>
<td>4</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>54.35</td>
<td>1</td>
<td>10</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>47.66</td>
<td>1</td>
<td>8</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>17.39</td>
<td>1</td>
<td>2</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>21.51</td>
<td>1</td>
<td>3</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">5</th>
<td>53.05</td>
<td>1</td>
<td>5</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-este-resultado" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado">Cómo leer este resultado</h3>
<p>Aquí verificamos primero la naturaleza de la respuesta: solo aparecen enteros no negativos, desde rutas sin incidencias hasta unas pocas rutas con conteos altos. La media global es 2.934 y la varianza 7.544, unas 2.6 veces mayor; pero ambas cifras resumen una mezcla de rutas cortas, largas y con climas distintos, así que no son todavía una prueba del supuesto de Poisson. Más adelante evaluaremos la dispersión después de explicar esas diferencias con el modelo.</p>
</section>
</section>
<section id="la-forma-de-una-variable-de-conteo" class="level2">
<h2 class="anchored" data-anchor-id="la-forma-de-una-variable-de-conteo">La forma de una variable de conteo</h2>
<p>Un conteo no llena una recta continua: toma valores <img src="https://latex.codecogs.com/png.latex?0,1,2,%5Cldots">. Además, suele ser asimétrico, acumular observaciones cerca de cero y extender una cola hacia valores grandes. Veamos la distribución de incidencias antes de elegir un modelo.</p>
<div id="f128c206" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:37.779036Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:37.778838Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:37.929248Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:37.928556Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">valores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(y.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb4-2">frecuencias <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(y).value_counts().reindex(valores, fill_value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb4-3"></span>
<span id="cb4-4">plt.bar(valores, frecuencias, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'white'</span>)</span>
<span id="cb4-5">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'número de incidencias'</span>)</span>
<span id="cb4-6">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'número de rutas'</span>)</span>
<span id="cb4-7">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Conteos discretos, asimétricos y con una cola a la derecha'</span>)</span>
<span id="cb4-8">plt.xticks(valores)</span>
<span id="cb4-9">plt.show()</span>
<span id="cb4-10"></span>
<span id="cb4-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Moda observada (número de incidencias): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>frecuencias<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>idxmax()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb4-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Rutas con 0, 1 o 2 incidencias: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean(y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/10-regresion-poisson/index_files/figure-html/cell-4-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Moda observada (número de incidencias): 1
Rutas con 0, 1 o 2 incidencias: 55.4%</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-1">Cómo leer este resultado</h3>
<p>El histograma no es una campana continua: son barras separadas para <img src="https://latex.codecogs.com/png.latex?0,1,2,%5Cldots">, con mayor concentración en conteos bajos y una cola hacia la derecha. El conteo más frecuente es 1 y el 55.4% de las rutas tiene como máximo dos incidencias, mientras la cola llega hasta 19. Esa geometría pide una distribución definida sobre enteros no negativos.</p>
</section>
</section>
<section id="la-distribución-de-poisson" class="level2">
<h2 class="anchored" data-anchor-id="la-distribución-de-poisson">La distribución de Poisson</h2>
<p>Una variable Poisson cuenta eventos que ocurren en una unidad de exposición. Su parámetro <img src="https://latex.codecogs.com/png.latex?%5Clambda%3E0"> es a la vez su media y su varianza. En un modelo de regresión, la condición se escribe dados los predictores <img src="https://latex.codecogs.com/png.latex?X">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AY%5Cmid%20X%5Csim%5Coperatorname%7BPoisson%7D(%5Clambda),%0A%5Cqquad%0A%5Cmathbb%7BE%7D(Y%5Cmid%20X)=%5Clambda,%0A%5Cqquad%0A%5Coperatorname%7BVar%7D(Y%5Cmid%20X)=%5Clambda.%0A"></p>
<p>Esa igualdad entre media y varianza condicionales se llama <strong>equidispersión</strong>; al final del artículo verificamos si los datos la respetan.</p>
<p>No significa que todos los conteos tengan la misma media. En una regresión, cada ruta recibe su propia <img src="https://latex.codecogs.com/png.latex?%5Clambda_i"> según sus características.</p>
<div id="2502ee07" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:37.931131Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:37.930928Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:38.169431Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:38.168510Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">21</span>)</span>
<span id="cb6-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> lambda_valor, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>), (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>), (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>)]:</span>
<span id="cb6-3">    plt.plot(</span>
<span id="cb6-4">        k, poisson_dist.pmf(k, mu<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>lambda_valor),</span>
<span id="cb6-5">        marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">rf'</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">lambda=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>lambda_valor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>,</span>
<span id="cb6-6">    )</span>
<span id="cb6-7">plt.xlabel(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r'conteo </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">y</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb6-8">plt.ylabel(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r'</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">P</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">(</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">Y=y</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb6-9">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'La forma de Poisson cambia con la tasa esperada'</span>)</span>
<span id="cb6-10">plt.legend()</span>
<span id="cb6-11">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/10-regresion-poisson/index_files/figure-html/cell-5-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-estas-distribuciones" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estas-distribuciones">Cómo leer estas distribuciones</h3>
<p>Con <img src="https://latex.codecogs.com/png.latex?%5Clambda=1">, casi toda la masa está cerca de cero. Al subir a 4 y 10, el centro se desplaza a la derecha y la distribución se ensancha. En regresión no elegimos una sola de estas curvas para todas las rutas: estimamos una tasa <img src="https://latex.codecogs.com/png.latex?%5Clambda_i"> distinta para cada combinación de longitud y clima.</p>
</section>
</section>
<section id="por-qué-la-regresión-lineal-falla-con-conteos" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-la-regresión-lineal-falla-con-conteos">Por qué la regresión lineal falla con conteos</h2>
<p>Dividimos los datos en entrenamiento y prueba. Después ajustamos una regresión lineal ingenua con longitud y clima. Para visualizar el problema sin mezclar grupos, dibujamos su predicción para <strong>clima normal</strong> y la comparamos con rutas de entrenamiento bajo esa misma condición.</p>
<div id="70f6a4c0" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:38.171267Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:38.170992Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:38.286650Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:38.285973Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">X_tr, X_te, y_tr, y_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(</span>
<span id="cb7-2">    X, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA</span>
<span id="cb7-3">)</span>
<span id="cb7-4"></span>
<span id="cb7-5">modelo_lineal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression().fit(X_tr, y_tr)</span>
<span id="cb7-6">pred_lineal_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_lineal.predict(X_te)</span>
<span id="cb7-7"></span>
<span id="cb7-8">longitud_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">65</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>)</span>
<span id="cb7-9">X_grid_normal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([longitud_grid, np.zeros_like(longitud_grid)])</span>
<span id="cb7-10">pred_lineal_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_lineal.predict(X_grid_normal)</span>
<span id="cb7-11">mascara_normal_tr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_tr[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb7-12"></span>
<span id="cb7-13">plt.scatter(</span>
<span id="cb7-14">    X_tr[mascara_normal_tr, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], y_tr[mascara_normal_tr],</span>
<span id="cb7-15">    s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'rutas con clima normal'</span>,</span>
<span id="cb7-16">)</span>
<span id="cb7-17">plt.plot(longitud_grid, pred_lineal_grid, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'regresión lineal'</span>)</span>
<span id="cb7-18">plt.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb7-19">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud de la ruta (km)'</span>)</span>
<span id="cb7-20">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'incidencias'</span>)</span>
<span id="cb7-21">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'La recta puede predecir conteos negativos'</span>)</span>
<span id="cb7-22">plt.legend()</span>
<span id="cb7-23">plt.show()</span>
<span id="cb7-24"></span>
<span id="cb7-25"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Predicción lineal a 0 km, clima normal: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>modelo_lineal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>predict([[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb7-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Predicción mínima en prueba: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pred_lineal_te<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb7-27"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Rutas de prueba con predicción negativa: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>(pred_lineal_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/10-regresion-poisson/index_files/figure-html/cell-6-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Predicción lineal a 0 km, clima normal: -1.752
Predicción mínima en prueba: -1.052
Rutas de prueba con predicción negativa: 16</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-2" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-2">Cómo leer este resultado</h3>
<p>La recta no conoce la frontera natural en cero. Para rutas cortas con clima normal prolonga la tendencia hasta valores negativos: 16 rutas de prueba reciben predicciones imposibles, la menor de ellas −1.052 incidencias. El valor a 0 km (−1.752) es una extrapolación —ninguna ruta mide menos de 5 km—, pero las predicciones negativas de prueba sí ocurren dentro del rango observado. El problema no se resuelve recortando los negativos a cero: necesitamos una forma funcional cuya media sea positiva por construcción.</p>
</section>
</section>
<section id="la-arquitectura-formal-del-glm-de-poisson" class="level2">
<h2 class="anchored" data-anchor-id="la-arquitectura-formal-del-glm-de-poisson">La arquitectura formal del GLM de Poisson</h2>
<p>El modelo combina las mismas tres piezas que ya viste en logística:</p>
<ol type="1">
<li><strong>Distribución de la respuesta:</strong> cada conteo sigue una distribución Poisson condicional a sus predictores.</li>
<li><strong>Predictor lineal:</strong> longitud y clima se combinan sin restricciones en <img src="https://latex.codecogs.com/png.latex?%5Ceta_i">.</li>
<li><strong>Función de enlace:</strong> el logaritmo conecta la tasa media positiva con ese predictor.</li>
</ol>
<p><img src="https://latex.codecogs.com/png.latex?%0AY_i%5Csim%5Coperatorname%7BPoisson%7D(%5Clambda_i),%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ceta_i=%5Cbeta_0+%5Cbeta_1x_%7Bi1%7D+%5Ccdots+%5Cbeta_kx_%7Bik%7D=X_i%5Cbeta,%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Clog(%5Clambda_i)=%5Ceta_i.%0A"></p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Pieza</th>
<th>Regresión de Poisson</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Respuesta</td>
<td>Poisson</td>
</tr>
<tr class="even">
<td>Media</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Clambda_i"></td>
</tr>
<tr class="odd">
<td>Predictor lineal</td>
<td><img src="https://latex.codecogs.com/png.latex?X_i%5Cbeta"></td>
</tr>
<tr class="even">
<td>Enlace</td>
<td>log</td>
</tr>
<tr class="odd">
<td>Función inversa</td>
<td>exponencial</td>
</tr>
</tbody>
</table>
<p>Como <img src="https://latex.codecogs.com/png.latex?%5Clambda_i=e%5E%7B%5Ceta_i%7D">, la tasa esperada siempre es positiva.</p>
<section id="el-mismo-esqueleto-otra-respuesta" class="level3">
<h3 class="anchored" data-anchor-id="el-mismo-esqueleto-otra-respuesta">El mismo esqueleto, otra respuesta</h3>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Modelo</th>
<th>Distribución</th>
<th>Enlace</th>
<th>Inversa</th>
<th>Qué estima</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Logística</td>
<td>Bernoulli</td>
<td>logit</td>
<td>sigmoide</td>
<td>probabilidad del sí</td>
</tr>
<tr class="even">
<td>Poisson</td>
<td>Poisson</td>
<td>log</td>
<td>exponencial</td>
<td>tasa esperada de eventos</td>
</tr>
</tbody>
</table>
<p>La idea unificadora del GLM es mantener <img src="https://latex.codecogs.com/png.latex?X%5Cbeta"> y adaptar la distribución y el enlace a la naturaleza de <img src="https://latex.codecogs.com/png.latex?Y">.</p>
</section>
</section>
<section id="por-qué-modelamos-el-logaritmo-de-la-tasa" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-modelamos-el-logaritmo-de-la-tasa">Por qué modelamos el logaritmo de la tasa</h2>
<p>La tasa <img src="https://latex.codecogs.com/png.latex?%5Clambda"> no puede ser negativa, pero el predictor <img src="https://latex.codecogs.com/png.latex?%5Ceta=X%5Cbeta"> sí puede tomar cualquier valor real. El enlace log resuelve esa diferencia:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Clog(%5Clambda)=%5Ceta%0A%5Cquad%5CLongleftrightarrow%5Cquad%0A%5Clambda=e%5E%5Ceta.%0A"></p>
<p>La exponencial es la función inversa del enlace. Convierte toda la recta real en valores estrictamente positivos y transforma cambios aditivos en <img src="https://latex.codecogs.com/png.latex?%5Ceta"> en cambios multiplicativos sobre la tasa.</p>
<div id="3ca9b5a5" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:38.288384Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:38.288179Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:38.404190Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:38.403452Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1">eta_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>)</span>
<span id="cb9-2">lambda_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(eta_grid)</span>
<span id="cb9-3"></span>
<span id="cb9-4">plt.plot(eta_grid, lambda_grid, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb9-5">plt.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb9-6">plt.axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb9-7">plt.scatter([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r'</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">e</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">^</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">0=1</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb9-8">plt.xlabel(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r'predictor lineal </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">eta=X</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">\b</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">eta</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb9-9">plt.ylabel(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r'tasa esperada </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">lambda=e</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">^</span><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">eta</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb9-10">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'La exponencial transforma cualquier valor real en una tasa positiva'</span>)</span>
<span id="cb9-11">plt.legend()</span>
<span id="cb9-12">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/10-regresion-poisson/index_files/figure-html/cell-7-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-esta-función" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-función">Cómo leer esta función</h3>
<p>Cuando <img src="https://latex.codecogs.com/png.latex?%5Ceta=0">, la tasa esperada es 1. Valores negativos de <img src="https://latex.codecogs.com/png.latex?%5Ceta"> producen tasas entre 0 y 1; valores positivos producen tasas mayores que 1. La curva nunca cruza cero. Además, un incremento fijo en <img src="https://latex.codecogs.com/png.latex?%5Ceta"> multiplica la tasa, en lugar de sumarle siempre la misma cantidad.</p>
</section>
<section id="antes-de-seguir-pregúntate" class="level3">
<h3 class="anchored" data-anchor-id="antes-de-seguir-pregúntate">Antes de seguir, pregúntate</h3>
<p>Si <img src="https://latex.codecogs.com/png.latex?%5Cbeta_1"> aumenta, ¿la tasa crece más rápido o más lento con la longitud? Si solo cambia <img src="https://latex.codecogs.com/png.latex?%5Cbeta_0">, ¿cambia la forma del crecimiento o su nivel inicial? ¿Y qué efecto tendría sumar un coeficiente positivo cuando el clima es adverso?</p>
<div id="e1671f04" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:38.406068Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:38.405863Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:38.623208Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:38.622187Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">x_coef <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>)</span>
<span id="cb10-2">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb10-3"></span>
<span id="cb10-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> beta_1 <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.045</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.07</span>]:</span>
<span id="cb10-5">    ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(x_coef, np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> beta_1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x_coef), label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">rf'</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$\b</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">eta_1=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>beta_1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb10-6">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'La pendiente controla el ritmo de crecimiento'</span>, xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud'</span>, ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa esperada'</span>)</span>
<span id="cb10-7">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].legend()</span>
<span id="cb10-8"></span>
<span id="cb10-9"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> beta_0, etiqueta <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.6</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nivel bajo'</span>), (<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nivel medio'</span>), (<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nivel alto'</span>)]:</span>
<span id="cb10-10">    ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(x_coef, np.exp(beta_0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.045</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x_coef), label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>etiqueta)</span>
<span id="cb10-11">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'El intercepto cambia el nivel de la tasa'</span>, xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud'</span>, ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa esperada'</span>)</span>
<span id="cb10-12">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].legend()</span>
<span id="cb10-13"></span>
<span id="cb10-14">plt.tight_layout()</span>
<span id="cb10-15">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/10-regresion-poisson/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="cómo-leer-esta-figura" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-figura">Cómo leer esta figura</h3>
<p>Una pendiente mayor acelera el crecimiento multiplicativo de la tasa con la longitud. Cambiar el intercepto eleva o reduce toda la curva. Una variable binaria como clima adverso actúa de forma parecida a un cambio de nivel: cuando vale 1, suma su coeficiente en la escala log y multiplica la tasa por <img src="https://latex.codecogs.com/png.latex?e%5E%7B%5Cbeta_%7B%5Ctext%7Bclima%7D%7D%7D">.</p>
</section>
</section>
<section id="ajustar-el-modelo-predictivo" class="level2">
<h2 class="anchored" data-anchor-id="ajustar-el-modelo-predictivo">Ajustar el modelo predictivo</h2>
<p>El modelo de <code>scikit-learn</code> tendrá un propósito predictivo: aprende únicamente con entrenamiento y se evalúa sobre prueba. <code>PoissonRegressor</code> incluye una penalización L2 —la misma idea de Ridge del artículo de regularización— cuya intensidad controla <code>alpha</code>. Su valor por defecto, <code>alpha=1.0</code>, no tiene nada de especial para estos datos, así que lo tratamos como cualquier hiperparámetro: lo elegimos por <strong>validación cruzada (CV)</strong> con 5 particiones (<em>folds</em>) <strong>solo sobre el entrenamiento</strong>, en una malla de 11 valores entre <img src="https://latex.codecogs.com/png.latex?10%5E%7B-4%7D"> y <img src="https://latex.codecogs.com/png.latex?10">. Antes estandarizamos los predictores, porque la penalización L2 depende de la escala: sin estandarizar, contraería mucho más el coeficiente del clima (una variable 0/1) que el de la longitud (medida en km).</p>
<p>Para evaluar usamos la <strong>deviance media de Poisson</strong>, que compara cada conteo observado <img src="https://latex.codecogs.com/png.latex?y_i"> con su tasa predicha <img src="https://latex.codecogs.com/png.latex?%5Chat%5Clambda_i">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AD=%5Cfrac%7B2%7D%7Bn%7D%5Csum_%7Bi=1%7D%5E%7Bn%7D%5Cleft%5By_i%5Clog%5Cfrac%7By_i%7D%7B%5Chat%5Clambda_i%7D-(y_i-%5Chat%5Clambda_i)%5Cright%5D,%0A"></p>
<p>con la convención <img src="https://latex.codecogs.com/png.latex?y_i%5Clog(y_i/%5Chat%5Clambda_i)=0"> cuando <img src="https://latex.codecogs.com/png.latex?y_i=0">. Vale 0 si cada predicción coincide con su conteo y crece con la discrepancia: cuanto menor, mejor. La complementamos con el <strong>error absoluto medio (MAE)</strong>, el promedio de <img src="https://latex.codecogs.com/png.latex?%7Cy_i-%5Chat%5Clambda_i%7C">, que se lee directamente en incidencias por ruta.</p>
<div id="d28ee21a" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:38.624945Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:38.624744Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:43.883483Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:43.882132Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1">alphas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.logspace(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>)</span>
<span id="cb11-2">busqueda <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> GridSearchCV(</span>
<span id="cb11-3">    make_pipeline(StandardScaler(), PoissonRegressor(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>)),</span>
<span id="cb11-4">    {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'poissonregressor__alpha'</span>: alphas},</span>
<span id="cb11-5">    cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>KFold(n_splits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA),</span>
<span id="cb11-6">    scoring<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'neg_mean_poisson_deviance'</span>,</span>
<span id="cb11-7">).fit(X_tr, y_tr)</span>
<span id="cb11-8">modelo_predictivo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> busqueda.best_estimator_</span>
<span id="cb11-9">pred_poisson_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_predictivo.predict(X_te)</span>
<span id="cb11-10"></span>
<span id="cb11-11">alpha_opt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> busqueda.best_params_[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'poissonregressor__alpha'</span>]</span>
<span id="cb11-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'alpha elegido por CV: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>alpha_opt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4g}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> (rango probado: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>alphas[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0e}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>alphas[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0e}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb11-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'¿Cae en el borde del rango?'</span>, alpha_opt <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> (alphas[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], alphas[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]))</span>
<span id="cb11-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Deviance media de CV con ese alpha: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>busqueda<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>best_score_<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb11-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Predicción mínima en prueba: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pred_poisson_te<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb11-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Predicción máxima en prueba: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pred_poisson_te<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb11-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Deviance de Poisson en prueba: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mean_poisson_deviance(y_te, pred_poisson_te)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb11-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'MAE en prueba: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mean_absolute_error(y_te, pred_poisson_te)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>alpha elegido por CV: 0.01 (rango probado: 1e-04 a 1e+01)
¿Cae en el borde del rango? False
Deviance media de CV con ese alpha: 1.052
Predicción mínima en prueba: 0.490
Predicción máxima en prueba: 10.140
Deviance de Poisson en prueba: 1.063
MAE en prueba: 1.216</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-3" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-3">Cómo leer este resultado</h3>
<p>La validación cruzada eligió <img src="https://latex.codecogs.com/png.latex?%5Calpha="> 0.01, dentro del rango probado y no en su borde: una penalización pequeña, razonable con solo dos predictores y 490 rutas de entrenamiento.</p>
<p>Todas las predicciones de prueba son positivas —entre 0.490 y 10.140 incidencias— porque el modelo regresa a la escala de conteos mediante la exponencial. En prueba, la deviance media es 1.063 y el MAE, 1.216 incidencias por ruta; en la sección del baseline veremos si eso es mucho o poco.</p>
<p>Este modelo sirve para generar predicciones, no para construir p-valores; de eso se encarga el modelo inferencial de más adelante.</p>
</section>
</section>
<section id="visualizar-la-tasa-ajustada" class="level2">
<h2 class="anchored" data-anchor-id="visualizar-la-tasa-ajustada">Visualizar la tasa ajustada</h2>
<p>Dibujaremos la tasa esperada según longitud para clima normal y adverso. Los puntos son conteos observados, por eso permanecen dispersos alrededor de cada curva: el modelo estima la <strong>media condicional</strong>, no pretende pasar por cada observación.</p>
<div id="489f02af" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:43.886699Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:43.886208Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:44.028167Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:44.027337Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">longitud_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>)</span>
<span id="cb13-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> indicador_clima, color, etiqueta <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [</span>
<span id="cb13-3">    (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clima normal'</span>),</span>
<span id="cb13-4">    (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clima adverso'</span>),</span>
<span id="cb13-5">]:</span>
<span id="cb13-6">    X_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([longitud_grid, np.full_like(longitud_grid, indicador_clima)])</span>
<span id="cb13-7">    tasa_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_predictivo.predict(X_grid)</span>
<span id="cb13-8">    plt.plot(longitud_grid, tasa_grid, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>etiqueta)</span>
<span id="cb13-9">    mascara <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> clima_adverso <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> indicador_clima</span>
<span id="cb13-10">    plt.scatter(longitud[mascara], y[mascara], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.15</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color)</span>
<span id="cb13-11"></span>
<span id="cb13-12">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud de la ruta (km)'</span>)</span>
<span id="cb13-13">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'incidencias observadas / tasa esperada'</span>)</span>
<span id="cb13-14">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Tasa estimada según longitud y clima'</span>)</span>
<span id="cb13-15">plt.legend()</span>
<span id="cb13-16">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/10-regresion-poisson/index_files/figure-html/cell-10-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-estas-curvas" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estas-curvas">Cómo leer estas curvas</h3>
<p>La tasa aumenta con la longitud y la curva de clima adverso queda por encima de la curva de clima normal. La separación es multiplicativa: a igual longitud, pasar a clima adverso multiplica la tasa por un factor constante, <img src="https://latex.codecogs.com/png.latex?e%5E%7B%5Cbeta_%7B%5Ctext%7Bclima%7D%7D%7D">. Como el eje vertical está en escala de conteos (no logarítmica), ese mismo factor se ve como una distancia entre curvas que crece con la longitud. La dispersión vertical de los puntos recuerda que una tasa esperada no es una predicción exacta del conteo individual.</p>
</section>
</section>
<section id="modelo-inferencial-y-cocientes-de-tasas" class="level2">
<h2 class="anchored" data-anchor-id="modelo-inferencial-y-cocientes-de-tasas">Modelo inferencial y cocientes de tasas</h2>
<p>Ajustamos con <code>statsmodels</code> un GLM de Poisson sobre el <strong>mismo conjunto de entrenamiento</strong>. Su propósito es inferencial: estimar coeficientes, cocientes de tasas de incidencia (IRR) y p-valores.</p>
<p>El modelo predictivo de scikit-learn usa una penalización L2 (pequeña, elegida por CV) sobre predictores estandarizados; este GLM de statsmodels no regulariza y trabaja con las variables en sus unidades originales. Aunque ambos reciben las mismas observaciones, sus coeficientes no son directamente comparables; lo comparable son sus predicciones. Para una variable <img src="https://latex.codecogs.com/png.latex?x_j">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Coperatorname%7BIRR%7D_j=e%5E%7B%5Cbeta_j%7D.%0A"></p>
<p>Un cambio de <img src="https://latex.codecogs.com/png.latex?d"> unidades multiplica la tasa por <img src="https://latex.codecogs.com/png.latex?e%5E%7Bd%5Cbeta_j%7D=(e%5E%7B%5Cbeta_j%7D)%5Ed">.</p>
<div id="8c3f7c44" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:44.029911Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:44.029698Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:44.041196Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:44.040446Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">X_tr_sm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sm.add_constant(X_tr)</span>
<span id="cb14-2">modelo_inferencial <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sm.GLM(</span>
<span id="cb14-3">    y_tr, X_tr_sm, family<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>sm.families.Poisson()</span>
<span id="cb14-4">).fit()</span>
<span id="cb14-5"></span>
<span id="cb14-6">nombres <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'intercepto'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clima_adverso'</span>]</span>
<span id="cb14-7">coeficientes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(modelo_inferencial.params, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres)</span>
<span id="cb14-8">irr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(coeficientes)</span>
<span id="cb14-9">p_valores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(modelo_inferencial.pvalues, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres)</span>
<span id="cb14-10"></span>
<span id="cb14-11">tabla_inferencia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb14-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'coeficiente'</span>: coeficientes,</span>
<span id="cb14-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IRR'</span>: irr,</span>
<span id="cb14-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'p-valor'</span>: p_valores,</span>
<span id="cb14-15">})</span>
<span id="cb14-16">display(tabla_inferencia.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb14-17"></span>
<span id="cb14-18">irr_10_km <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> coeficientes[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud'</span>])</span>
<span id="cb14-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'IRR acumulado para 10 km adicionales: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>irr_10_km<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">coeficiente</th>
<th data-quarto-table-cell-role="th">IRR</th>
<th data-quarto-table-cell-role="th">p-valor</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">intercepto</th>
<td>-0.9907</td>
<td>0.3713</td>
<td>0.0</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">longitud</th>
<td>0.0460</td>
<td>1.0471</td>
<td>0.0</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">clima_adverso</th>
<td>0.5675</td>
<td>1.7638</td>
<td>0.0</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>IRR acumulado para 10 km adicionales: 1.585</code></pre>
</div>
</div>
<section id="cómo-leer-estos-cocientes-de-tasas" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estos-cocientes-de-tasas">Cómo leer estos cocientes de tasas</h3>
<p>En el GLM inferencial, cada kilómetro adicional multiplica la tasa esperada por 1.047, es decir, la aumenta cerca de 4.7% manteniendo fijo el clima. Al acumular 10 km, el factor es 1.585: aproximadamente 58.5% más. A igual longitud, el clima adverso multiplica la tasa por 1.764, cerca de 76.4% más que el clima normal. Como los datos son simulados, puedes contrastarlo con la regla oculta: <img src="https://latex.codecogs.com/png.latex?e%5E%7B0.045%7D%5Capprox1.046"> por kilómetro y <img src="https://latex.codecogs.com/png.latex?e%5E%7B0.6%7D%5Capprox1.822"> para el clima; el modelo recupera ambos efectos con buena aproximación.</p>
<p>Los p-valores son tan pequeños que la tabla los muestra como 0.0 al redondear a cuatro decimales; aportan evidencia contra la hipótesis de coeficiente nulo bajo los supuestos del modelo; no demuestran causalidad ni importancia práctica. Tampoco corresponde ordenar cuál factor es “más importante” comparando cambios expresados en unidades diferentes.</p>
<p>Esta interpretación corresponde al modelo sin regularización ajustado en entrenamiento, y sus errores estándar y p-valores suponen equidispersión: la verificamos en la sección de dispersión. A continuación, los perfiles usan el modelo predictivo; como su penalización es pequeña, sus predicciones quedan muy cerca de las del GLM.</p>
</section>
</section>
<section id="tasas-esperadas-para-rutas-concretas" class="level2">
<h2 class="anchored" data-anchor-id="tasas-esperadas-para-rutas-concretas">Tasas esperadas para rutas concretas</h2>
<p>Comparamos rutas cortas, medias y largas bajo clima normal y adverso. Esta tabla lleva los coeficientes a la escala que necesita quien toma decisiones: número esperado de incidencias por ruta.</p>
<div id="d2ffc24e" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:44.043009Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:44.042811Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:44.053725Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:44.052952Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">perfiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb16-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tipo_ruta'</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'corta'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'corta'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'media'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'media'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'larga'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'larga'</span>],</span>
<span id="cb16-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud_km'</span>: [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">55</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">55</span>],</span>
<span id="cb16-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clima'</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'normal'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'adverso'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'normal'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'adverso'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'normal'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'adverso'</span>],</span>
<span id="cb16-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clima_adverso'</span>: [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb16-6">})</span>
<span id="cb16-7">X_perfiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> perfiles[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud_km'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clima_adverso'</span>]].to_numpy()</span>
<span id="cb16-8">perfiles[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'incidencias_esperadas'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_predictivo.predict(X_perfiles)</span>
<span id="cb16-9">display(perfiles[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tipo_ruta'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'longitud_km'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clima'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'incidencias_esperadas'</span>]].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">tipo_ruta</th>
<th data-quarto-table-cell-role="th">longitud_km</th>
<th data-quarto-table-cell-role="th">clima</th>
<th data-quarto-table-cell-role="th">incidencias_esperadas</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>corta</td>
<td>10</td>
<td>normal</td>
<td>0.594</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>corta</td>
<td>10</td>
<td>adverso</td>
<td>1.044</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>media</td>
<td>30</td>
<td>normal</td>
<td>1.484</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>media</td>
<td>30</td>
<td>adverso</td>
<td>2.611</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>larga</td>
<td>55</td>
<td>normal</td>
<td>4.665</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">5</th>
<td>larga</td>
<td>55</td>
<td>adverso</td>
<td>8.209</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-estos-perfiles" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estos-perfiles">Cómo leer estos perfiles</h3>
<p>En el modelo predictivo, una ruta de 30 km pasa de 1.484 incidencias esperadas con clima normal a 2.611 con clima adverso. Para 55 km, las predicciones son 4.665 y 8.209, respectivamente. En ambas longitudes el cociente adverso/normal es el mismo, cerca de 1.76, próximo al IRR de 1.764 del GLM: el clima actúa como un factor multiplicativo constante.</p>
<p>Estas cifras son <strong>medias esperadas</strong>: predecir 2.611 incidencias no significa observar una fracción de incidencia, sino que muchas rutas comparables promediarían aproximadamente 2.611 eventos.</p>
</section>
</section>
<section id="comparar-contra-un-baseline" class="level2">
<h2 class="anchored" data-anchor-id="comparar-contra-un-baseline">Comparar contra un baseline</h2>
<p>Una métrica aislada no dice si el modelo aporta valor. El baseline más simple ignora longitud y clima y predice para todas las rutas la media de conteos observada en entrenamiento. Compararemos ambos con la misma deviance de Poisson y con MAE sobre prueba.</p>
<div id="789e7d7f" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:44.055681Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:44.055481Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:44.065060Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:44.064346Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1">pred_baseline <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.full(y_te.shape, y_tr.mean(), dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb17-2"></span>
<span id="cb17-3">deviance_modelo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mean_poisson_deviance(y_te, pred_poisson_te)</span>
<span id="cb17-4">deviance_baseline <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mean_poisson_deviance(y_te, pred_baseline)</span>
<span id="cb17-5">mae_modelo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mean_absolute_error(y_te, pred_poisson_te)</span>
<span id="cb17-6">mae_baseline <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mean_absolute_error(y_te, pred_baseline)</span>
<span id="cb17-7">reduccion_deviance <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> deviance_modelo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> deviance_baseline</span>
<span id="cb17-8"></span>
<span id="cb17-9">tabla_comparacion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb17-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'modelo'</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'media de entrenamiento'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'regresión de Poisson'</span>],</span>
<span id="cb17-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'deviance_poisson'</span>: [deviance_baseline, deviance_modelo],</span>
<span id="cb17-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MAE'</span>: [mae_baseline, mae_modelo],</span>
<span id="cb17-13">})</span>
<span id="cb17-14">display(tabla_comparacion.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb17-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Reducción relativa de deviance frente al baseline: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>reduccion_deviance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">modelo</th>
<th data-quarto-table-cell-role="th">deviance_poisson</th>
<th data-quarto-table-cell-role="th">MAE</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>media de entrenamiento</td>
<td>2.553</td>
<td>2.123</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>regresión de Poisson</td>
<td>1.063</td>
<td>1.216</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Reducción relativa de deviance frente al baseline: 58.4%</code></pre>
</div>
</div>
<section id="cómo-leer-esta-comparación" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-comparación">Cómo leer esta comparación</h3>
<p>En prueba, la regresión de Poisson reduce la deviance de 2.553 a 1.063 y el MAE de 2.123 a 1.216 frente al baseline. La reducción relativa de deviance es 58.4%, de modo que longitud y clima sí aportan información predictiva fuera de entrenamiento.</p>
<p>Ese 58.4% mide mejora respecto a esta referencia concreta; no es un porcentaje de incidencias explicadas ni garantiza el mismo desempeño en otra población.</p>
</section>
</section>
<section id="revisar-el-supuesto-de-dispersión" class="level2">
<h2 class="anchored" data-anchor-id="revisar-el-supuesto-de-dispersión">Revisar el supuesto de dispersión</h2>
<p>En una Poisson ideal, la varianza condicional coincide con la media condicional. Una comprobación diagnóstica habitual es la razón de dispersión de Pearson:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cwidehat%5Cphi=%5Cfrac%7B%5Cchi%5E2_%7B%5Ctext%7BPearson%7D%7D%7D%7B%5Ctext%7Bgrados%20de%20libertad%20residuales%7D%7D.%0A"></p>
<p>Valores cercanos a 1 son compatibles con la dispersión Poisson; valores claramente mayores sugieren sobredispersión y la necesidad de revisar el modelo o considerar alternativas como binomial negativa.</p>
<div id="b45c73ec" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:44.067341Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:44.066977Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:44.147847Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:44.147198Z&quot;}}" data-execution_count="13">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1">dispersion_pearson <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_inferencial.pearson_chi2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> modelo_inferencial.df_resid</span>
<span id="cb19-2">ajuste_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_inferencial.fittedvalues</span>
<span id="cb19-3">residuos_pearson <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_inferencial.resid_pearson</span>
<span id="cb19-4"></span>
<span id="cb19-5">plt.scatter(ajuste_train, residuos_pearson, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb19-6">plt.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>)</span>
<span id="cb19-7">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa ajustada en entrenamiento'</span>)</span>
<span id="cb19-8">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'residuo de Pearson'</span>)</span>
<span id="cb19-9">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Residuos de Pearson frente a la tasa ajustada'</span>)</span>
<span id="cb19-10">plt.show()</span>
<span id="cb19-11"></span>
<span id="cb19-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Razón de dispersión de Pearson: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>dispersion_pearson<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/10-regresion-poisson/index_files/figure-html/cell-14-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Razón de dispersión de Pearson: 0.983</code></pre>
</div>
</div>
<section id="cómo-leer-este-diagnóstico" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-diagnóstico">Cómo leer este diagnóstico</h3>
<p>La razón de dispersión de Pearson es 0.983, muy próxima a 1; no aparece una señal global de sobredispersión en este ejemplo. Compárala con los datos crudos del inicio, donde la varianza (7.544) era unas 2.6 veces la media (2.934): ese exceso aparente venía de mezclar rutas con tasas distintas y desaparece cuando el modelo tiene en cuenta la longitud y el clima. Las bandas curvas del gráfico son esperables porque el conteo observado solo toma valores enteros, mientras la tasa ajustada es continua.</p>
<p>Este diagnóstico es orientativo, no una prueba automática. Una razón claramente superior a 1 o una estructura adicional de los residuos indicaría variabilidad o patrones que la Poisson no está capturando.</p>
</section>
</section>
<section id="errores-comunes-en-regresión-de-poisson" class="level2">
<h2 class="anchored" data-anchor-id="errores-comunes-en-regresión-de-poisson">Errores comunes en regresión de Poisson</h2>
<ol type="1">
<li><strong>Tratar cualquier entero como conteo Poisson.</strong> Debe representar eventos no negativos observados bajo una exposición comparable.</li>
<li><strong>Interpretar <img src="https://latex.codecogs.com/png.latex?%5Cbeta_j"> como cambio aditivo en incidencias.</strong> El efecto es multiplicativo sobre la tasa; se interpreta con <img src="https://latex.codecogs.com/png.latex?e%5E%7B%5Cbeta_j%7D">.</li>
<li><strong>Comparar IRR de variables con unidades distintas como si midieran importancia.</strong> Primero fija cambios relevantes, como 10 km frente a un cambio de clima.</li>
<li><strong>Reportar una deviance sin modelo de referencia (<em>baseline</em>).</strong> El modelo debe superar una predicción trivial sobre datos de prueba.</li>
<li><strong>Usar p-valores como prueba causal.</strong> Dependen de los supuestos y no sustituyen el tamaño ni la relevancia práctica del efecto.</li>
<li><strong>Ignorar la sobredispersión.</strong> Si la variabilidad excede claramente lo permitido por Poisson, los errores estándar y conclusiones pueden ser inadecuados.</li>
<li><strong>Confundir tasa esperada con conteo observado.</strong> Una predicción como 2.4 es una media para rutas comparables, no una incidencia fraccionaria.</li>
<li><strong>Olvidar la exposición.</strong> Si unas rutas representan más tiempo o distancia de observación que otras, puede necesitarse un <em>offset</em>.</li>
</ol>
</section>
<section id="lo-que-debes-llevarte-de-este-artículo" class="level2">
<h2 class="anchored" data-anchor-id="lo-que-debes-llevarte-de-este-artículo">Lo que debes llevarte de este artículo</h2>
<p>La cadena completa es:</p>
<pre class="text"><code>respuesta de conteo
→ distribución Poisson
→ predictor lineal η = Xβ
→ enlace log
→ tasa esperada λ = exp(η)</code></pre>
<p>La exponencial garantiza tasas positivas. Los coeficientes se interpretan mediante IRR, el modelo predictivo se evalúa en prueba contra un baseline y el supuesto de dispersión debe revisarse antes de confiar en la inferencia.</p>
</section>
<section id="cierre-técnico" class="level2">
<h2 class="anchored" data-anchor-id="cierre-técnico">Cierre técnico</h2>
<p>La regresión de Poisson conserva el predictor lineal, pero adapta la distribución y el enlace a una respuesta de conteo. El paralelo queda así:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Modelo</th>
<th>Distribución</th>
<th>Enlace</th>
<th>Escala de salida</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Logística</td>
<td>Bernoulli</td>
<td>logit</td>
<td>probabilidad</td>
</tr>
<tr class="even">
<td>Poisson</td>
<td>Poisson</td>
<td>log</td>
<td>tasa esperada</td>
</tr>
</tbody>
</table>
<p>Esa estructura común permite cambiar el tipo de respuesta sin abandonar el lenguaje de los GLM.</p>
</section>
<section id="qué-sigue" class="level2">
<h2 class="anchored" data-anchor-id="qué-sigue">¿Qué sigue?</h2>
<p>Hasta aquí, longitud y clima entran con efectos lineales en la escala log. Pero una relación real puede curvarse: quizá el riesgo crece lentamente en rutas medianas y se acelera en rutas muy largas.</p>
<p>Los <strong>modelos aditivos generalizados (GAM)</strong> combinan dos ideas que ya viste en la serie: la distribución y el enlace de un GLM con la flexibilidad local de los splines. El siguiente paso será permitir efectos no lineales sin perder la estructura interpretable del modelo.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>glm</category>
  <category>regresion-poisson</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/avanzado/10-regresion-poisson/</guid>
  <pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Análisis Avanzado de Datos — 10. Modelos aditivos generalizados (GAM)</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/avanzado/11-modelos-aditivos-gam/</link>
  <description><![CDATA[ 




<section id="análisis-avanzado-de-datos-10.-modelos-aditivos-generalizados-gam" class="level1">
<h1>Análisis Avanzado de Datos — 10. Modelos aditivos generalizados (GAM)</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado convierte datos en decisiones. Científico de Datos, Arquitecto de IA y asesor tecnológico con más de 20 años de experiencia en analítica avanzada, machine learning, Big Data e IoT. Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), asesora a entidades gubernamentales y empresas privadas en Colombia y es referente en analítica y normatividad para los sectores postal y logístico del país. Una serie pensada para ir de la teoría a la práctica, con ejemplos concretos en cada paso.</p>
<p>📌 <em>Parte de la serie <strong>Análisis Avanzado de Datos</strong>.</em></p>
</section>
<section id="cuando-el-efecto-no-es-una-recta" class="level2">
<h2 class="anchored" data-anchor-id="cuando-el-efecto-no-es-una-recta">Cuando el efecto no es una recta</h2>
<p>En los artículos anteriores el GLM te dio una arquitectura clara: eliges una <strong>distribución</strong> para <img src="https://latex.codecogs.com/png.latex?Y">, una <strong>función de enlace</strong> y un <strong>predictor lineal</strong>. Eso cubre el sí/no (logística) y los conteos (Poisson). La pieza que queda rígida es el predictor: cada variable entra con una pendiente constante. Si el efecto <strong>sube y luego baja</strong>, esa recta no tiene cómo contarlo. Es la pregunta que dejó abierta el artículo de Poisson: un riesgo que crece despacio en rutas medianas y se acelera en las muy largas.</p>
<p>Los <strong>splines</strong> del artículo de suavización ya resolvieron la forma flexible para una media continua. Un <strong>modelo aditivo generalizado (GAM)</strong> junta las dos ideas: conserva la distribución y el enlace del GLM, pero reemplaza el predictor lineal por una <strong>suma de funciones suaves</strong>. El resultado sigue siendo interpretable —puedes dibujar el efecto de cada variable— y ya no exige que ese efecto sea monótono.</p>
</section>
<section id="objetivos-de-aprendizaje" class="level2">
<h2 class="anchored" data-anchor-id="objetivos-de-aprendizaje">Objetivos de aprendizaje</h2>
<p>Al terminar este notebook vas a ser capaz de:</p>
<ul>
<li><strong>Escribir</strong> un GAM como un GLM en el que el predictor lineal se reemplaza por una suma de funciones suaves.</li>
<li><strong>Reconocer</strong> un efecto no monótono en los datos y explicar por qué una logística lineal no puede capturarlo.</li>
<li><strong>Conectar</strong> el spline de la suavización con el ingrediente que le da flexibilidad al GLM.</li>
<li><strong>Elegir</strong> el número de nodos (<em>knots</em>) del spline por validación cruzada sobre el entrenamiento, sin usar el conjunto de prueba.</li>
<li><strong>Comparar</strong> de forma justa un GLM lineal, un GAM y un modelo de referencia trivial (<em>baseline</em>) sobre datos reservados.</li>
<li><strong>Leer</strong> la curva del efecto parcial: dónde sube, dónde baja y qué implica para el problema.</li>
<li><strong>Interpretar</strong> con prudencia un contraste de verosimilitud entre el predictor lineal y el suave, sin confundirlo con causalidad.</li>
</ul>
</section>
<section id="el-gam-como-un-glm-con-predictor-suave" class="level2">
<h2 class="anchored" data-anchor-id="el-gam-como-un-glm-con-predictor-suave">El GAM como un GLM con predictor suave</h2>
<p>Un modelo lineal generalizado combina tres piezas: la distribución de <img src="https://latex.codecogs.com/png.latex?Y">, un predictor y una función de enlace <img src="https://latex.codecogs.com/png.latex?g"> que conecta la media con ese predictor. En el GLM clásico el predictor es lineal:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ag(%5Cmathbb%7BE%7D%5BY%5D)=%5Cbeta_0+%5Cbeta_1%20x_1+%5Cbeta_2%20x_2+%5Ccdots%0A"></p>
<p>Un GAM cambia <strong>una sola pieza</strong>: cada término <img src="https://latex.codecogs.com/png.latex?%5Cbeta_j%20x_j"> puede volverse una función suave <img src="https://latex.codecogs.com/png.latex?f_j">, estimada con un spline:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ag(%5Cmathbb%7BE%7D%5BY%5D)=%5Cbeta_0+f_1(x_1)+f_2(x_2)+%5Ccdots%0A"></p>
<p>Cada <img src="https://latex.codecogs.com/png.latex?f_j"> es flexible: no fijas de antemano que el efecto sea una recta ni una parábola. El spline aprende la forma a partir de los datos, con la cantidad de flexibilidad que tú controles —aquí, con el número de knots.</p>
<p>Lo que <strong>no</strong> cambia es el resto del GLM. Si <img src="https://latex.codecogs.com/png.latex?Y"> es binaria, sigues usando Bernoulli y el enlace logit. Si <img src="https://latex.codecogs.com/png.latex?Y"> es un conteo, sigues usando Poisson y el enlace log. El GAM no es una familia distinta: es el mismo esqueleto con un predictor aditivo en lugar de uno lineal.</p>
<section id="de-glm-lineal-a-gam" class="level3">
<h3 class="anchored" data-anchor-id="de-glm-lineal-a-gam">De GLM lineal a GAM</h3>
<p>El camino es una sola flecha:</p>
<p><strong>GLM</strong> (logística, Poisson: distribución + enlace + predictor lineal) <img src="https://latex.codecogs.com/png.latex?%5Crightarrow"> <strong>añade forma flexible</strong> (cada <img src="https://latex.codecogs.com/png.latex?x_j"> entra con un spline <img src="https://latex.codecogs.com/png.latex?f_j">) <img src="https://latex.codecogs.com/png.latex?%5Crightarrow"> <strong>GAM</strong>.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Pieza</th>
<th>GLM lineal (logística, Poisson)</th>
<th>GAM</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Distribución de <img src="https://latex.codecogs.com/png.latex?Y"></td>
<td>Bernoulli, Poisson, …</td>
<td>la misma</td>
</tr>
<tr class="even">
<td>Función de enlace <img src="https://latex.codecogs.com/png.latex?g"></td>
<td>logit, log, …</td>
<td>la misma</td>
</tr>
<tr class="odd">
<td>Predictor</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Cbeta_0+%5Cbeta_1%20x_1+%5Cbeta_2%20x_2+%5Ccdots"></td>
<td><img src="https://latex.codecogs.com/png.latex?%5Cbeta_0+f_1(x_1)+f_2(x_2)+%5Ccdots"></td>
</tr>
<tr class="even">
<td>Forma de cada efecto</td>
<td>recta en la escala del enlace</td>
<td>curva suave (spline)</td>
</tr>
<tr class="odd">
<td>Qué estima</td>
<td>probabilidad del sí (logística), tasa esperada de eventos (Poisson)</td>
<td>lo mismo, con forma flexible</td>
</tr>
<tr class="even">
<td>Qué interpretas</td>
<td>un número (el coeficiente)</td>
<td>una función (el efecto parcial)</td>
</tr>
</tbody>
</table>
<p>La aditividad es lo que conserva la interpretabilidad. Como las <img src="https://latex.codecogs.com/png.latex?f_j"> se suman, puedes dibujar <img src="https://latex.codecogs.com/png.latex?f_1"> contra <img src="https://latex.codecogs.com/png.latex?x_1"> dejando fijas las demás variables y <strong>leer el efecto de esa variable a lo largo de su rango</strong>. Una caja negra puede acertar predicciones sin mostrarte dónde el efecto sube o baja; el GAM te deja ver esa forma. Por eso es la herramienta natural cuando sospechas no linealidad y aún quieres explicar el resultado, no solo predecirlo.</p>
<p>En este artículo nos concentramos en una respuesta binaria y <strong>una</strong> variable continua, para que la curva se vea sin mezclas. La fórmula de arriba sigue valiendo con varias <img src="https://latex.codecogs.com/png.latex?f_j">; cada una se dibuja por separado.</p>
<p>Aunque cambie la respuesta, el enlace o la forma del predictor, la cadena conceptual es la misma. Ahora vamos a un caso donde esa forma flexible no es un lujo: es la diferencia entre un modelo casi inútil y uno que describe lo que ocurre.</p>
</section>
</section>
<section id="preparación-del-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparación-del-entorno">Preparación del entorno</h2>
<p>Cargamos scikit-learn para ajustar y comparar modelos predictivos, statsmodels para la inferencia del final y una constante global <code>SEMILLA</code> que fija toda la aleatoriedad del artículo.</p>
<div id="cda004c7" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:38.410726Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:38.410531Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:41.348081Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:41.347324Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split, StratifiedKFold</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LogisticRegression</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> SplineTransformer</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.pipeline <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_pipeline</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> roc_auc_score, accuracy_score, roc_curve</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> statsmodels.api <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sm</span>
<span id="cb1-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy.stats <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> chi2</span>
<span id="cb1-11"></span>
<span id="cb1-12">SEMILLA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2026</span></span>
<span id="cb1-13">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb1-14">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'figure.figsize'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span></code></pre></div></div>
</div>
</section>
<section id="los-datos-conversión-según-la-edad" class="level2">
<h2 class="anchored" data-anchor-id="los-datos-conversión-según-la-edad">Los datos: conversión según la edad</h2>
<p>Simulamos 900 clientes. De cada uno conocemos la <strong>edad</strong> y si <strong>convierte</strong> (compra: 1) o no (0). La regla oculta es deliberada: la probabilidad de conversión <strong>sube hacia las edades intermedias y baja en los extremos</strong> —un pico, no una rampa. En la práctica no conoces esa regla; la infieres de lo que observas.</p>
<p>Ese patrón no monótono es el escenario donde el GAM demuestra su valor. Un modelo que asuma “a más edad, siempre más (o siempre menos) conversión” va a chocar con los datos.</p>
<div id="d41551d5" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:41.350616Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:41.350230Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:41.365184Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:41.364513Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">900</span></span>
<span id="cb2-2">edad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">75</span>, n)</span>
<span id="cb2-3"></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Regla oculta: log-odds sube y baja con la edad (pico, no rampa).</span></span>
<span id="cb2-5">logit_real <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> edad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0034</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> edad<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb2-6">prob_real <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>logit_real))</span>
<span id="cb2-7">convierte <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.binomial(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, prob_real)</span>
<span id="cb2-8"></span>
<span id="cb2-9">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> edad.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-10">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> convierte</span>
<span id="cb2-11"></span>
<span id="cb2-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> clientes | tasa de conversión: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Convierten: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(y.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | no convierten: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>((<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-14">pd.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'edad'</span>: edad[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'convierte'</span>: y[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]}).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>900 clientes | tasa de conversión: 44.4%
Convierten: 400 | no convierten: 500</code></pre>
</div>
<div class="cell-output cell-output-display" data-execution_count="2">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">edad</th>
<th data-quarto-table-cell-role="th">convierte</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>28.199</td>
<td>1</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>54.475</td>
<td>0</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>44.634</td>
<td>1</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>39.119</td>
<td>1</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>38.230</td>
<td>1</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-este-resultado" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado">Cómo leer este resultado</h3>
<p>La tasa global de conversión es <strong>44.4%</strong>: 400 clientes convierten y 500 no. Las clases están razonablemente equilibradas, así que una regla ingenua (“nadie convierte”) acertaría el 55.6% de las veces —ese será el baseline más adelante.</p>
<p>La variable respuesta es 0 o 1. El predictor es una edad continua entre 18 y 75 años. Lo que todavía no ves es <em>cómo</em> se relaciona la conversión con la edad. Para eso hay que mirar la tasa <strong>por tramos</strong>, no el promedio global.</p>
</section>
</section>
<section id="la-tasa-observada-no-es-monótona" class="level2">
<h2 class="anchored" data-anchor-id="la-tasa-observada-no-es-monótona">La tasa observada no es monótona</h2>
<p>Si el efecto de la edad fuera una rampa, al agrupar por tramos verías una secuencia que siempre sube o siempre baja. Calculemos la tasa de conversión en ventanas de 7 años, de 18 a 74 (los 17 clientes de 74 a 75 años quedan fuera de los tramos), y dibujémosla.</p>
<div id="cc95fe56" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:41.367330Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:41.367024Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:41.478907Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:41.478233Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">bins <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">81</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>)</span>
<span id="cb4-2">centros <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (bins[:<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> bins[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb4-3">tasas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-4">ns <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> a, b <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(bins[:<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], bins[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:]):</span>
<span id="cb4-6">    mascara <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (edad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> a) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (edad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> b)</span>
<span id="cb4-7">    ns.append(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(mascara.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()))</span>
<span id="cb4-8">    tasas.append(y[mascara].mean())</span>
<span id="cb4-9"></span>
<span id="cb4-10">tabla_tramos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb4-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'edad (centro)'</span>: centros,</span>
<span id="cb4-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'n'</span>: ns,</span>
<span id="cb4-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa observada'</span>: tasas,</span>
<span id="cb4-14">})</span>
<span id="cb4-15">display(tabla_tramos.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb4-16"></span>
<span id="cb4-17">plt.plot(centros, tasas, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb4-18">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'edad'</span>)</span>
<span id="cb4-19">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa de conversión observada'</span>)</span>
<span id="cb4-20">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'El efecto de la edad no es monótono: sube y baja'</span>)</span>
<span id="cb4-21">plt.ylim(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb4-22">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">edad (centro)</th>
<th data-quarto-table-cell-role="th">n</th>
<th data-quarto-table-cell-role="th">tasa observada</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>21.5</td>
<td>98</td>
<td>0.276</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>28.5</td>
<td>98</td>
<td>0.490</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>35.5</td>
<td>97</td>
<td>0.608</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>42.5</td>
<td>104</td>
<td>0.663</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>49.5</td>
<td>137</td>
<td>0.650</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">5</th>
<td>56.5</td>
<td>103</td>
<td>0.447</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">6</th>
<td>63.5</td>
<td>127</td>
<td>0.346</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">7</th>
<td>70.5</td>
<td>119</td>
<td>0.151</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/11-modelos-aditivos-gam/index_files/figure-html/cell-4-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-1">Cómo leer este resultado</h3>
<p>La tasa <strong>sube hasta un máximo y después cae</strong>. En el tramo de 18–25 años convierte el <strong>27.6%</strong>; hacia 39–46 años llega al <strong>66.3%</strong>; en 67–74 años baja al <strong>15.1%</strong>. No es una pendiente: es un pico, con el máximo observado entre los 39 y los 53 años (<strong>66.3%</strong> y <strong>65.0%</strong> en los dos tramos centrales).</p>
<p>Ese es el detalle que lo cambia todo. Un modelo obligado a elegir una sola dirección —siempre más conversión con la edad, o siempre menos— no puede seguir una curva que cambia de sentido. Veamos el fracaso de esa herramienta antes de cambiar de idea.</p>
</section>
</section>
<section id="entrenamiento-y-prueba-antes-de-modelar" class="level2">
<h2 class="anchored" data-anchor-id="entrenamiento-y-prueba-antes-de-modelar">Entrenamiento y prueba, antes de modelar</h2>
<p>Separamos el 30% de los clientes como conjunto de <strong>prueba</strong> y lo reservamos. Todo ajuste, toda comparación de complejidad y toda validación cruzada ocurrirán <strong>solo en entrenamiento</strong>. La prueba entra al final, una vez, para reportar.</p>
<div id="91093047" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:41.481316Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:41.481116Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:41.503051Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:41.502258Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">X_tr, X_te, y_tr, y_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(</span>
<span id="cb5-2">    X, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA, stratify<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y</span>
<span id="cb5-3">)</span>
<span id="cb5-4">edad_tr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_tr.ravel()</span>
<span id="cb5-5">edad_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_te.ravel()</span>
<span id="cb5-6"></span>
<span id="cb5-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Entrenamiento: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_tr)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> clientes | tasa: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y_tr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb5-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Prueba:        </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_te)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> clientes | tasa: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y_te<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Entrenamiento: 630 clientes | tasa: 44.4%
Prueba:        270 clientes | tasa: 44.4%</code></pre>
</div>
</div>
</section>
<section id="intento-1-regresión-logística-lineal" class="level2">
<h2 class="anchored" data-anchor-id="intento-1-regresión-logística-lineal">Intento 1: regresión logística lineal</h2>
<p>Ajustamos primero el GLM que ya conoces: una logística estándar. En la escala logit, asume que el efecto de la edad es <strong>una recta</strong> —siempre en la misma dirección. En la escala de probabilidad eso produce una sigmoide monótona. Si los datos forman un pico, este modelo tiene que aplanarlo.</p>
<div id="3dc160ea" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:41.504883Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:41.504681Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:41.610572Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:41.609780Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">lineal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>).fit(X_tr, y_tr)</span>
<span id="cb7-2"></span>
<span id="cb7-3">grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">75</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb7-4">prob_lin_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lineal.predict_proba(grid)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb7-5"></span>
<span id="cb7-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Tasas observadas en entrenamiento, para no mezclar con la prueba.</span></span>
<span id="cb7-7">tasas_tr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb7-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> a, b <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(bins[:<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], bins[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:]):</span>
<span id="cb7-9">    mascara <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (edad_tr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> a) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (edad_tr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> b)</span>
<span id="cb7-10">    tasas_tr.append(y_tr[mascara].mean() <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> mascara.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>() <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> np.nan)</span>
<span id="cb7-11"></span>
<span id="cb7-12">plt.plot(centros, tasas_tr, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>,</span>
<span id="cb7-13">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa observada (entrenamiento)'</span>)</span>
<span id="cb7-14">plt.plot(grid, prob_lin_grid, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb7-15">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'logística lineal'</span>)</span>
<span id="cb7-16">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'edad'</span>)</span>
<span id="cb7-17">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad de conversión'</span>)</span>
<span id="cb7-18">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Logística lineal: una sola dirección, una rampa suave'</span>)</span>
<span id="cb7-19">plt.ylim(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb7-20">plt.legend()</span>
<span id="cb7-21">plt.show()</span>
<span id="cb7-22"></span>
<span id="cb7-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Coeficiente de la edad: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>lineal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>coef_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb7-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Intercepto:             </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>lineal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>intercept_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb7-25"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Probabilidades a lo largo de la edad: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>prob_lin_grid<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>prob_lin_grid<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/11-modelos-aditivos-gam/index_files/figure-html/cell-6-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Coeficiente de la edad: -0.019
Intercepto:             0.693
Probabilidades a lo largo de la edad: 0.322 a 0.586</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-2" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-2">Cómo leer este resultado</h3>
<p>La curva roja es <strong>una rampa suave y descendente</strong>: a lo largo de las edades, las probabilidades van apenas de <strong>0.586</strong> (18 años) a <strong>0.322</strong> (75 años), mientras que las tasas observadas por tramo recorren de 15.1% a 66.3%. La logística lineal, obligada a una sola dirección, elige una pendiente levemente negativa (coeficiente <strong>-0.019</strong> por año) porque la cola derecha —clientes mayores, con baja conversión— arrastra la pendiente hacia abajo. No puede subir hacia los 40 y bajar después: tiene que elegir un compromiso, y ese compromiso asigna su probabilidad más alta (<strong>0.586</strong>) justo a los clientes de 18 años, uno de los grupos que menos convierte (27.6% en el tramo de 18–25).</p>
<p>El modelo no falla porque la edad no importe: falla porque <strong>importa con una forma que este GLM no puede representar</strong>. Cuánto pierde en discriminación lo mediremos en prueba, cuando el GAM ya tenga su número de knots fijado.</p>
</section>
</section>
<section id="repaso-el-spline-es-la-pieza-que-da-flexibilidad" class="level2">
<h2 class="anchored" data-anchor-id="repaso-el-spline-es-la-pieza-que-da-flexibilidad">Repaso: el spline es la pieza que da flexibilidad</h2>
<p>En el artículo de suavización con splines ya usaste uno para una media continua: <code>SplineTransformer</code> expandía <img src="https://latex.codecogs.com/png.latex?X"> en una base local y <code>LinearRegression</code> estimaba los pesos. El truco no era cambiar de algoritmo; era <strong>cambiar el espacio de características</strong>.</p>
<p>Un spline cúbico parte el rango de la variable en tramos definidos por <strong>knots</strong> (nodos) y, en cada tramo, ajusta un polinomio de grado 3. En los knots las piezas se empalman de modo que la curva, su pendiente y su curvatura coincidan. El resultado es una función suave, capaz de subir y bajar, sin que tú le impongas una parábola ni una recta.</p>
<p>En scikit-learn, <code>n_knots</code> <strong>cuenta también los extremos</strong>. Con <code>n_knots=5</code> hay tres knots internos; <code>degree=3</code> es el cúbico de siempre. <code>include_bias=False</code> deja el intercepto en manos del clasificador, igual que en ese artículo.</p>
<p>La novedad aquí es el compañero de esa expansión: en vez de <code>LinearRegression</code> (media continua), usamos <code>LogisticRegression</code> (probabilidad). El spline sigue siendo el mismo objeto; ahora vive <strong>dentro</strong> de un GLM.</p>
<p>Un detalle que importa más adelante: en scikit-learn, <code>LogisticRegression</code> <strong>penaliza por defecto</strong> los pesos con una penalización L2 (<code>C=1.0</code>), la misma idea de Ridge. Sobre la edad sin transformar su efecto es mínimo, pero sobre las bases del spline encoge los pesos y suaviza la curva. Es la misma lógica de los GAM de uso profesional, que combinan knots con una penalización de suavidad: la flexibilidad efectiva depende de las dos cosas, no solo del número de knots.</p>
<div id="f9c44766" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:41.612536Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:41.612235Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:41.746140Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:41.745151Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1">spline_demo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SplineTransformer(n_knots<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, degree<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, include_bias<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb9-2">bases_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> spline_demo.fit(X_tr).transform(grid)</span>
<span id="cb9-3"></span>
<span id="cb9-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Columnas que fabrica SplineTransformer(n_knots=5): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>bases_grid<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb9-5"></span>
<span id="cb9-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(bases_grid.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]):</span>
<span id="cb9-7">    plt.plot(grid, bases_grid[:, j], linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'base </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb9-8">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'edad'</span>)</span>
<span id="cb9-9">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'valor de la base'</span>)</span>
<span id="cb9-10">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cada columna del spline actúa en un tramo de la edad'</span>)</span>
<span id="cb9-11">plt.legend()</span>
<span id="cb9-12">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Columnas que fabrica SplineTransformer(n_knots=5): 6</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/11-modelos-aditivos-gam/index_files/figure-html/cell-7-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-estas-bases" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estas-bases">Cómo leer estas bases</h3>
<p>Cada curva es una columna: vale más en un tramo de la edad y se apaga fuera de él. El modelo no estima “un coeficiente de la edad”; estima <strong>un peso por base</strong>. Al combinarlas con esos pesos, la contribución de la edad puede subir en un tramo y bajar en otro. Eso era imposible con un único <img src="https://latex.codecogs.com/png.latex?%5Cbeta">.</p>
<p>Con <code>n_knots=5</code>, <code>degree=3</code> e <code>include_bias=False</code>, scikit-learn fabrica <strong>6 columnas</strong>: <img src="https://latex.codecogs.com/png.latex?n_%7B%5Cmathrm%7Bknots%7D%7D+%5Cmathrm%7Bdegree%7D-2=5+3-2=6">. Más knots significan tramos más cortos y más capacidad de doblarse —también más riesgo de seguir el ruido. Esa tensión es la que resolveremos con validación cruzada. Antes, veamos en una figura qué ocurre cuando cambias la flexibilidad a mano.</p>
</section>
</section>
<section id="intento-2-el-gam-spline-logística" class="level2">
<h2 class="anchored" data-anchor-id="intento-2-el-gam-spline-logística">Intento 2: el GAM (spline + logística)</h2>
<p>Un GAM logístico es, en la práctica, exactamente esa cadena de pasos (<em>pipeline</em>): expandir la edad con un spline y ajustar una logística sobre las columnas resultantes. La distribución sigue siendo Bernoulli; el enlace sigue siendo logit; lo único que se volvió flexible es el predictor.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Coperatorname%7Blogit%7D(p)=%5Cbeta_0+f(%5Ctext%7Bedad%7D).%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?f"> es la combinación lineal de las bases del spline. Todavía no elegimos cuántos knots usar: primero vamos a ver qué cambia con su número. Ajustamos tres GAM sobre el mismo entrenamiento, con tres valores de <code>n_knots</code>: <strong>2</strong> (sin knots internos: un único polinomio cúbico), <strong>5</strong> (flexibilidad moderada) y <strong>15</strong> (muy flexible). Las curvas se dibujan contra la tasa observada en entrenamiento. Ninguna de estas tres configuraciones se evalúa aún en prueba: esto es un experimento visual, no la selección del modelo.</p>
<div id="35d46b11" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:41.747918Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:41.747705Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:41.961649Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:41.960976Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1">fig, ejes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), sharey<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb11-2">configuraciones <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb11-3">    (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'poca flexibilidad'</span>),</span>
<span id="cb11-4">    (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'flexibilidad moderada'</span>),</span>
<span id="cb11-5">    (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mucha flexibilidad'</span>),</span>
<span id="cb11-6">]</span>
<span id="cb11-7"></span>
<span id="cb11-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax, (k, etiqueta) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(ejes, configuraciones):</span>
<span id="cb11-9">    modelo_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_pipeline(</span>
<span id="cb11-10">        SplineTransformer(n_knots<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k, degree<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, include_bias<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>),</span>
<span id="cb11-11">        LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>),</span>
<span id="cb11-12">    ).fit(X_tr, y_tr)</span>
<span id="cb11-13">    ax.plot(centros, tasas_tr, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>,</span>
<span id="cb11-14">            label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa observada'</span>)</span>
<span id="cb11-15">    ax.plot(grid, modelo_k.predict_proba(grid)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb11-16">            color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'GAM, n_knots=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb11-17">    ax.set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> knots: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>etiqueta<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb11-18">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'edad'</span>)</span>
<span id="cb11-19">    ax.set_ylim(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb11-20"></span>
<span id="cb11-21">ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad de conversión'</span>)</span>
<span id="cb11-22">ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].legend(loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'upper right'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb11-23">plt.tight_layout()</span>
<span id="cb11-24">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/11-modelos-aditivos-gam/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-esta-figura" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-figura">Cómo leer esta figura</h3>
<p>A la izquierda, con <strong>2 knots</strong>, la curva es casi plana: forma un pico tenue, desplazado hacia los 29 años y que no pasa de 0.52. Conviene precisar la causa. Con <code>n_knots=2</code> no hay knots internos y el spline es un único polinomio cúbico en todo el rango de edad, que sí podría dibujar el pico. Lo que lo aplana es la penalización L2 que <code>LogisticRegression</code> aplica por defecto (<code>C=1.0</code>): con bases tan anchas, formar el pico exige pesos grandes, y la penalización los encoge. El resultado es subajuste —demasiada rigidez efectiva—, producido por la penalización más que por la falta de knots; sin penalización, este mismo spline recupera el pico, con máximo cerca de los 41 años.</p>
<p>Al centro, con <strong>5 knots</strong>, la curva <strong>sigue el pico</strong>: sube hacia las edades intermedias y baja en los extremos. Esa es la forma que los tramos observados estaban pidiendo.</p>
<p>A la derecha, con <strong>15 knots</strong>, la curva se vuelve más inquieta: persigue subidas y bajadas locales que pueden ser ruido del entrenamiento. Es el sobreajuste: tanta flexibilidad que el modelo empieza a memorizar fluctuaciones que no se van a repetir.</p>
<p>La figura te da la intuición. No te da el número con el que debes quedarte. Ese número no se elige a simple vista ni mirando la prueba.</p>
</section>
<section id="antes-de-seguir-pregúntate" class="level3">
<h3 class="anchored" data-anchor-id="antes-de-seguir-pregúntate">Antes de seguir, pregúntate</h3>
<ol type="1">
<li>Si eliges <code>n_knots</code> como el valor que mejor ajusta la curva verde a los puntos grises de <strong>entrenamiento</strong>, ¿estás midiendo ajuste o generalización?</li>
<li>Si el óptimo de validación cruzada cayera en el <strong>borde</strong> del rango que probaste —el más rígido o el más flexible—, ¿qué harías antes de declararlo ganador?</li>
<li>¿Por qué el conjunto de prueba no puede participar en esta decisión?</li>
</ol>
<p>La siguiente celda responde las tres: validación cruzada <strong>dentro del entrenamiento</strong>, un rango que deja ver ambos extremos, y la prueba todavía intacta.</p>
</section>
</section>
<section id="elegir-el-número-de-knots-por-validación-cruzada" class="level2">
<h2 class="anchored" data-anchor-id="elegir-el-número-de-knots-por-validación-cruzada">Elegir el número de knots por validación cruzada</h2>
<p>Recorremos <code>n_knots</code> de <strong>2 a 15</strong>. Para cada valor armamos el mismo pipeline (<code>SplineTransformer</code> + <code>LogisticRegression</code>) y estimamos el <strong>AUC</strong> promedio (área bajo la curva ROC: la probabilidad de que el modelo asigne mayor probabilidad a un cliente que convierte que a uno que no) con validación cruzada (CV, por <em>cross-validation</em>) de 5 pliegues (<em>folds</em>) estratificados <strong>sobre el entrenamiento</strong>. El <code>SplineTransformer</code> vive <em>dentro</em> del pipeline: los knots se calculan en cada fold de ajuste, no con el entrenamiento completo y mucho menos con la prueba.</p>
<p>La métrica es AUC, no exactitud: queremos un modelo que ordene bien quién convierte, sin fijar todavía un umbral.</p>
<p>Si el máximo cayera en el borde del rango, ampliaríamos los candidatos. Un óptimo en el borde no es una elección: es una señal de que no exploraste suficiente.</p>
<div id="f9d96058" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:41.963813Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:41.963526Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:42.323045Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:42.322318Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">candidatos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>]</span>
<span id="cb12-2">cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StratifiedKFold(n_splits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA)</span>
<span id="cb12-3"></span>
<span id="cb12-4">filas_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb12-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> n_knots <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> candidatos:</span>
<span id="cb12-6">    aucs_fold <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb12-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> idx_ajuste, idx_valid <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> cv.split(X_tr, y_tr):</span>
<span id="cb12-8">        modelo_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_pipeline(</span>
<span id="cb12-9">            SplineTransformer(n_knots<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_knots, degree<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, include_bias<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>),</span>
<span id="cb12-10">            LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>),</span>
<span id="cb12-11">        )</span>
<span id="cb12-12">        modelo_cv.fit(X_tr[idx_ajuste], y_tr[idx_ajuste])</span>
<span id="cb12-13">        prob_valid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_cv.predict_proba(X_tr[idx_valid])[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb12-14">        aucs_fold.append(roc_auc_score(y_tr[idx_valid], prob_valid))</span>
<span id="cb12-15">    filas_cv.append({</span>
<span id="cb12-16">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'n_knots'</span>: n_knots,</span>
<span id="cb12-17">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'AUC_CV'</span>: np.mean(aucs_fold),</span>
<span id="cb12-18">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desv_AUC'</span>: np.std(aucs_fold, ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb12-19">    })</span>
<span id="cb12-20"></span>
<span id="cb12-21">tabla_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(filas_cv)</span>
<span id="cb12-22">mejor_n_knots <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(tabla_cv.loc[tabla_cv[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'AUC_CV'</span>].idxmax(), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'n_knots'</span>])</span>
<span id="cb12-23">en_borde <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mejor_n_knots <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> (candidatos[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], candidatos[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb12-24"></span>
<span id="cb12-25">display(tabla_cv.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb12-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Mejor n_knots según AUC de CV: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_n_knots<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb12-27"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Rango explorado: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>candidatos[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>candidatos[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb12-28"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'¿El óptimo cae en el borde del rango? </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sí"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> en_borde <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"no"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb12-29"></span>
<span id="cb12-30">plt.plot(tabla_cv[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'n_knots'</span>], tabla_cv[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'AUC_CV'</span>], marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb12-31">plt.errorbar(</span>
<span id="cb12-32">    tabla_cv[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'n_knots'</span>], tabla_cv[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'AUC_CV'</span>], yerr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>tabla_cv[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desv_AUC'</span>],</span>
<span id="cb12-33">    fmt<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'none'</span>, ecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, capsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,</span>
<span id="cb12-34">)</span>
<span id="cb12-35">plt.axvline(mejor_n_knots, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'elegido: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_n_knots<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb12-36">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'n_knots'</span>)</span>
<span id="cb12-37">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'AUC de validación cruzada'</span>)</span>
<span id="cb12-38">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'La flexibilidad se elige en entrenamiento, no en prueba'</span>)</span>
<span id="cb12-39">plt.legend()</span>
<span id="cb12-40">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">n_knots</th>
<th data-quarto-table-cell-role="th">AUC_CV</th>
<th data-quarto-table-cell-role="th">desv_AUC</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>2</td>
<td>0.607</td>
<td>0.035</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>3</td>
<td>0.707</td>
<td>0.049</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>4</td>
<td>0.706</td>
<td>0.049</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>5</td>
<td>0.706</td>
<td>0.049</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>6</td>
<td>0.703</td>
<td>0.049</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">5</th>
<td>8</td>
<td>0.700</td>
<td>0.052</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">6</th>
<td>10</td>
<td>0.697</td>
<td>0.052</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">7</th>
<td>12</td>
<td>0.698</td>
<td>0.049</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">8</th>
<td>15</td>
<td>0.693</td>
<td>0.042</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Mejor n_knots según AUC de CV: 3
Rango explorado: 2 a 15
¿El óptimo cae en el borde del rango? no</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/11-modelos-aditivos-gam/index_files/figure-html/cell-9-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-esta-validación-cruzada" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-validación-cruzada">Cómo leer esta validación cruzada</h3>
<p>El peor extremo es <code>n_knots=2</code>, con AUC de CV <strong>0.607</strong>: es la rigidez efectiva que viste en la figura anterior, causada sobre todo por la penalización L2 por defecto sobre bases muy anchas (sin penalización, el mismo spline de 2 knots alcanza un AUC de CV de 0.705). El máximo está en <strong><code>n_knots=3</code></strong>, con AUC de CV <strong>0.707</strong>. A partir de ahí el AUC se estanca o baja levemente: con 15 knots cae a <strong>0.693</strong>, una diferencia de 0.014 que queda dentro de la variación entre folds (desviación estándar de 0.042 a 0.052). Más flexibilidad no trae más acierto esperado; a partir de cierto punto solo agrega varianza.</p>
<p>El óptimo <strong>no cae en el borde</strong>: el rango iba de 2 a 15, y 3 queda en el interior. No hace falta ampliar candidatos. La lección es la misma del artículo de splines: la forma verdadera es un pico suave, y la validación cruzada elige un spline modesto, no el más flexible.</p>
<p>Las barras son la desviación estándar del AUC entre folds. Cuando dos valores tienen medias casi iguales y barras que se solapan, conviene el más simple. Aquí 3, 4 y 5 están prácticamente empatados (<strong>0.707</strong>, <strong>0.706</strong> y <strong>0.706</strong>); el máximo, <strong>3</strong>, es además el más simple de los tres, así que nos quedamos con él y lo fijamos <strong>antes</strong> de tocar la prueba.</p>
</section>
</section>
<section id="el-gam-elegido-frente-a-la-logística-lineal" class="level2">
<h2 class="anchored" data-anchor-id="el-gam-elegido-frente-a-la-logística-lineal">El GAM elegido, frente a la logística lineal</h2>
<p>Reajustamos el pipeline con <code>n_knots=3</code> en <strong>todo</strong> el entrenamiento —los folds ya cumplieron su papel— y dibujamos las dos curvas sobre la misma tasa observada. Las métricas numéricas de prueba llegan en la siguiente sección; esta figura es para ver si el GAM, ya con el hiperparámetro fijado, recupera el pico.</p>
<div id="f4241ad6" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:42.325053Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:42.324767Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:42.431581Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:42.430859Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">gam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_pipeline(</span>
<span id="cb14-2">    SplineTransformer(n_knots<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mejor_n_knots, degree<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, include_bias<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>),</span>
<span id="cb14-3">    LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>),</span>
<span id="cb14-4">).fit(X_tr, y_tr)</span>
<span id="cb14-5"></span>
<span id="cb14-6">prob_gam_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gam.predict_proba(grid)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb14-7"></span>
<span id="cb14-8">plt.plot(centros, tasas_tr, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>,</span>
<span id="cb14-9">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa observada (entrenamiento)'</span>)</span>
<span id="cb14-10">plt.plot(grid, prob_lin_grid, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>,</span>
<span id="cb14-11">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'logística lineal'</span>)</span>
<span id="cb14-12">plt.plot(grid, prob_gam_grid, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb14-13">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'GAM (n_knots=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_n_knots<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb14-14">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'edad'</span>)</span>
<span id="cb14-15">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad de conversión'</span>)</span>
<span id="cb14-16">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'El GAM recupera el pico; la logística lineal lo aplana'</span>)</span>
<span id="cb14-17">plt.ylim(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb14-18">plt.legend()</span>
<span id="cb14-19">plt.show()</span>
<span id="cb14-20"></span>
<span id="cb14-21">edad_pico <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(grid[np.argmax(prob_gam_grid), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb14-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Pico de la curva GAM: edad </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>edad_pico<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> años, probabilidad </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>prob_gam_grid<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb14-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Rango de la curva GAM: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>prob_gam_grid<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>prob_gam_grid<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/11-modelos-aditivos-gam/index_files/figure-html/cell-10-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Pico de la curva GAM: edad 43.9 años, probabilidad 0.638
Rango de la curva GAM: 0.148 a 0.638</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-3" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-3">Cómo leer este resultado</h3>
<p>La curva verde <strong>sigue el pico</strong>: sube desde los 18 años, alcanza su máximo cerca de <strong>43.9 años</strong> (probabilidad <strong>0.638</strong>) y baja hasta <strong>0.148</strong> en el extremo derecho. La roja sigue siendo la rampa descendente de <strong>0.586 a 0.322</strong>.</p>
<p>Esa es la esencia del GAM: <strong>conservas la estructura del GLM</strong> —Bernoulli, logit, un efecto por variable que puedes dibujar— y <strong>liberas la forma</strong> de ese efecto. Todavía no celebres el gráfico: un modelo puede lucir bien en entrenamiento y no generalizar.</p>
</section>
</section>
<section id="comparación-justa-lineal-vs-gam-vs-baseline" class="level2">
<h2 class="anchored" data-anchor-id="comparación-justa-lineal-vs-gam-vs-baseline">Comparación justa: lineal vs GAM vs baseline</h2>
<p>Tres reglas, el mismo conjunto de prueba, las mismas métricas:</p>
<ol type="1">
<li><strong>Baseline trivial:</strong> siempre predice la clase mayoritaria del entrenamiento (aquí, “no convierte”). Como su marcador es constante, su AUC es 0.5: no ordena.</li>
<li><strong>Logística lineal:</strong> el GLM con predictor rígido.</li>
<li><strong>GAM:</strong> el mismo GLM, con el spline cuyo <code>n_knots</code> se eligió por CV en entrenamiento.</li>
</ol>
<p>El AUC mide discriminación (ordenar quién convierte). La exactitud mide aciertos con umbral 0.5. Ninguna de las dos se usó para elegir knots sobre la prueba.</p>
<div id="911eea89" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:42.433471Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:42.433262Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:42.449188Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:42.448421Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">prob_lin_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lineal.predict_proba(X_te)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb16-2">auc_lineal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> roc_auc_score(y_te, prob_lin_te)</span>
<span id="cb16-3">acc_lineal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> accuracy_score(y_te, lineal.predict(X_te))</span>
<span id="cb16-4"></span>
<span id="cb16-5">prob_gam_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gam.predict_proba(X_te)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb16-6">auc_gam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> roc_auc_score(y_te, prob_gam_te)</span>
<span id="cb16-7">acc_gam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> accuracy_score(y_te, gam.predict(X_te))</span>
<span id="cb16-8"></span>
<span id="cb16-9">clase_mayoritaria <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> y_tr.mean() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb16-10">pred_base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.full_like(y_te, clase_mayoritaria)</span>
<span id="cb16-11">acc_base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> accuracy_score(y_te, pred_base)</span>
<span id="cb16-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Un marcador constante no ordena: el AUC de referencia es 0.5.</span></span>
<span id="cb16-13">auc_base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span></span>
<span id="cb16-14"></span>
<span id="cb16-15">comparacion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb16-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'modelo'</span>: [</span>
<span id="cb16-17">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Baseline (clase mayoritaria)'</span>,</span>
<span id="cb16-18">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Logística lineal'</span>,</span>
<span id="cb16-19">        <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'GAM (n_knots=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_n_knots<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>,</span>
<span id="cb16-20">    ],</span>
<span id="cb16-21">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'AUC prueba'</span>: [auc_base, auc_lineal, auc_gam],</span>
<span id="cb16-22">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'exactitud prueba'</span>: [acc_base, acc_lineal, acc_gam],</span>
<span id="cb16-23">})</span>
<span id="cb16-24">display(comparacion.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb16-25"></span>
<span id="cb16-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Clase mayoritaria en entrenamiento: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>clase_mayoritaria<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> '</span></span>
<span id="cb16-27">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'(</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"convierte"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> clase_mayoritaria <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"no convierte"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb16-28"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'AUC  — baseline </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>auc_base<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | lineal </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>auc_lineal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | GAM </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>auc_gam<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb16-29"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Acc. — baseline </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acc_base<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | lineal </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acc_lineal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | GAM </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acc_gam<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">modelo</th>
<th data-quarto-table-cell-role="th">AUC prueba</th>
<th data-quarto-table-cell-role="th">exactitud prueba</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>Baseline (clase mayoritaria)</td>
<td>0.500</td>
<td>0.556</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>Logística lineal</td>
<td>0.599</td>
<td>0.507</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>GAM (n_knots=3)</td>
<td>0.718</td>
<td>0.674</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Clase mayoritaria en entrenamiento: 0 (no convierte)
AUC  — baseline 0.500 | lineal 0.599 | GAM 0.718
Acc. — baseline 0.556 | lineal 0.507 | GAM 0.674</code></pre>
</div>
</div>
<section id="cómo-leer-la-comparación" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-la-comparación">Cómo leer la comparación</h3>
<p>En prueba, el GAM alcanza un <strong>AUC de 0.718</strong> frente a <strong>0.599</strong> de la logística lineal y <strong>0.500</strong> del baseline. La mejora no es un retoque: es la diferencia entre ordenar apenas mejor que el azar y recuperar la forma que realmente discrimina.</p>
<p>En exactitud el contraste es todavía más claro. El baseline (siempre “no convierte”) acierta el <strong>55.6%</strong>. La logística lineal baja a <strong>50.7%</strong>: peor que ignorar la edad. El GAM sube a <strong>67.4%</strong>. Un predictor mal especificado no es “un poco peor”; puede <strong>destruir</strong> incluso la ventaja de la clase mayoritaria, porque el umbral 0.5 se aplica sobre probabilidades que no describen el fenómeno.</p>
<p>Estas cifras salen de 270 clientes que el modelo no usó ni para estimar coeficientes ni para elegir knots. Por eso la comparación es justa.</p>
</section>
</section>
<section id="discriminación-a-lo-largo-de-todos-los-umbrales-roc" class="level2">
<h2 class="anchored" data-anchor-id="discriminación-a-lo-largo-de-todos-los-umbrales-roc">Discriminación a lo largo de todos los umbrales: ROC</h2>
<p>El AUC resume la curva ROC. Dibujar las tres reglas juntas deja ver <em>dónde</em> gana el GAM, no solo el número agregado.</p>
<div id="8f97fe4e" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:42.451127Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:42.450929Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:42.565930Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:42.565033Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">fpr_lin, tpr_lin, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> roc_curve(y_te, prob_lin_te)</span>
<span id="cb18-2">fpr_gam, tpr_gam, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> roc_curve(y_te, prob_gam_te)</span>
<span id="cb18-3"></span>
<span id="cb18-4">plt.plot(fpr_gam, tpr_gam, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb18-5">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'GAM (AUC = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>auc_gam<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb18-6">plt.plot(fpr_lin, tpr_lin, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb18-7">         label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'logística lineal (AUC = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>auc_lineal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb18-8">plt.plot([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k--'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'baseline / azar (AUC = 0.500)'</span>)</span>
<span id="cb18-9">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa de falsos positivos'</span>)</span>
<span id="cb18-10">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tasa de verdaderos positivos'</span>)</span>
<span id="cb18-11">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Curva ROC en prueba: la ventaja del GAM está en los umbrales exigentes'</span>)</span>
<span id="cb18-12">plt.legend()</span>
<span id="cb18-13">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/11-modelos-aditivos-gam/index_files/figure-html/cell-12-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-la-curva-roc" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-la-curva-roc">Cómo leer la curva ROC</h3>
<p>Un AUC de <strong>0.718</strong> significa que, al tomar al azar un cliente que convierte y uno que no, el GAM asigna mayor probabilidad al que sí convierte aproximadamente el 72% de las veces. La curva de la logística lineal (<strong>0.599</strong>) incluso queda por debajo de la diagonal hasta una tasa de falsos positivos cercana a 0.33: sus primeros puestos los ocupan los clientes más jóvenes, a quienes asigna la probabilidad más alta aunque convierten poco. La ventaja del GAM se concentra en los umbrales exigentes: con tasas de falsos positivos entre 0.1 y 0.4, su tasa de verdaderos positivos supera a la de la lineal en unos 0.2 a 0.35. A partir de una tasa de falsos positivos de 0.5, las dos curvas prácticamente coinciden.</p>
<p>Recuerda la distinción de la logística: el AUC mide <strong>discriminación</strong> (ordenar), no <strong>calibración</strong> (si anunciar 0.60 se traduce en 60 de cada 100). Para desplegar probabilidades operativas haría falta un chequeo extra de calibración. Aquí nos basta con confirmar que la forma flexible mejora el ordenamiento sobre la prueba.</p>
</section>
</section>
<section id="la-ventaja-interpretativa-leer-la-forma-del-efecto" class="level2">
<h2 class="anchored" data-anchor-id="la-ventaja-interpretativa-leer-la-forma-del-efecto">La ventaja interpretativa: leer la forma del efecto</h2>
<p>Un buen AUC no explica <em>qué hace</em> la edad. El GAM sí puede. Como el predictor es <img src="https://latex.codecogs.com/png.latex?f(%5Ctext%7Bedad%7D)">, podemos dibujar esa contribución a lo largo del rango: la <strong>curva de efecto parcial</strong>.</p>
<p>En la escala de probabilidad ves el mensaje para el negocio: en qué edades la conversión esperada es alta o baja. En la escala logit ves <img src="https://latex.codecogs.com/png.latex?f"> centrada —la pieza aditiva del modelo—, sin mezclarla con el intercepto. Las dos cuentan la misma historia; cambian las unidades.</p>
<div id="449a1efe" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:42.567715Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:42.567400Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:42.736394Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:42.735652Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1">spline <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gam.named_steps[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'splinetransformer'</span>]</span>
<span id="cb19-2">clf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gam.named_steps[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'logisticregression'</span>]</span>
<span id="cb19-3">bases_efecto <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> spline.transform(grid)</span>
<span id="cb19-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Contribución de la edad en log-odds, centrada para leer forma y no nivel.</span></span>
<span id="cb19-5">f_logit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> bases_efecto <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> clf.coef_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb19-6">f_logit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> f_logit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> f_logit.mean()</span>
<span id="cb19-7"></span>
<span id="cb19-8">fig, ejes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb19-9"></span>
<span id="cb19-10">ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(grid, prob_gam_grid, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb19-11">ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].axvline(edad_pico, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb19-12">ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(</span>
<span id="cb19-13">    xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'edad'</span>,</span>
<span id="cb19-14">    ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad de conversión estimada'</span>,</span>
<span id="cb19-15">    title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Escala de probabilidad'</span>,</span>
<span id="cb19-16">    ylim<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb19-17">)</span>
<span id="cb19-18"></span>
<span id="cb19-19">ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(grid, f_logit, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb19-20">ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb19-21">ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].axvline(edad_pico, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb19-22">ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(</span>
<span id="cb19-23">    xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'edad'</span>,</span>
<span id="cb19-24">    ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'f(edad) centrada (log-odds)'</span>,</span>
<span id="cb19-25">    title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Escala del predictor aditivo'</span>,</span>
<span id="cb19-26">)</span>
<span id="cb19-27"></span>
<span id="cb19-28">plt.tight_layout()</span>
<span id="cb19-29">plt.show()</span>
<span id="cb19-30"></span>
<span id="cb19-31"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Máximo de f(edad) en </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>edad_pico<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> años'</span>)</span>
<span id="cb19-32"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'f(edad) en 20 años: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>interp(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, grid.ravel(), f_logit)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb19-33"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'f(edad) en 44 años: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>interp(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">44</span>, grid.ravel(), f_logit)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb19-34"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'f(edad) en 70 años: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>interp(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">70</span>, grid.ravel(), f_logit)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/11-modelos-aditivos-gam/index_files/figure-html/cell-13-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Máximo de f(edad) en 43.9 años
f(edad) en 20 años: -0.511
f(edad) en 44 años: 0.834
f(edad) en 70 años: -1.136</code></pre>
</div>
</div>
<section id="cómo-leer-el-efecto-parcial" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-el-efecto-parcial">Cómo leer el efecto parcial</h3>
<p>En probabilidad, la conversión estimada <strong>sube desde los 18 años hasta cerca de 44</strong>, y <strong>baja con claridad después de los 50</strong>, hasta valores bajos alrededor de los 70. No es “los mayores convierten menos” como lema global: los más jóvenes también convierten menos que el grupo intermedio. El GAM te deja decir <em>dónde</em> ocurre cada tramo, no solo el signo de un coeficiente.</p>
<p>En log-odds, <img src="https://latex.codecogs.com/png.latex?f(%5Ctext%7Bedad%7D)"> está por debajo de cero en los extremos —<strong><img src="https://latex.codecogs.com/png.latex?f(20)=-0.511"></strong>, <strong><img src="https://latex.codecogs.com/png.latex?f(70)=-1.136"></strong>— y por encima cerca del pico —<strong><img src="https://latex.codecogs.com/png.latex?f(44)=0.834"></strong>. Como la centraste, el cero es el nivel medio de la curva, no “efecto nulo”. Lo útil no es un p-valor de cada base: es esta forma. Frente a una caja negra, esta es la ventaja que viniste a buscar —la misma variable, el mismo modelo probabilístico, y un dibujo que puedes explicar.</p>
</section>
</section>
<section id="hay-evidencia-de-que-la-forma-suave-mejora-el-ajuste" class="level2">
<h2 class="anchored" data-anchor-id="hay-evidencia-de-que-la-forma-suave-mejora-el-ajuste">¿Hay evidencia de que la forma suave mejora el ajuste?</h2>
<p>El AUC de prueba ya respondió en clave predictiva. En clave inferencial, sobre el <strong>mismo entrenamiento</strong>, comparamos dos GLM binomiales <strong>sin penalización</strong> (a diferencia del pipeline de scikit-learn, que aplica la L2 por defecto; por eso sus coeficientes no coinciden con los de <code>gam</code>):</p>
<ul>
<li><strong>reducido:</strong> <img src="https://latex.codecogs.com/png.latex?%5Coperatorname%7Blogit%7D(p)=%5Cbeta_0+%5Cbeta_1%5C,%5Ctext%7Bedad%7D"></li>
<li><strong>GAM:</strong> <img src="https://latex.codecogs.com/png.latex?%5Coperatorname%7Blogit%7D(p)=%5Cbeta_0+"> bases del spline con el <code>n_knots</code> ya elegido</li>
</ul>
<p>El contraste de verosimilitud (LRT) pregunta si las bases extra mejoran el ajuste lo bastante como para no atribuirlo al azar, <em>bajo los supuestos del modelo</em>. Las bases del spline, junto con el intercepto, reproducen exactamente cualquier recta dentro del rango de entrenamiento, así que el modelo lineal es un caso particular (anidado) del suave y el LRT es legítimo; el AIC (criterio de información de Akaike, <img src="https://latex.codecogs.com/png.latex?-2%5Clog%20L+2k">, donde menor es mejor), que no exige anidamiento, apunta en la misma dirección. Un p-valor pequeño no demuestra que la edad cause la conversión, ni que 3 knots sea la verdad del fenómeno, ni que el modelo deba desplegarse. Es una evidencia de asociación con forma no lineal, en esta muestra de entrenamiento. Además, <code>n_knots</code> se eligió con estos mismos datos, así que el p-valor es algo optimista.</p>
<div id="a7c16cbf" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:42.739151Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:42.738893Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:42.759297Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:42.758523Z&quot;}}" data-execution_count="13">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># GLM lineal (statsmodels, sin regularizar), sobre entrenamiento.</span></span>
<span id="cb21-2">X_lin_sm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sm.add_constant(X_tr)</span>
<span id="cb21-3">glm_lineal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sm.GLM(y_tr, X_lin_sm, family<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>sm.families.Binomial()).fit()</span>
<span id="cb21-4"></span>
<span id="cb21-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># GAM: las mismas bases que el pipeline, también sobre entrenamiento.</span></span>
<span id="cb21-6">bases_tr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> spline.transform(X_tr)</span>
<span id="cb21-7">X_gam_sm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sm.add_constant(bases_tr)</span>
<span id="cb21-8">glm_gam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sm.GLM(y_tr, X_gam_sm, family<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>sm.families.Binomial()).fit()</span>
<span id="cb21-9"></span>
<span id="cb21-10">stat_lrt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (glm_gam.llf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> glm_lineal.llf)</span>
<span id="cb21-11">gl_lrt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(glm_gam.df_model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> glm_lineal.df_model)</span>
<span id="cb21-12">p_lrt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> chi2.sf(stat_lrt, gl_lrt)</span>
<span id="cb21-13"></span>
<span id="cb21-14">tabla_lineal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb21-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'coeficiente'</span>: glm_lineal.params,</span>
<span id="cb21-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'p-valor'</span>: glm_lineal.pvalues,</span>
<span id="cb21-17">}, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'intercepto'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'edad'</span>])</span>
<span id="cb21-18"></span>
<span id="cb21-19">tabla_bases <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb21-20">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'coeficiente'</span>: glm_gam.params[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:],</span>
<span id="cb21-21">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'p-valor'</span>: glm_gam.pvalues[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:],</span>
<span id="cb21-22">}, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'base spline </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(bases_tr.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])])</span>
<span id="cb21-23"></span>
<span id="cb21-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Logística lineal (entrenamiento, statsmodels):'</span>)</span>
<span id="cb21-25">display(tabla_lineal.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb21-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Coeficientes de cada base del spline (no se interpretan uno a uno):'</span>)</span>
<span id="cb21-27">display(tabla_bases.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb21-28"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'LRT (GAM vs lineal): estadístico = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>stat_lrt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, gl = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>gl_lrt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, p-valor = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>p_lrt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2e}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb21-29"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'AIC lineal: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>glm_lineal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>aic<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | AIC GAM: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>glm_gam<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>aic<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Logística lineal (entrenamiento, statsmodels):</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">coeficiente</th>
<th data-quarto-table-cell-role="th">p-valor</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">intercepto</th>
<td>0.6932</td>
<td>0.0068</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">edad</th>
<td>-0.0192</td>
<td>0.0002</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Coeficientes de cada base del spline (no se interpretan uno a uno):</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">coeficiente</th>
<th data-quarto-table-cell-role="th">p-valor</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">base spline 1</th>
<td>1.1782</td>
<td>0.8478</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">base spline 2</th>
<td>2.3356</td>
<td>0.7491</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">base spline 3</th>
<td>6.0880</td>
<td>0.3105</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">base spline 4</th>
<td>0.9347</td>
<td>0.9022</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>LRT (GAM vs lineal): estadístico = 75.59, gl = 3, p-valor = 2.71e-16
AIC lineal: 855.2 | AIC GAM: 785.6</code></pre>
</div>
</div>
<section id="cómo-leer-estos-p-valores" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estos-p-valores">Cómo leer estos p-valores</h3>
<p>En el GLM lineal, el coeficiente de la edad es <strong>-0.0192</strong> con p-valor <strong>0.0002</strong>. Eso <em>no</em> significa que el modelo lineal sea el correcto. Significa que, <em>si</em> el efecto fuera una recta, hay evidencia contra pendiente cero. Los datos también son compatibles con un pico cuya cola derecha arrastra la recta hacia abajo: un coeficiente significativo puede convivir con una <strong>forma mal especificada</strong>.</p>
<p>Los p-valores de las bases del spline (<strong>0.8478</strong>, <strong>0.7491</strong>, <strong>0.3105</strong>, <strong>0.9022</strong>) no se leen como “esta base no importa”. Las columnas están correlacionadas; cada una cubre un tramo y el nivel se comparte con el intercepto. Preguntar por una base aislada es la pregunta equivocada. La pregunta correcta es conjunta: el LRT vale <strong>75.59</strong> con <strong>3</strong> grados de libertad y p-valor <strong>2.71×10⁻¹⁶</strong>. Bajo los supuestos del GLM binomial, hay evidencia muy fuerte de que el predictor suave describe mejor el entrenamiento que la recta. El AIC apunta en la misma dirección: <strong>785.6</strong> frente a <strong>855.2</strong>.</p>
<p>Ninguno de estos números establece causalidad. Aquí la edad determina la conversión porque así lo programamos en la simulación; el LRT solo confirma que una forma suave describe esa regla mejor que una recta. En datos reales nadie asigna edades al azar, y el mismo LRT sería evidencia de asociación no lineal, no de un mecanismo.</p>
</section>
</section>
<section id="cuándo-usar-un-gam" class="level2">
<h2 class="anchored" data-anchor-id="cuándo-usar-un-gam">Cuándo usar un GAM</h2>
<p>Usa un GAM cuando la respuesta pide un GLM —binaria, de conteo, etc.— y al menos un predictor continuo <strong>no se deja resumir con una pendiente</strong>. Señales típicas: la tasa observada sube y baja, un diagnóstico residual muestra curvatura sistemática, o un término polinómico ayuda pero no quieres fijar el grado a mano.</p>
<p>No es el primer recurso. Si la logística lineal ya captura el fenómeno y el gráfico del efecto es una rampa razonable, añadir splines solo suma varianza. Tampoco sustituye a un modelo que necesite interacciones complejas o cientos de predictores: el GAM brilla con <strong>pocas variables cuyo efecto quieres dibujar</strong>.</p>
</section>
<section id="errores-comunes-al-pasar-de-un-glm-a-un-gam" class="level2">
<h2 class="anchored" data-anchor-id="errores-comunes-al-pasar-de-un-glm-a-un-gam">Errores comunes al pasar de un GLM a un GAM</h2>
<ol type="1">
<li><strong>Elegir los knots mirando la prueba o el gráfico final.</strong> La complejidad se decide por validación cruzada en entrenamiento. Si el óptimo cae en el borde, se amplía el rango; no se declara ganador un extremo no explorado.</li>
<li><strong>Preprocesar el spline fuera del pipeline.</strong> Ajustar <code>SplineTransformer</code> con todo <img src="https://latex.codecogs.com/png.latex?X"> y <em>después</em> hacer CV es fuga: los folds de validación ya influyeron en los knots.</li>
<li><strong>Leer cada coeficiente de la base como si fuera una pendiente.</strong> El objeto interpretable es la curva <img src="https://latex.codecogs.com/png.latex?f_j">, no <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> de la columna 3.</li>
<li><strong>Confundir un p-valor del término lineal con una forma correcta.</strong> Un coeficiente de la edad puede ser “significativo” y aun así aplanar un pico.</li>
<li><strong>Interpretar el LRT o el AUC como causalidad.</strong> Ambos responden a asociación y a predicción, no a “si cambio la edad, causa la conversión”.</li>
<li><strong>Olvidar el baseline.</strong> Un AUC de 0.60 parece un número; frente a 0.50 y a 0.72 se entiende lo que vale.</li>
<li><strong>Tratar el GAM como caja negra porque usa un spline.</strong> La aditividad está para dibujarse. Si no miras <img src="https://latex.codecogs.com/png.latex?f_j">, desperdicias la ventaja del modelo.</li>
<li><strong>Identificar flexibilidad con calidad.</strong> En este ejemplo, 15 knots no mejoran a 3 en CV (AUC de 0.693 frente a 0.707, una diferencia dentro de la variación entre folds). Más knots no es más modelo: es más capacidad de memorizar.</li>
</ol>
</section>
<section id="lo-que-debes-llevarte" class="level2">
<h2 class="anchored" data-anchor-id="lo-que-debes-llevarte">Lo que debes llevarte</h2>
<p>La cadena del GLM, ahora completa, es:</p>
<pre class="text"><code>respuesta (binaria, conteo, …)
→ distribución (Bernoulli, Poisson, …)
→ predictor: lineal Xβ  o  aditivo β₀ + Σ fⱼ(xⱼ)
→ función de enlace (logit, log, …)
→ media: probabilidad, tasa, …</code></pre>
<p>Tres artículos, una sola idea. La <strong>logística</strong> adaptó la distribución y el enlace a una respuesta Bernoulli: el predictor seguía siendo lineal y la salida, una probabilidad. La <strong>Poisson</strong> hizo lo mismo con un conteo: enlace log, tasa positiva. El <strong>GAM</strong> deja intactas distribución y enlace y abre el predictor: sustituye <img src="https://latex.codecogs.com/png.latex?%5Cbeta_j%20x_j"> por <img src="https://latex.codecogs.com/png.latex?f_j(x_j)">. Por eso el gráfico de este artículo se parece al de la logística —una probabilidad entre 0 y 1— y a la vez al de un spline —una curva que sube y baja—. No hubo que inventar una familia nueva: bastó con cambiar la pieza del predictor y elegir su complejidad sin fugar la prueba.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 50%">
<col style="width: 50%">
</colgroup>
<thead>
<tr class="header">
<th>Modelo</th>
<th>Qué cambia respecto al GLM gaussiano clásico</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Logística</td>
<td>distribución Bernoulli + enlace logit</td>
</tr>
<tr class="even">
<td>Poisson</td>
<td>distribución Poisson + enlace log</td>
</tr>
<tr class="odd">
<td>GAM</td>
<td>el predictor deja de ser lineal en cada <img src="https://latex.codecogs.com/png.latex?x_j">, que puede entrar con <img src="https://latex.codecogs.com/png.latex?f_j"> (sigue siendo lineal en los pesos de las bases)</td>
</tr>
</tbody>
</table>
<p>Si recuerdas esa tabla, puedes reconocer el siguiente problema real por el tipo de <img src="https://latex.codecogs.com/png.latex?Y"> y por la forma del efecto, no por el nombre del método. El spline que ya conocías del artículo de suavización es el mecanismo que estima cada <img src="https://latex.codecogs.com/png.latex?f_j">. El número de knots no se adivina: se elige por validación cruzada, se verifica que no quede en el borde, y se evalúa una sola vez en prueba contra un GLM lineal y contra un baseline trivial.</p>
<p>Para comunicar el modelo, dibuja <img src="https://latex.codecogs.com/png.latex?f_j">. Ese dibujo es la razón de haber usado un GAM y no una caja negra.</p>
</section>
<section id="qué-sigue" class="level2">
<h2 class="anchored" data-anchor-id="qué-sigue">¿Qué sigue?</h2>
<p>Hasta aquí la pregunta era: dada <img src="https://latex.codecogs.com/png.latex?Y"> y dadas unas <img src="https://latex.codecogs.com/png.latex?X"> observables, ¿cómo modelar la media con una distribución, un enlace y —si hace falta— una forma suave? En el próximo tema la pregunta se da la vuelta.</p>
<p>A menudo no quieres predecir una respuesta, sino <strong>encontrar estructura oculta</strong> dentro de muchas variables a la vez: direcciones que concentran la varianza, componentes que se mezclan, factores que no mediste de forma directa. Ahí entran las <strong>variables latentes</strong>, con herramientas como <strong>PCA</strong> e <strong>ICA</strong>, y la reducción de dimensionalidad.</p>
<p>El hilo no se rompe: sigues buscando una representación interpretable de los datos. Cambia el objeto. Ya no es <img src="https://latex.codecogs.com/png.latex?f(%5Ctext%7Bedad%7D)">; son las direcciones o las fuentes que el conjunto está usando sin nombrarte.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>glm</category>
  <category>gam</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/avanzado/11-modelos-aditivos-gam/</guid>
  <pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Análisis Avanzado de Datos — 11. Variables latentes I: Análisis de Componentes Principales (PCA)</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/avanzado/12-pca/</link>
  <description><![CDATA[ 




<section id="análisis-avanzado-de-datos-11.-variables-latentes-i-análisis-de-componentes-principales-pca" class="level1">
<h1>Análisis Avanzado de Datos — 11. Variables latentes I: Análisis de Componentes Principales (PCA)</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado convierte datos en decisiones. Científico de Datos, Arquitecto de IA y asesor tecnológico con más de 20 años de experiencia en analítica avanzada, machine learning, Big Data e IoT. Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), asesora a entidades gubernamentales y empresas privadas en Colombia y es referente en analítica y normatividad para los sectores postal y logístico del país. Una serie pensada para ir de la teoría a la práctica, con ejemplos concretos en cada paso.</p>
<p>📌 <em>Parte de la serie <strong>Análisis Avanzado de Datos</strong>.</em></p>
</section>
<section id="un-cambio-de-paradigma-de-predecir-a-descubrir" class="level2">
<h2 class="anchored" data-anchor-id="un-cambio-de-paradigma-de-predecir-a-descubrir">Un cambio de paradigma: de predecir a descubrir</h2>
<p>Hasta ahora, de la regresión lineal a los GAM del artículo anterior, trabajaste en <strong>aprendizaje supervisado</strong>: tenías variables <img src="https://latex.codecogs.com/png.latex?X">, una respuesta <img src="https://latex.codecogs.com/png.latex?y"> y buscabas aprender una regla para predecir <img src="https://latex.codecogs.com/png.latex?y"> a partir de <img src="https://latex.codecogs.com/png.latex?X">. En este artículo cambia la pregunta: ya no buscas predecir una respuesta, sino encontrar <strong>variables latentes</strong>, es decir, estructura no observada directamente que organiza muchas variables a la vez.</p>
<p>El <strong>Análisis de Componentes Principales (PCA)</strong> es aprendizaje <strong>no supervisado</strong>. No recibe una variable objetivo. Examina únicamente las relaciones entre las variables de <img src="https://latex.codecogs.com/png.latex?X"> para descubrir sus direcciones dominantes y representar los datos con menos dimensiones.</p>
<p>Usaremos las etiquetas reales de los vinos solo después, para colorear una figura y evaluar una aplicación predictiva. PCA no las verá al aprender sus componentes.</p>
</section>
<section id="objetivos-de-aprendizaje" class="level2">
<h2 class="anchored" data-anchor-id="objetivos-de-aprendizaje">Objetivos de aprendizaje</h2>
<p>Al terminar este notebook vas a ser capaz de:</p>
<ul>
<li><strong>Explicar</strong> qué problema resuelve PCA y por qué sus componentes son ortogonales.</li>
<li><strong>Estandarizar</strong> las variables antes de aplicar PCA cuando sus escalas difieren.</li>
<li><strong>Interpretar</strong> la varianza explicada, el gráfico de sedimentación (<em>scree plot</em>) y la varianza acumulada.</li>
<li><strong>Elegir</strong> un número razonable de componentes mediante un umbral y contrastarlo con validación cruzada.</li>
<li><strong>Leer</strong> una proyección y las cargas de sus primeros componentes.</li>
<li><strong>Medir</strong> el compromiso entre compresión y error de reconstrucción.</li>
<li><strong>Distinguir</strong> PCA de un método supervisado y anticipar su diferencia con ICA (Análisis de Componentes Independientes), el próximo tema de la serie.</li>
</ul>
</section>
<section id="el-problema-formal-muchas-coordenadas-estructura-repetida" class="level2">
<h2 class="anchored" data-anchor-id="el-problema-formal-muchas-coordenadas-estructura-repetida">El problema formal: muchas coordenadas, estructura repetida</h2>
<p>Cuando aumentan las variables, las observaciones se vuelven más dispersas y las distancias pierden contraste: es una cara de la <strong>maldición de la dimensionalidad</strong>. Además, si varias variables están correlacionadas, describen parte del mismo patrón y añaden redundancia.</p>
<p>PCA reemplaza las variables originales por nuevas coordenadas llamadas <strong>componentes principales</strong>. Cada componente es una combinación lineal de las variables; el primero busca la dirección de mayor dispersión, el segundo la mayor dispersión restante bajo la condición de ser perpendicular al primero, y así sucesivamente.</p>
</section>
<section id="la-optimización-detrás-de-pca" class="level2">
<h2 class="anchored" data-anchor-id="la-optimización-detrás-de-pca">La optimización detrás de PCA</h2>
<p>Sea <img src="https://latex.codecogs.com/png.latex?X_c"> la matriz de datos centrada y sea <img src="https://latex.codecogs.com/png.latex?w_1"> una dirección de longitud uno. La proyección de los datos sobre esa dirección es <img src="https://latex.codecogs.com/png.latex?X_cw_1">. PCA elige:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Aw_1=%5Cunderset%7B%5ClVert%20w%5CrVert_2=1%7D%7B%5Coperatorname%7Barg%5C,max%7D%7D%5C;%5Coperatorname%7BVar%7D(X_cw)%0A=%5Cunderset%7B%5ClVert%20w%5CrVert_2=1%7D%7B%5Coperatorname%7Barg%5C,max%7D%7D%5C;w%5E%5Ctop%20S%20w,%0A"></p>
<p>donde <img src="https://latex.codecogs.com/png.latex?S=%5Cfrac%7B1%7D%7Bn-1%7DX_c%5E%5Ctop%20X_c"> es la matriz de covarianza. Para el componente <img src="https://latex.codecogs.com/png.latex?j"> se añade la restricción <img src="https://latex.codecogs.com/png.latex?w_j%5E%5Ctop%20w_%5Cell=0"> para todo <img src="https://latex.codecogs.com/png.latex?%5Cell%3Cj">.</p>
<p>La solución conduce al problema de valores propios:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0ASw_j=%5Clambda_jw_j,%5Cqquad%20%5Clambda_1%5Cgeq%5Clambda_2%5Cgeq%5Ccdots%5Cgeq%5Clambda_p.%0A"></p>
<p>Como <img src="https://latex.codecogs.com/png.latex?S"> es simétrica, sus vectores propios pueden elegirse ortonormales: <img src="https://latex.codecogs.com/png.latex?W%5E%5Ctop%20W=I">. Los vectores <img src="https://latex.codecogs.com/png.latex?w_j"> son las direcciones; los valores propios <img src="https://latex.codecogs.com/png.latex?%5Clambda_j"> indican cuánta varianza captura cada dirección. Las nuevas coordenadas son las <strong>puntuaciones</strong> o <em>scores</em> <img src="https://latex.codecogs.com/png.latex?Z=X_cW"> y quedan no correlacionadas entre sí.</p>
<blockquote class="blockquote">
<p><strong>Punto clave.</strong> PCA es <strong>no supervisado</strong>: encuentra direcciones de máxima varianza usando solo <img src="https://latex.codecogs.com/png.latex?X">. No conoce las etiquetas, no intenta separar clases y una varianza grande no garantiza utilidad predictiva. Si luego coloreamos una proyección por clase, lo hacemos únicamente para interpretar una estructura que PCA descubrió sin esa información.</p>
</blockquote>
</section>
<section id="qué-significa-girar-el-sistema-de-coordenadas" class="level2">
<h2 class="anchored" data-anchor-id="qué-significa-girar-el-sistema-de-coordenadas">Qué significa girar el sistema de coordenadas</h2>
<p>Imagina una nube alargada en diagonal. Los ejes horizontal y vertical no describen bien su forma. PCA gira los ejes: el primer eje queda sobre la dirección larga de la nube y el segundo, perpendicular, recoge la variación corta.</p>
<p>Este giro, por sí solo, no pierde información: con todos los ejes girados se recuperan exactamente los datos. La reducción ocurre cuando conservas las primeras <img src="https://latex.codecogs.com/png.latex?k%3Cp"> coordenadas y descartas las direcciones con poca varianza. Primero veremos esa idea con dos variables; solo después ajustaremos PCA sobre las trece.</p>
</section>
<section id="preparación-del-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparación-del-entorno">Preparación del entorno</h2>
<div id="92795133" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:49.757594Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:49.757000Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:51.900173Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:51.899350Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.datasets <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> load_wine</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.decomposition <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PCA</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LogisticRegression</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> accuracy_score</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> StratifiedKFold, cross_val_score, train_test_split</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.pipeline <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Pipeline</span>
<span id="cb1-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> StandardScaler</span>
<span id="cb1-11"></span>
<span id="cb1-12">SEMILLA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2026</span></span>
<span id="cb1-13">COLORES <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#2A6F97'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#D97706'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#2D6A4F'</span>]</span>
<span id="cb1-14">plt.rcParams.update({</span>
<span id="cb1-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'figure.figsize'</span>: (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb1-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.top'</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb1-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.right'</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb1-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.titleweight'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'bold'</span>,</span>
<span id="cb1-19">})</span></code></pre></div></div>
</div>
</section>
<section id="los-datos-trece-mediciones-químicas-de-vinos" class="level2">
<h2 class="anchored" data-anchor-id="los-datos-trece-mediciones-químicas-de-vinos">Los datos: trece mediciones químicas de vinos</h2>
<p>Usaremos <code>load_wine</code>, un conjunto clásico incluido en scikit-learn y disponible sin internet. Cada fila es un vino; las 13 columnas son mediciones químicas como alcohol, magnesio, fenoles y prolina.</p>
<p>El conjunto también contiene tres clases de origen. Las guardaremos aparte: no entrarán al ajuste de PCA.</p>
<div id="53c4ce76" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:51.902644Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:51.902340Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:51.950554Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:51.949894Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">wine <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> load_wine(as_frame<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb2-2">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> wine.data.copy()</span>
<span id="cb2-3">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> wine.target.copy()</span>
<span id="cb2-4">nombres_clase <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> wine.target_names</span>
<span id="cb2-5"></span>
<span id="cb2-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Observaciones: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Variables numéricas: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Observaciones por clase:'</span>, y.value_counts().sort_index().to_dict())</span>
<span id="cb2-9">display(X.head().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb2-10">display(X.describe().loc[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'std'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'min'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'max'</span>]].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Observaciones: 178
Variables numéricas: 13
Observaciones por clase: {0: 59, 1: 71, 2: 48}</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">alcohol</th>
<th data-quarto-table-cell-role="th">malic_acid</th>
<th data-quarto-table-cell-role="th">ash</th>
<th data-quarto-table-cell-role="th">alcalinity_of_ash</th>
<th data-quarto-table-cell-role="th">magnesium</th>
<th data-quarto-table-cell-role="th">total_phenols</th>
<th data-quarto-table-cell-role="th">flavanoids</th>
<th data-quarto-table-cell-role="th">nonflavanoid_phenols</th>
<th data-quarto-table-cell-role="th">proanthocyanins</th>
<th data-quarto-table-cell-role="th">color_intensity</th>
<th data-quarto-table-cell-role="th">hue</th>
<th data-quarto-table-cell-role="th">od280/od315_of_diluted_wines</th>
<th data-quarto-table-cell-role="th">proline</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>14.23</td>
<td>1.71</td>
<td>2.43</td>
<td>15.6</td>
<td>127.0</td>
<td>2.80</td>
<td>3.06</td>
<td>0.28</td>
<td>2.29</td>
<td>5.64</td>
<td>1.04</td>
<td>3.92</td>
<td>1065.0</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>13.20</td>
<td>1.78</td>
<td>2.14</td>
<td>11.2</td>
<td>100.0</td>
<td>2.65</td>
<td>2.76</td>
<td>0.26</td>
<td>1.28</td>
<td>4.38</td>
<td>1.05</td>
<td>3.40</td>
<td>1050.0</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>13.16</td>
<td>2.36</td>
<td>2.67</td>
<td>18.6</td>
<td>101.0</td>
<td>2.80</td>
<td>3.24</td>
<td>0.30</td>
<td>2.81</td>
<td>5.68</td>
<td>1.03</td>
<td>3.17</td>
<td>1185.0</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>14.37</td>
<td>1.95</td>
<td>2.50</td>
<td>16.8</td>
<td>113.0</td>
<td>3.85</td>
<td>3.49</td>
<td>0.24</td>
<td>2.18</td>
<td>7.80</td>
<td>0.86</td>
<td>3.45</td>
<td>1480.0</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>13.24</td>
<td>2.59</td>
<td>2.87</td>
<td>21.0</td>
<td>118.0</td>
<td>2.80</td>
<td>2.69</td>
<td>0.39</td>
<td>1.82</td>
<td>4.32</td>
<td>1.04</td>
<td>2.93</td>
<td>735.0</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">alcohol</th>
<th data-quarto-table-cell-role="th">malic_acid</th>
<th data-quarto-table-cell-role="th">ash</th>
<th data-quarto-table-cell-role="th">alcalinity_of_ash</th>
<th data-quarto-table-cell-role="th">magnesium</th>
<th data-quarto-table-cell-role="th">total_phenols</th>
<th data-quarto-table-cell-role="th">flavanoids</th>
<th data-quarto-table-cell-role="th">nonflavanoid_phenols</th>
<th data-quarto-table-cell-role="th">proanthocyanins</th>
<th data-quarto-table-cell-role="th">color_intensity</th>
<th data-quarto-table-cell-role="th">hue</th>
<th data-quarto-table-cell-role="th">od280/od315_of_diluted_wines</th>
<th data-quarto-table-cell-role="th">proline</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">mean</th>
<td>13.00</td>
<td>2.34</td>
<td>2.37</td>
<td>19.49</td>
<td>99.74</td>
<td>2.30</td>
<td>2.03</td>
<td>0.36</td>
<td>1.59</td>
<td>5.06</td>
<td>0.96</td>
<td>2.61</td>
<td>746.89</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">std</th>
<td>0.81</td>
<td>1.12</td>
<td>0.27</td>
<td>3.34</td>
<td>14.28</td>
<td>0.63</td>
<td>1.00</td>
<td>0.12</td>
<td>0.57</td>
<td>2.32</td>
<td>0.23</td>
<td>0.71</td>
<td>314.91</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">min</th>
<td>11.03</td>
<td>0.74</td>
<td>1.36</td>
<td>10.60</td>
<td>70.00</td>
<td>0.98</td>
<td>0.34</td>
<td>0.13</td>
<td>0.41</td>
<td>1.28</td>
<td>0.48</td>
<td>1.27</td>
<td>278.00</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">max</th>
<td>14.83</td>
<td>5.80</td>
<td>3.23</td>
<td>30.00</td>
<td>162.00</td>
<td>3.88</td>
<td>5.08</td>
<td>0.66</td>
<td>3.58</td>
<td>13.00</td>
<td>1.71</td>
<td>4.00</td>
<td>1680.00</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-este-resultado" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado">Cómo leer este resultado</h3>
<p>Tenemos <strong>178 vinos y 13 variables</strong>. Las clases contienen 59, 71 y 48 observaciones, pero esas etiquetas quedan fuera de <img src="https://latex.codecogs.com/png.latex?X">. Fíjate también en las escalas: <code>nonflavanoid_phenols</code> va de <strong>0.13 a 0.66</strong>, mientras <code>proline</code> va de <strong>278 a 1680</strong>. Esta diferencia será decisiva antes de calcular PCA.</p>
</section>
</section>
<section id="paso-1-detectar-redundancia-entre-variables" class="level2">
<h2 class="anchored" data-anchor-id="paso-1-detectar-redundancia-entre-variables">Paso 1: detectar redundancia entre variables</h2>
<p>Trece variables no parecen demasiadas, pero ya dificultan una inspección conjunta. Una matriz de correlaciones permite detectar pares que se mueven de forma parecida. Si abundan correlaciones altas, existe información compartida que unas pocas direcciones podrían resumir.</p>
<div id="c05511eb" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:51.952729Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:51.952530Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:52.201758Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:52.200956Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">correlaciones <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.corr()</span>
<span id="cb4-2">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>))</span>
<span id="cb4-3">imagen <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ax.imshow(correlaciones, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'RdBu_r'</span>, vmin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, vmax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb4-4">ax.set_xticks(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]), X.columns, rotation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">70</span>, ha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'right'</span>)</span>
<span id="cb4-5">ax.set_yticks(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]), X.columns)</span>
<span id="cb4-6">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Correlación entre las 13 mediciones'</span>)</span>
<span id="cb4-7">fig.colorbar(imagen, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ax, shrink<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'correlación'</span>)</span>
<span id="cb4-8">plt.tight_layout()</span>
<span id="cb4-9">plt.show()</span>
<span id="cb4-10"></span>
<span id="cb4-11">triangulo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> correlaciones.where(np.triu(np.ones(correlaciones.shape), k<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">bool</span>))</span>
<span id="cb4-12">pares <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> triangulo.stack().rename(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'correlación'</span>).to_frame()</span>
<span id="cb4-13">pares[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'magnitud'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pares[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'correlación'</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>()</span>
<span id="cb4-14">display(pares.sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'magnitud'</span>, ascending<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>).head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/12-pca/index_files/figure-html/cell-4-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">correlación</th>
<th data-quarto-table-cell-role="th">magnitud</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">total_phenols</th>
<th data-quarto-table-cell-role="th">flavanoids</th>
<td>0.865</td>
<td>0.865</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">flavanoids</th>
<th data-quarto-table-cell-role="th">od280/od315_of_diluted_wines</th>
<td>0.787</td>
<td>0.787</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">total_phenols</th>
<th data-quarto-table-cell-role="th">od280/od315_of_diluted_wines</th>
<td>0.700</td>
<td>0.700</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">flavanoids</th>
<th data-quarto-table-cell-role="th">proanthocyanins</th>
<td>0.653</td>
<td>0.653</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">alcohol</th>
<th data-quarto-table-cell-role="th">proline</th>
<td>0.644</td>
<td>0.644</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">total_phenols</th>
<th data-quarto-table-cell-role="th">proanthocyanins</th>
<td>0.612</td>
<td>0.612</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-este-resultado-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-1">Cómo leer este resultado</h3>
<p>El mapa no es uniforme: hay un bloque rojo de variables fenólicas (<code>total_phenols</code>, <code>flavanoids</code>, <code>proanthocyanins</code>, <code>od280/od315_of_diluted_wines</code>) y varias celdas azules, que marcan correlaciones negativas. El par más correlacionado es <code>total_phenols</code>–<code>flavanoids</code>, con <strong><img src="https://latex.codecogs.com/png.latex?r=0.865"></strong>. También aparecen relaciones fuertes con <code>od280/od315_of_diluted_wines</code>: <strong>0.787</strong> con <code>flavanoids</code> y <strong>0.700</strong> con <code>total_phenols</code>. No necesitamos elegir una variable y borrar la otra: PCA puede condensar su movimiento compartido.</p>
</section>
</section>
<section id="paso-2-estandarizar-antes-de-pca" class="level2">
<h2 class="anchored" data-anchor-id="paso-2-estandarizar-antes-de-pca">Paso 2: estandarizar antes de PCA</h2>
<p>PCA maximiza <strong>varianza</strong>. Si una variable está medida con números mucho mayores, puede dominar el resultado solo por sus unidades. Aquí la prolina usa centenas y miles, mientras otras mediciones se mantienen por debajo de 1.</p>
<p>Por eso la estandarización es obligatoria en este ejemplo. <code>StandardScaler</code>, que ya conoces, transforma cada columna como</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Az_%7Bij%7D=%5Cfrac%7Bx_%7Bij%7D-%5Cbar%7Bx%7D_j%7D%7B%5Csigma_j%7D,%0A%5Cqquad%0A%5Csigma_j=%5Csqrt%7B%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi=1%7D%5E%7Bn%7D(x_%7Bij%7D-%5Cbar%7Bx%7D_j)%5E2%7D.%0A"></p>
<p>Así, cada variable queda con media cercana a 0 y desviación estándar poblacional cercana a 1. PCA sobre datos estandarizados equivale a trabajar con la estructura de correlaciones, no con las unidades originales.</p>
<div id="77b99b94" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:52.203576Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:52.203291Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:52.246982Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:52.246341Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">escalador <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler()</span>
<span id="cb5-2">X_std <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> escalador.fit_transform(X)</span>
<span id="cb5-3"></span>
<span id="cb5-4">pca_sin_escalar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA().fit(X)</span>
<span id="cb5-5">pca_estandarizado_previo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA().fit(X_std)</span>
<span id="cb5-6">variable_dominante <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.columns[np.argmax(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(pca_sin_escalar.components_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]))]</span>
<span id="cb5-7"></span>
<span id="cb5-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Máxima media estandarizada en valor absoluto: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(X_std.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2e}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb5-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Desviaciones estándar poblacionales: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X_std<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>std(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X_std<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>std(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb5-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Sin escalar, PC1 explica: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pca_sin_escalar<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>explained_variance_ratio_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb5-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Variable dominante sin escalar: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>variable_dominante<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb5-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Estandarizado, PC1 explica: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pca_estandarizado_previo<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>explained_variance_ratio_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Máxima media estandarizada en valor absoluto: 8.38e-16
Desviaciones estándar poblacionales: 1.000 a 1.000
Sin escalar, PC1 explica: 99.81%
Variable dominante sin escalar: proline
Estandarizado, PC1 explica: 36.20%</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-2" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-2">Cómo leer este resultado</h3>
<p>Tras escalar, las medias son numéricamente 0 y todas las desviaciones estándar poblacionales son <strong>1.000</strong>. Sin estandarizar, PC1 (el primer componente principal; PC2 será el segundo, y así sucesivamente) atribuye <strong>99.81%</strong> de la varianza a una dirección dominada por <code>proline</code>: el algoritmo está leyendo unidades. Estandarizado, PC1 explica <strong>36.20%</strong> y combina varias mediciones.</p>
<p>La regla práctica es simple: si las unidades o escalas difieren, coloca <code>StandardScaler</code> antes de PCA. En un flujo predictivo ambos deben ir dentro del mismo <code>Pipeline</code> para evitar fuga de información.</p>
</section>
</section>
<section id="paso-3-intuición-geométrica-con-dos-variables" class="level2">
<h2 class="anchored" data-anchor-id="paso-3-intuición-geométrica-con-dos-variables">Paso 3: intuición geométrica con dos variables</h2>
<p>Tomemos las dos variables más correlacionadas. Después de estandarizarlas, una flecha mostrará el primer vector propio. Su orientación debe seguir el eje largo de la nube; una segunda dirección ortogonal recogería la dispersión restante.</p>
<div id="ebf5ccce" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:52.248694Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:52.248502Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:52.335669Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:52.334749Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">variables_2d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'total_phenols'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'flavanoids'</span>]</span>
<span id="cb7-2">X_2d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler().fit_transform(X[variables_2d])</span>
<span id="cb7-3">pca_2d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>).fit(X_2d)</span>
<span id="cb7-4">direccion_pc1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_2d.components_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb7-5">longitud <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.sqrt(pca_2d.explained_variance_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb7-6"></span>
<span id="cb7-7">plt.scatter(X_2d[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X_2d[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">28</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#457B9D'</span>)</span>
<span id="cb7-8">plt.arrow(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, longitud <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> direccion_pc1[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], longitud <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> direccion_pc1[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb7-9">          width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.035</span>, head_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#C2410C'</span>, length_includes_head<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb7-10">plt.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, lw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)</span>
<span id="cb7-11">plt.axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, lw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)</span>
<span id="cb7-12">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'fenoles totales (estandarizada)'</span>)</span>
<span id="cb7-13">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'flavonoides (estandarizada)'</span>)</span>
<span id="cb7-14">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC1 sigue la dirección de máxima varianza'</span>)</span>
<span id="cb7-15">plt.axis(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'equal'</span>)</span>
<span id="cb7-16">plt.show()</span>
<span id="cb7-17"></span>
<span id="cb7-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Correlación entre las variables: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X[variables_2d]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>corr()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb7-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Varianza explicada por PC1 en este plano: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pca_2d<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>explained_variance_ratio_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb7-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Dirección de PC1:'</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(direccion_pc1, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/12-pca/index_files/figure-html/cell-6-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Correlación entre las variables: 0.865
Varianza explicada por PC1 en este plano: 93.23%
Dirección de PC1: [0.707 0.707]</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-3" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-3">Cómo leer este resultado</h3>
<p>Las dos variables tienen correlación <strong>0.865</strong> y forman una nube alargada. La flecha de PC1 apunta en la dirección <img src="https://latex.codecogs.com/png.latex?(0.707,%200.707)=(1,1)/%5Csqrt%7B2%7D">: ambas variables contribuyen en el mismo sentido y con el mismo peso. Con dos variables estandarizadas y correlación positiva esto no es casualidad: la matriz de correlaciones <img src="https://latex.codecogs.com/png.latex?%5Cbegin%7Bpmatrix%7D1&amp;r%5C%5Cr&amp;1%5Cend%7Bpmatrix%7D"> siempre tiene ese vector propio, con <img src="https://latex.codecogs.com/png.latex?%5Clambda_1=1+r">. Por eso esa única dirección conserva <img src="https://latex.codecogs.com/png.latex?(1+r)/2="> <strong>93.23%</strong> de la varianza de este plano. Lo que los datos deciden es cuánta varianza captura PC1, no hacia dónde apunta; con más de dos variables, en cambio, la dirección sí depende de toda la estructura de correlaciones.</p>
<p>La ortogonalidad tiene una consecuencia útil: las coordenadas principales quedan no correlacionadas. Pero no confundas “no correlacionadas” con “independientes”; esa diferencia será central cuando lleguemos a ICA.</p>
</section>
<section id="antes-de-seguir-pregúntate" class="level3">
<h3 class="anchored" data-anchor-id="antes-de-seguir-pregúntate">Antes de seguir, pregúntate</h3>
<p>Si una sola dirección resume 93.23% de este plano, ¿qué esperas que ocurra al extender la idea a 13 variables? ¿Conservar dos componentes bastará, o necesitaremos más para retener el 90% de la información medida como varianza?</p>
</section>
</section>
<section id="paso-4-ajustar-pca-completo" class="level2">
<h2 class="anchored" data-anchor-id="paso-4-ajustar-pca-completo">Paso 4: ajustar PCA completo</h2>
<p>Ahora sí usamos las 13 variables estandarizadas. Ajustamos todos los componentes para observar cómo se reparte la varianza antes de decidir cuántos conservar. La proporción de varianza explicada (PVE) por el componente <img src="https://latex.codecogs.com/png.latex?j"> es</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7BPVE%7D_j=%5Cfrac%7B%5Clambda_j%7D%7B%5Csum_%7B%5Cell=1%7D%5E%7Bp%7D%5Clambda_%5Cell%7D.%0A"></p>
<div id="c2c1f40c" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:52.337574Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:52.337363Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:52.422346Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:52.421552Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1">pca_completo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA()</span>
<span id="cb9-2">scores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_completo.fit_transform(X_std)</span>
<span id="cb9-3">varianza_explicada <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_completo.explained_variance_ratio_</span>
<span id="cb9-4">varianza_acumulada <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cumsum(varianza_explicada)</span>
<span id="cb9-5"></span>
<span id="cb9-6">W <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_completo.components_.T</span>
<span id="cb9-7">error_ortogonalidad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(W.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> W <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> np.eye(X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])))</span>
<span id="cb9-8">covarianza_scores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cov(scores, rowvar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb9-9">max_covarianza_cruzada <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(covarianza_scores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> np.diag(np.diag(covarianza_scores))))</span>
<span id="cb9-10"></span>
<span id="cb9-11">tabla_varianza <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb9-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'componente'</span>: np.arange(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb9-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'varianza_explicada'</span>: varianza_explicada,</span>
<span id="cb9-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'varianza_acumulada'</span>: varianza_acumulada,</span>
<span id="cb9-15">})</span>
<span id="cb9-16">display(tabla_varianza.style.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">format</span>({</span>
<span id="cb9-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'varianza_explicada'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{:.2%}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>,</span>
<span id="cb9-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'varianza_acumulada'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{:.2%}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>,</span>
<span id="cb9-19">}))</span>
<span id="cb9-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Error máximo en WᵀW = I: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>error_ortogonalidad<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2e}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb9-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Máxima covarianza cruzada entre scores: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>max_covarianza_cruzada<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2e}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<style type="text/css">
</style>

<table id="T_25a57" class="caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th class="blank level0" data-quarto-table-cell-role="th">&nbsp;</th>
<th id="T_25a57_level0_col0" class="col_heading level0 col0" data-quarto-table-cell-role="th">componente</th>
<th id="T_25a57_level0_col1" class="col_heading level0 col1" data-quarto-table-cell-role="th">varianza_explicada</th>
<th id="T_25a57_level0_col2" class="col_heading level0 col2" data-quarto-table-cell-role="th">varianza_acumulada</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th id="T_25a57_level0_row0" class="row_heading level0 row0" data-quarto-table-cell-role="th">0</th>
<td id="T_25a57_row0_col0" class="data row0 col0">1</td>
<td id="T_25a57_row0_col1" class="data row0 col1">36.20%</td>
<td id="T_25a57_row0_col2" class="data row0 col2">36.20%</td>
</tr>
<tr class="even">
<th id="T_25a57_level0_row1" class="row_heading level0 row1" data-quarto-table-cell-role="th">1</th>
<td id="T_25a57_row1_col0" class="data row1 col0">2</td>
<td id="T_25a57_row1_col1" class="data row1 col1">19.21%</td>
<td id="T_25a57_row1_col2" class="data row1 col2">55.41%</td>
</tr>
<tr class="odd">
<th id="T_25a57_level0_row2" class="row_heading level0 row2" data-quarto-table-cell-role="th">2</th>
<td id="T_25a57_row2_col0" class="data row2 col0">3</td>
<td id="T_25a57_row2_col1" class="data row2 col1">11.12%</td>
<td id="T_25a57_row2_col2" class="data row2 col2">66.53%</td>
</tr>
<tr class="even">
<th id="T_25a57_level0_row3" class="row_heading level0 row3" data-quarto-table-cell-role="th">3</th>
<td id="T_25a57_row3_col0" class="data row3 col0">4</td>
<td id="T_25a57_row3_col1" class="data row3 col1">7.07%</td>
<td id="T_25a57_row3_col2" class="data row3 col2">73.60%</td>
</tr>
<tr class="odd">
<th id="T_25a57_level0_row4" class="row_heading level0 row4" data-quarto-table-cell-role="th">4</th>
<td id="T_25a57_row4_col0" class="data row4 col0">5</td>
<td id="T_25a57_row4_col1" class="data row4 col1">6.56%</td>
<td id="T_25a57_row4_col2" class="data row4 col2">80.16%</td>
</tr>
<tr class="even">
<th id="T_25a57_level0_row5" class="row_heading level0 row5" data-quarto-table-cell-role="th">5</th>
<td id="T_25a57_row5_col0" class="data row5 col0">6</td>
<td id="T_25a57_row5_col1" class="data row5 col1">4.94%</td>
<td id="T_25a57_row5_col2" class="data row5 col2">85.10%</td>
</tr>
<tr class="odd">
<th id="T_25a57_level0_row6" class="row_heading level0 row6" data-quarto-table-cell-role="th">6</th>
<td id="T_25a57_row6_col0" class="data row6 col0">7</td>
<td id="T_25a57_row6_col1" class="data row6 col1">4.24%</td>
<td id="T_25a57_row6_col2" class="data row6 col2">89.34%</td>
</tr>
<tr class="even">
<th id="T_25a57_level0_row7" class="row_heading level0 row7" data-quarto-table-cell-role="th">7</th>
<td id="T_25a57_row7_col0" class="data row7 col0">8</td>
<td id="T_25a57_row7_col1" class="data row7 col1">2.68%</td>
<td id="T_25a57_row7_col2" class="data row7 col2">92.02%</td>
</tr>
<tr class="odd">
<th id="T_25a57_level0_row8" class="row_heading level0 row8" data-quarto-table-cell-role="th">8</th>
<td id="T_25a57_row8_col0" class="data row8 col0">9</td>
<td id="T_25a57_row8_col1" class="data row8 col1">2.22%</td>
<td id="T_25a57_row8_col2" class="data row8 col2">94.24%</td>
</tr>
<tr class="even">
<th id="T_25a57_level0_row9" class="row_heading level0 row9" data-quarto-table-cell-role="th">9</th>
<td id="T_25a57_row9_col0" class="data row9 col0">10</td>
<td id="T_25a57_row9_col1" class="data row9 col1">1.93%</td>
<td id="T_25a57_row9_col2" class="data row9 col2">96.17%</td>
</tr>
<tr class="odd">
<th id="T_25a57_level0_row10" class="row_heading level0 row10" data-quarto-table-cell-role="th">10</th>
<td id="T_25a57_row10_col0" class="data row10 col0">11</td>
<td id="T_25a57_row10_col1" class="data row10 col1">1.74%</td>
<td id="T_25a57_row10_col2" class="data row10 col2">97.91%</td>
</tr>
<tr class="even">
<th id="T_25a57_level0_row11" class="row_heading level0 row11" data-quarto-table-cell-role="th">11</th>
<td id="T_25a57_row11_col0" class="data row11 col0">12</td>
<td id="T_25a57_row11_col1" class="data row11 col1">1.30%</td>
<td id="T_25a57_row11_col2" class="data row11 col2">99.20%</td>
</tr>
<tr class="odd">
<th id="T_25a57_level0_row12" class="row_heading level0 row12" data-quarto-table-cell-role="th">12</th>
<td id="T_25a57_row12_col0" class="data row12 col0">13</td>
<td id="T_25a57_row12_col1" class="data row12 col1">0.80%</td>
<td id="T_25a57_row12_col2" class="data row12 col2">100.00%</td>
</tr>
</tbody>
</table>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Error máximo en WᵀW = I: 1.78e-15
Máxima covarianza cruzada entre scores: 7.43e-16</code></pre>
</div>
</div>
<section id="cómo-leer-esta-tabla" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-tabla">Cómo leer esta tabla</h3>
<p>PC1 explica <strong>36.20%</strong> y PC2, <strong>19.21%</strong>. Juntas conservan <strong>55.41%</strong> de la varianza total: resumen mucho, pero casi la mitad todavía queda en otras direcciones. PC3 añade <strong>11.12%</strong> y lleva el acumulado a <strong>66.53%</strong>.</p>
<p>Las contribuciones disminuyen porque PCA ordena los valores propios de mayor a menor. Además, el error máximo de <strong><img src="https://latex.codecogs.com/png.latex?1.78%5Ctimes10%5E%7B-15%7D"></strong> en <img src="https://latex.codecogs.com/png.latex?W%5E%5Ctop%20W=I"> confirma que las direcciones son ortonormales, y la máxima covarianza cruzada de <strong><img src="https://latex.codecogs.com/png.latex?7.43%5Ctimes10%5E%7B-16%7D"></strong> confirma que los <em>scores</em> están no correlacionados, salvo precisión numérica.</p>
<p>No existe una frontera universal entre componente útil e inútil; necesitas una regla explícita ligada al propósito.</p>
</section>
</section>
<section id="cuántos-componentes-conservar" class="level2">
<h2 class="anchored" data-anchor-id="cuántos-componentes-conservar">Cuántos componentes conservar</h2>
<p>Dos criterios habituales son:</p>
<ul>
<li><strong>Regla del codo:</strong> busca dónde las ganancias marginales del <em>scree plot</em> comienzan a aplanarse. Es visual y puede ser ambigua.</li>
<li><strong>Umbral acumulado:</strong> elige el menor <img src="https://latex.codecogs.com/png.latex?k"> que alcance, por ejemplo, 90% o 95% de varianza. Es reproducible, pero el umbral depende del costo de perder información.</li>
</ul>
<p>Para una tarea predictiva, <img src="https://latex.codecogs.com/png.latex?k"> es un hiperparámetro: conviene contrastarlo mediante validación cruzada sobre entrenamiento, no escogerlo mirando el conjunto de prueba.</p>
<div id="f7dc80e9" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:52.424007Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:52.423810Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:52.637736Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:52.637201Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1">componentes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb11-2">k_90 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argmax(varianza_acumulada <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.90</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb11-3">k_95 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argmax(varianza_acumulada <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb11-4"></span>
<span id="cb11-5">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.5</span>))</span>
<span id="cb11-6">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].bar(componentes, varianza_explicada, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#457B9D'</span>)</span>
<span id="cb11-7">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(componentes, varianza_explicada, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#17324D'</span>, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>)</span>
<span id="cb11-8">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Scree plot'</span>, xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'componente'</span>, ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'proporción de varianza'</span>)</span>
<span id="cb11-9">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_xticks(componentes)</span>
<span id="cb11-10"></span>
<span id="cb11-11">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(componentes, varianza_acumulada, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#2D6A4F'</span>, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, lw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb11-12">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].axhline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.90</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#D97706'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'90%'</span>)</span>
<span id="cb11-13">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].axhline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#B42318'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'95%'</span>)</span>
<span id="cb11-14">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Varianza explicada acumulada'</span>, xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'número de componentes'</span>, ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'proporción acumulada'</span>, ylim<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.03</span>))</span>
<span id="cb11-15">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xticks(componentes)</span>
<span id="cb11-16">ax[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].legend()</span>
<span id="cb11-17">plt.tight_layout()</span>
<span id="cb11-18">plt.show()</span>
<span id="cb11-19"></span>
<span id="cb11-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Mínimo para alcanzar 90%: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k_90<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> componentes (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>varianza_acumulada[k_90 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb11-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Mínimo para alcanzar 95%: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k_95<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> componentes (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>varianza_acumulada[k_95 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/12-pca/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Mínimo para alcanzar 90%: 8 componentes (92.02%)
Mínimo para alcanzar 95%: 10 componentes (96.17%)</code></pre>
</div>
</div>
<section id="cómo-leer-estas-curvas" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estas-curvas">Cómo leer estas curvas</h3>
<p>La pendiente cae con rapidez en los primeros componentes y luego se aplana: el codo visual está alrededor de <strong>3 a 5 componentes</strong>. Con un criterio cuantitativo, necesitas <strong>8 componentes para superar 90%</strong> (alcanzan <strong>92.02%</strong>) y <strong>10 para superar 95%</strong> (alcanzan <strong>96.17%</strong>).</p>
<p>No hay contradicción: el codo favorece una representación compacta; el umbral exige conservar una fracción prefijada. La decisión final depende de si priorizas visualización, compresión o desempeño posterior.</p>
</section>
</section>
<section id="paso-5-proyectar-los-vinos-en-dos-componentes" class="level2">
<h2 class="anchored" data-anchor-id="paso-5-proyectar-los-vinos-en-dos-componentes">Paso 5: proyectar los vinos en dos componentes</h2>
<p>Para visualizar, conservamos PC1 y PC2. Cada punto seguirá siendo un vino, pero sus coordenadas ya no serán alcohol o magnesio: serán dos combinaciones de las 13 variables.</p>
<p>Colorearemos los puntos con la etiqueta real <strong>después</strong> de ajustar PCA. El color sirve para comprobar si la estructura no supervisada coincide con grupos conocidos; no participó en el cálculo de los ejes.</p>
<div id="43854246" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:52.640042Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:52.639842Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:52.756949Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:52.755891Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb13-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> clase, nombre, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(np.unique(y), nombres_clase, COLORES):</span>
<span id="cb13-3">    mascara <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y.to_numpy() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> clase</span>
<span id="cb13-4">    ax.scatter(scores[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], scores[mascara, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">48</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.75</span>,</span>
<span id="cb13-5">               color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombre, edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'white'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>)</span>
<span id="cb13-6">ax.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, lw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)</span>
<span id="cb13-7">ax.axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, lw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)</span>
<span id="cb13-8">ax.set_xlabel(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PC1 (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>varianza_explicada[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb13-9">ax.set_ylabel(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PC2 (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>varianza_explicada[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb13-10">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Proyección no supervisada; color añadido solo para interpretar'</span>)</span>
<span id="cb13-11">ax.legend(title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clase real'</span>)</span>
<span id="cb13-12">plt.show()</span>
<span id="cb13-13"></span>
<span id="cb13-14">centroides <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(scores[:, :<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>]).assign(clase<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y.to_numpy()).groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clase'</span>).mean()</span>
<span id="cb13-15">centroides.index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nombres_clase</span>
<span id="cb13-16">display(centroides.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/12-pca/index_files/figure-html/cell-9-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">PC1</th>
<th data-quarto-table-cell-role="th">PC2</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">class_0</th>
<td>2.283</td>
<td>0.968</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">class_1</th>
<td>-0.039</td>
<td>-1.643</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">class_2</th>
<td>-2.748</td>
<td>1.241</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-esta-proyección" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-proyección">Cómo leer esta proyección</h3>
<p>Aunque PCA nunca vio las etiquetas, aparecen tres regiones bastante claras. Los centroides de <code>class_0</code>, <code>class_1</code> y <code>class_2</code> están en PC1 en <strong>2.283, -0.039 y -2.748</strong>, respectivamente. PC1 separa con fuerza las clases 0 y 2; PC2 ayuda especialmente a desplazar <code>class_1</code>, cuyo centro está en <strong>-1.643</strong>.</p>
<p>Esto muestra una alineación útil entre alta varianza y clases, no una garantía general. En otro conjunto, la señal que separa etiquetas podría estar en una dirección de baja varianza y PCA podría descartarla.</p>
</section>
</section>
<section id="qué-representan-pc1-y-pc2-leer-las-cargas" class="level2">
<h2 class="anchored" data-anchor-id="qué-representan-pc1-y-pc2-leer-las-cargas">Qué representan PC1 y PC2: leer las cargas</h2>
<p>Cada coeficiente de <code>PCA.components_</code> indica cuánto participa una variable estandarizada en la dirección de un componente. En este notebook llamaremos <strong>cargas</strong> a esos coeficientes de los vectores propios unitarios: una magnitud grande implica mayor participación y el signo indica dirección relativa. En otros textos, “carga” puede referirse al coeficiente escalado por <img src="https://latex.codecogs.com/png.latex?%5Csqrt%7B%5Clambda_j%7D">, que se relaciona con la correlación entre variable y componente.</p>
<p>El signo global es arbitrario: multiplicar un vector propio y sus <em>scores</em> por <img src="https://latex.codecogs.com/png.latex?-1"> describe exactamente el mismo eje. Por eso interpreta patrones de magnitud y contraste, no etiquetas como “positivo” o “negativo” de forma aislada.</p>
<div id="d6c7b2f5" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:52.758838Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:52.758621Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:52.999218Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:52.998412Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">cargas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb14-2">    pca_completo.components_[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].T,</span>
<span id="cb14-3">    index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>X.columns,</span>
<span id="cb14-4">    columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>],</span>
<span id="cb14-5">)</span>
<span id="cb14-6"></span>
<span id="cb14-7">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb14-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> eje, componente, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(ax, [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>], [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#2A6F97'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#D97706'</span>]):</span>
<span id="cb14-9">    orden <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cargas[componente].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>().sort_values().index</span>
<span id="cb14-10">    eje.barh(orden, cargas.loc[orden, componente], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color)</span>
<span id="cb14-11">    eje.axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'black'</span>, lw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb14-12">    eje.set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Cargas de </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>componente<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb14-13">    eje.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'carga'</span>)</span>
<span id="cb14-14">plt.tight_layout()</span>
<span id="cb14-15">plt.show()</span>
<span id="cb14-16"></span>
<span id="cb14-17"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> componente <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>]:</span>
<span id="cb14-18">    principales <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cargas[componente].reindex(cargas[componente].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>().sort_values(ascending<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>).index).head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb14-19">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Cinco mayores cargas absolutas de </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>componente<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">:'</span>)</span>
<span id="cb14-20">    display(principales.to_frame(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'carga'</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/12-pca/index_files/figure-html/cell-10-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Cinco mayores cargas absolutas de PC1:</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">carga</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">flavanoids</th>
<td>0.423</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">total_phenols</th>
<td>0.395</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">od280/od315_of_diluted_wines</th>
<td>0.376</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">proanthocyanins</th>
<td>0.313</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">nonflavanoid_phenols</th>
<td>-0.299</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Cinco mayores cargas absolutas de PC2:</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">carga</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">color_intensity</th>
<td>0.530</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">alcohol</th>
<td>0.484</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">proline</th>
<td>0.365</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">ash</th>
<td>0.316</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">magnesium</th>
<td>0.300</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-las-cargas" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-las-cargas">Cómo leer las cargas</h3>
<p>En PC1 destacan sobre todo <code>flavanoids</code> (<strong>0.423</strong>), <code>total_phenols</code> (<strong>0.395</strong>) y <code>od280/od315_of_diluted_wines</code> (<strong>0.376</strong>): el eje resume principalmente un patrón fenólico compartido. <code>nonflavanoid_phenols</code> apunta en sentido contrario (<strong>-0.299</strong>).</p>
<p>PC2 está marcado por <code>color_intensity</code> (<strong>0.530</strong>), <code>alcohol</code> (<strong>0.484</strong>) y <code>proline</code> (<strong>0.365</strong>). Recuerda que hablamos de variables estandarizadas: estas magnitudes son comparables y no favorecen a la prolina por estar medida en cientos.</p>
</section>
<section id="dos-precauciones-al-interpretar" class="level3">
<h3 class="anchored" data-anchor-id="dos-precauciones-al-interpretar">Dos precauciones al interpretar</h3>
<ol type="1">
<li><strong>PCA describe variación, no causalidad.</strong> Una carga alta no demuestra que una variable origine el patrón.</li>
<li><strong>Los componentes dependen del preprocesamiento.</strong> Cambiar variables, transformar distribuciones o no estandarizar puede rotar por completo la solución.</li>
</ol>
<p>Las cargas son una traducción útil de los ejes, pero siempre deben leerse junto con el contexto de las mediciones.</p>
</section>
</section>
<section id="paso-6-reconstrucción-y-compresión" class="level2">
<h2 class="anchored" data-anchor-id="paso-6-reconstrucción-y-compresión">Paso 6: reconstrucción y compresión</h2>
<p>Con <img src="https://latex.codecogs.com/png.latex?k"> componentes guardamos los <em>scores</em> <img src="https://latex.codecogs.com/png.latex?Z_k=(X_%7Bstd%7D-%5Cmu_%7BPCA%7D)W_k"> en lugar de las 13 coordenadas originales, donde <img src="https://latex.codecogs.com/png.latex?W_k"> reúne las primeras <img src="https://latex.codecogs.com/png.latex?k"> columnas de <img src="https://latex.codecogs.com/png.latex?W"> y <img src="https://latex.codecogs.com/png.latex?%5Cmu_%7BPCA%7D"> es la media que PCA resta (aquí prácticamente cero, porque los datos ya están estandarizados). Podemos aproximar los datos estandarizados mediante</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cwidehat%20X_%7Bstd%7D=Z_kW_k%5E%5Ctop+%5Cmu_%7BPCA%7D.%0A"></p>
<p><code>pca_4.inverse_transform</code> realiza esa reconstrucción en el espacio estandarizado e incorpora la media <img src="https://latex.codecogs.com/png.latex?%5Cmu_%7BPCA%7D">. Después, <code>escalador.inverse_transform</code> deshace la estandarización para volver a las unidades originales. Si <img src="https://latex.codecogs.com/png.latex?k%3C13">, la reconstrucción pierde información; el error cuadrático medio (MSE) cuantifica cuánto. Para ilustrarlo usaremos <img src="https://latex.codecogs.com/png.latex?k=4">, un valor dentro del codo visual de 3 a 5 componentes.</p>
<div id="7d08ef32" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:53.001110Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:53.000795Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:53.011938Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:53.011316Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1">k_compresion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb17-2">pca_4 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k_compresion).fit(X_std)</span>
<span id="cb17-3">X_std_reconstruido_4 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_4.inverse_transform(pca_4.transform(X_std))</span>
<span id="cb17-4">X_reconstruido_4 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> escalador.inverse_transform(X_std_reconstruido_4)</span>
<span id="cb17-5">mse_4 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean((X_std <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> X_std_reconstruido_4) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb17-6"></span>
<span id="cb17-7">comparacion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb17-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'original'</span>: X.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>],</span>
<span id="cb17-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'reconstruido_con_4_PC'</span>: X_reconstruido_4[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>],</span>
<span id="cb17-10">})</span>
<span id="cb17-11">comparacion[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'error_absoluto'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (comparacion[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'original'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> comparacion[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'reconstruido_con_4_PC'</span>]).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>()</span>
<span id="cb17-12">display(comparacion.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb17-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Varianza conservada con 4 componentes: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>varianza_acumulada[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb17-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'MSE de reconstrucción en escala estandarizada: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mse_4<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb17-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Reducción de dimensiones: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> -&gt; </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k_compresion<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">original</th>
<th data-quarto-table-cell-role="th">reconstruido_con_4_PC</th>
<th data-quarto-table-cell-role="th">error_absoluto</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">alcohol</th>
<td>14.23</td>
<td>13.984</td>
<td>0.246</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">malic_acid</th>
<td>1.71</td>
<td>1.647</td>
<td>0.063</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">ash</th>
<td>2.43</td>
<td>2.474</td>
<td>0.044</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">alcalinity_of_ash</th>
<td>15.60</td>
<td>16.419</td>
<td>0.819</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">magnesium</th>
<td>127.00</td>
<td>113.381</td>
<td>13.619</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">total_phenols</th>
<td>2.80</td>
<td>3.129</td>
<td>0.329</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">flavanoids</th>
<td>3.06</td>
<td>3.364</td>
<td>0.304</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">nonflavanoid_phenols</th>
<td>0.28</td>
<td>0.246</td>
<td>0.034</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">proanthocyanins</th>
<td>2.29</td>
<td>2.153</td>
<td>0.137</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">color_intensity</th>
<td>5.64</td>
<td>6.167</td>
<td>0.527</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">hue</th>
<td>1.04</td>
<td>1.108</td>
<td>0.068</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">od280/od315_of_diluted_wines</th>
<td>3.92</td>
<td>3.279</td>
<td>0.641</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">proline</th>
<td>1065.00</td>
<td>1233.268</td>
<td>168.268</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Varianza conservada con 4 componentes: 73.60%
MSE de reconstrucción en escala estandarizada: 0.2640
Reducción de dimensiones: 13 -&gt; 4</code></pre>
</div>
</div>
<section id="cómo-leer-esta-reconstrucción" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-reconstrucción">Cómo leer esta reconstrucción</h3>
<p>Cuatro números por vino reemplazan temporalmente las 13 mediciones: una reducción de <strong>13 a 4 dimensiones</strong>. Al reconstruir, conservamos <strong>73.60%</strong> de la varianza y obtenemos un MSE estandarizado de <strong>0.2640</strong>.</p>
<p>No es coincidencia que <img src="https://latex.codecogs.com/png.latex?0.2640%20=%201%20-%200.7360">: con variables estandarizadas, el MSE de reconstrucción es exactamente la fracción de varianza que descartan los componentes omitidos.</p>
<p>La tabla compara el primer vino con su aproximación. No esperes igualdad exacta: la compresión conserva las direcciones dominantes y sacrifica detalles. En unidades originales, <code>proline</code> pasa de 1065 a 1233.268 (error absoluto de <strong>168.268</strong>) y <code>magnesium</code> de 127 a 113.381, mientras que las demás variables se desvían menos de 1 unidad. Medir el error en escala estandarizada evita que <code>proline</code> monopolice la métrica.</p>
</section>
</section>
<section id="experimento-error-frente-a-número-de-componentes" class="level2">
<h2 class="anchored" data-anchor-id="experimento-error-frente-a-número-de-componentes">Experimento: error frente a número de componentes</h2>
<p>Repetiremos la reconstrucción para <img src="https://latex.codecogs.com/png.latex?k=1,%5Cldots,13">. Al añadir componentes, el subespacio disponible crece, así que el error no puede aumentar. Con los 13 componentes recuperamos toda la información salvo precisión numérica.</p>
<div id="b6575c34" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:53.013993Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:53.013715Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:53.120604Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:53.119763Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1">errores_reconstruccion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb19-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>):</span>
<span id="cb19-3">    pca_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k).fit(X_std)</span>
<span id="cb19-4">    reconstruccion_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_k.inverse_transform(pca_k.transform(X_std))</span>
<span id="cb19-5">    errores_reconstruccion.append(np.mean((X_std <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> reconstruccion_k) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb19-6"></span>
<span id="cb19-7">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb19-8">ax.plot(componentes, errores_reconstruccion, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#B42318'</span>, lw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb19-9">ax.scatter([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span>], np.array(errores_reconstruccion)[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>]],</span>
<span id="cb19-10">           s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#D97706'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#2D6A4F'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#17324D'</span>], zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb19-11">ax.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Más componentes, menor error de reconstrucción'</span>,</span>
<span id="cb19-12">       xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'número de componentes'</span>, ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MSE en escala estandarizada'</span>)</span>
<span id="cb19-13">ax.set_xticks(componentes)</span>
<span id="cb19-14">plt.show()</span>
<span id="cb19-15"></span>
<span id="cb19-16"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span>]:</span>
<span id="cb19-17">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'k=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&gt;2}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: MSE = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>errores_reconstruccion[k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/12-pca/index_files/figure-html/cell-12-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>k= 1: MSE = 0.6380
k= 4: MSE = 0.2640
k= 8: MSE = 0.0798
k=13: MSE = 0.0000</code></pre>
</div>
</div>
<section id="cómo-leer-este-experimento" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-experimento">Cómo leer este experimento</h3>
<p>El MSE baja de <strong>0.6380 con 1 componente</strong> a <strong>0.2640 con 4</strong> y <strong>0.0798 con 8</strong>. Con los 13 componentes es <strong>0.0000</strong> porque ya no descartamos ninguna dirección. Cada valor es la varianza descartada de la tabla de varianza acumulada: <img src="https://latex.codecogs.com/png.latex?0.6380%20=%201%20-%200.3620"> y <img src="https://latex.codecogs.com/png.latex?0.0798%20=%201%20-%200.9202">.</p>
<p>La curva hace visible el precio de comprimir. Pasar de 4 a 8 componentes reduce el error de 0.2640 a 0.0798 (casi 70% menos), pero duplica el tamaño de la representación. Tu elección de <img src="https://latex.codecogs.com/png.latex?k"> expresa qué pérdida toleras a cambio de simplicidad.</p>
</section>
</section>
<section id="utilidad-práctica-un-modelo-predictivo-de-referencia" class="level2">
<h2 class="anchored" data-anchor-id="utilidad-práctica-un-modelo-predictivo-de-referencia">Utilidad práctica: un modelo predictivo de referencia</h2>
<p>PCA no necesita etiquetas, pero sus componentes pueden alimentar un modelo supervisado. Compararemos una regresión logística con las 13 variables frente a otra que recibe solo los primeros <img src="https://latex.codecogs.com/png.latex?k"> componentes.</p>
<p>El PCA anterior tuvo un propósito <strong>descriptivo</strong> y usó todo el conjunto para explicar su estructura; ninguno de sus objetos se reutiliza aquí. Para la comparación predictiva creamos una partición nueva, reservamos 30% para prueba y tomamos todas las decisiones con el 70% de entrenamiento.</p>
<p>En entrenamiento elegimos <img src="https://latex.codecogs.com/png.latex?k"> por validación cruzada estratificada probando todos los valores de 1 a 13. Con <img src="https://latex.codecogs.com/png.latex?k=13">, PCA solo gira los datos estandarizados y el modelo equivale al de referencia con las 13 variables, así que la misma tabla compara ambas opciones sin tocar la prueba. Tanto el escalado como PCA quedan dentro del <code>Pipeline</code>: cada <em>fold</em> (cada una de las cinco particiones de la validación cruzada) aprende sus transformaciones sin mirar su partición de validación, y el conjunto de prueba permanece intacto hasta el reporte final.</p>
<div id="421b9d15" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:53.122658Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:53.122357Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:53.904327Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:53.903583Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1">X_train, X_test, y_train, y_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(</span>
<span id="cb21-2">    X, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA, stratify<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y</span>
<span id="cb21-3">)</span>
<span id="cb21-4">cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StratifiedKFold(n_splits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA)</span>
<span id="cb21-5">candidatos_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb21-6">resultados_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb21-7"></span>
<span id="cb21-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> candidatos_k:</span>
<span id="cb21-9">    pipeline_pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([</span>
<span id="cb21-10">        (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'escalador'</span>, StandardScaler()),</span>
<span id="cb21-11">        (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pca'</span>, PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k)),</span>
<span id="cb21-12">        (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clasificador'</span>, LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>)),</span>
<span id="cb21-13">    ])</span>
<span id="cb21-14">    scores_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cross_val_score(pipeline_pca, X_train, y_train, cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>cv, scoring<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'accuracy'</span>)</span>
<span id="cb21-15">    resultados_cv.append({</span>
<span id="cb21-16">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k'</span>: k,</span>
<span id="cb21-17">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'exactitud_media_cv'</span>: scores_cv.mean(),</span>
<span id="cb21-18">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desviación_cv'</span>: scores_cv.std(),</span>
<span id="cb21-19">    })</span>
<span id="cb21-20"></span>
<span id="cb21-21">tabla_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(resultados_cv)</span>
<span id="cb21-22">mejor_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(tabla_cv.loc[tabla_cv[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'exactitud_media_cv'</span>].idxmax(), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k'</span>])</span>
<span id="cb21-23"></span>
<span id="cb21-24">representacion_elegida <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([</span>
<span id="cb21-25">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'escalador'</span>, StandardScaler()),</span>
<span id="cb21-26">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pca'</span>, PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mejor_k)),</span>
<span id="cb21-27">]).fit(X_train)</span>
<span id="cb21-28">varianza_mejor_k_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> representacion_elegida.named_steps[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pca'</span>].explained_variance_ratio_.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()</span>
<span id="cb21-29"></span>
<span id="cb21-30">display(tabla_cv.style.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">format</span>({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'exactitud_media_cv'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{:.3f}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desviación_cv'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{:.3f}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>}))</span>
<span id="cb21-31"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'k elegido solo con entrenamiento: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_k<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb21-32"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Varianza de entrenamiento conservada: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>varianza_mejor_k_train<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb21-33"></span>
<span id="cb21-34">plt.errorbar(tabla_cv[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k'</span>], tabla_cv[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'exactitud_media_cv'</span>], yerr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>tabla_cv[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desviación_cv'</span>],</span>
<span id="cb21-35">             marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, capsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#2A6F97'</span>)</span>
<span id="cb21-36">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'número de componentes'</span>)</span>
<span id="cb21-37">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'exactitud en validación cruzada'</span>)</span>
<span id="cb21-38">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Selección de k sin mirar el conjunto de prueba'</span>)</span>
<span id="cb21-39">plt.xticks(candidatos_k)</span>
<span id="cb21-40">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<style type="text/css">
</style>

<table id="T_5d745" class="caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th class="blank level0" data-quarto-table-cell-role="th">&nbsp;</th>
<th id="T_5d745_level0_col0" class="col_heading level0 col0" data-quarto-table-cell-role="th">k</th>
<th id="T_5d745_level0_col1" class="col_heading level0 col1" data-quarto-table-cell-role="th">exactitud_media_cv</th>
<th id="T_5d745_level0_col2" class="col_heading level0 col2" data-quarto-table-cell-role="th">desviación_cv</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th id="T_5d745_level0_row0" class="row_heading level0 row0" data-quarto-table-cell-role="th">0</th>
<td id="T_5d745_row0_col0" class="data row0 col0">1</td>
<td id="T_5d745_row0_col1" class="data row0 col1">0.855</td>
<td id="T_5d745_row0_col2" class="data row0 col2">0.053</td>
</tr>
<tr class="even">
<th id="T_5d745_level0_row1" class="row_heading level0 row1" data-quarto-table-cell-role="th">1</th>
<td id="T_5d745_row1_col0" class="data row1 col0">2</td>
<td id="T_5d745_row1_col1" class="data row1 col1">0.976</td>
<td id="T_5d745_row1_col2" class="data row1 col2">0.020</td>
</tr>
<tr class="odd">
<th id="T_5d745_level0_row2" class="row_heading level0 row2" data-quarto-table-cell-role="th">2</th>
<td id="T_5d745_row2_col0" class="data row2 col0">3</td>
<td id="T_5d745_row2_col1" class="data row2 col1">0.968</td>
<td id="T_5d745_row2_col2" class="data row2 col2">0.030</td>
</tr>
<tr class="even">
<th id="T_5d745_level0_row3" class="row_heading level0 row3" data-quarto-table-cell-role="th">3</th>
<td id="T_5d745_row3_col0" class="data row3 col0">4</td>
<td id="T_5d745_row3_col1" class="data row3 col1">0.984</td>
<td id="T_5d745_row3_col2" class="data row3 col2">0.020</td>
</tr>
<tr class="odd">
<th id="T_5d745_level0_row4" class="row_heading level0 row4" data-quarto-table-cell-role="th">4</th>
<td id="T_5d745_row4_col0" class="data row4 col0">5</td>
<td id="T_5d745_row4_col1" class="data row4 col1">0.976</td>
<td id="T_5d745_row4_col2" class="data row4 col2">0.020</td>
</tr>
<tr class="even">
<th id="T_5d745_level0_row5" class="row_heading level0 row5" data-quarto-table-cell-role="th">5</th>
<td id="T_5d745_row5_col0" class="data row5 col0">6</td>
<td id="T_5d745_row5_col1" class="data row5 col1">0.976</td>
<td id="T_5d745_row5_col2" class="data row5 col2">0.020</td>
</tr>
<tr class="odd">
<th id="T_5d745_level0_row6" class="row_heading level0 row6" data-quarto-table-cell-role="th">6</th>
<td id="T_5d745_row6_col0" class="data row6 col0">7</td>
<td id="T_5d745_row6_col1" class="data row6 col1">0.959</td>
<td id="T_5d745_row6_col2" class="data row6 col2">0.026</td>
</tr>
<tr class="even">
<th id="T_5d745_level0_row7" class="row_heading level0 row7" data-quarto-table-cell-role="th">7</th>
<td id="T_5d745_row7_col0" class="data row7 col0">8</td>
<td id="T_5d745_row7_col1" class="data row7 col1">0.959</td>
<td id="T_5d745_row7_col2" class="data row7 col2">0.026</td>
</tr>
<tr class="odd">
<th id="T_5d745_level0_row8" class="row_heading level0 row8" data-quarto-table-cell-role="th">8</th>
<td id="T_5d745_row8_col0" class="data row8 col0">9</td>
<td id="T_5d745_row8_col1" class="data row8 col1">0.976</td>
<td id="T_5d745_row8_col2" class="data row8 col2">0.020</td>
</tr>
<tr class="even">
<th id="T_5d745_level0_row9" class="row_heading level0 row9" data-quarto-table-cell-role="th">9</th>
<td id="T_5d745_row9_col0" class="data row9 col0">10</td>
<td id="T_5d745_row9_col1" class="data row9 col1">0.976</td>
<td id="T_5d745_row9_col2" class="data row9 col2">0.020</td>
</tr>
<tr class="odd">
<th id="T_5d745_level0_row10" class="row_heading level0 row10" data-quarto-table-cell-role="th">10</th>
<td id="T_5d745_row10_col0" class="data row10 col0">11</td>
<td id="T_5d745_row10_col1" class="data row10 col1">0.967</td>
<td id="T_5d745_row10_col2" class="data row10 col2">0.031</td>
</tr>
<tr class="even">
<th id="T_5d745_level0_row11" class="row_heading level0 row11" data-quarto-table-cell-role="th">11</th>
<td id="T_5d745_row11_col0" class="data row11 col0">12</td>
<td id="T_5d745_row11_col1" class="data row11 col1">0.976</td>
<td id="T_5d745_row11_col2" class="data row11 col2">0.020</td>
</tr>
<tr class="odd">
<th id="T_5d745_level0_row12" class="row_heading level0 row12" data-quarto-table-cell-role="th">12</th>
<td id="T_5d745_row12_col0" class="data row12 col0">13</td>
<td id="T_5d745_row12_col1" class="data row12 col1">0.967</td>
<td id="T_5d745_row12_col2" class="data row12 col2">0.031</td>
</tr>
</tbody>
</table>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>k elegido solo con entrenamiento: 4
Varianza de entrenamiento conservada: 73.91%</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/12-pca/index_files/figure-html/cell-13-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-la-selección-de-k" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-la-selección-de-k">Cómo leer la selección de <img src="https://latex.codecogs.com/png.latex?k"></h3>
<p>Al probar <strong>todos los valores de 1 a 13</strong>, la mayor exactitud media de validación es <strong>0.984 con <img src="https://latex.codecogs.com/png.latex?k=4"></strong>. El óptimo no cae en un borde. Con <img src="https://latex.codecogs.com/png.latex?k=13">, equivalente al modelo con las 13 variables, la exactitud media es <strong>0.967</strong>. Aun así, la ventaja de <img src="https://latex.codecogs.com/png.latex?k=4"> sobre <img src="https://latex.codecogs.com/png.latex?k=2"> es pequeña: <strong>0.008</strong>, que equivale a un solo vino (2 errores frente a 3 entre los 124 vinos de entrenamiento) y es menor que la desviación de aproximadamente <strong>0.020</strong> entre <em>folds</em>. Por eso conviene leer <img src="https://latex.codecogs.com/png.latex?k=4"> como la mejor media observada, no como una superioridad concluyente sobre toda alternativa compacta.</p>
<p>Al reajustar la representación elegida solo con entrenamiento, cuatro componentes conservan <strong>73.91%</strong> de su varianza. Esta cifra predictiva se calcula sin usar el conjunto de prueba; el 73.60% visto antes pertenece al análisis descriptivo sobre todos los vinos. Ahora fijamos <img src="https://latex.codecogs.com/png.latex?k=4"> y usamos el conjunto de prueba una sola vez.</p>
</section>
</section>
<section id="comparación-final-en-datos-no-vistos" class="level2">
<h2 class="anchored" data-anchor-id="comparación-final-en-datos-no-vistos">Comparación final en datos no vistos</h2>
<p>El modelo de referencia estandariza las 13 variables y ajusta regresión logística. La alternativa añade PCA con el <img src="https://latex.codecogs.com/png.latex?k"> elegido. Ambos modelos usan la misma partición, el mismo clasificador y el mismo conjunto de prueba; así aislamos el efecto de reducir dimensiones.</p>
<div id="01a344df" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:53.906366Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:53.906161Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:05:53.932925Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:05:53.932069Z&quot;}}" data-execution_count="13">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1">modelo_completo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([</span>
<span id="cb23-2">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'escalador'</span>, StandardScaler()),</span>
<span id="cb23-3">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clasificador'</span>, LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>)),</span>
<span id="cb23-4">])</span>
<span id="cb23-5">modelo_reducido <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([</span>
<span id="cb23-6">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'escalador'</span>, StandardScaler()),</span>
<span id="cb23-7">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pca'</span>, PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mejor_k)),</span>
<span id="cb23-8">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'clasificador'</span>, LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>)),</span>
<span id="cb23-9">])</span>
<span id="cb23-10"></span>
<span id="cb23-11">modelo_completo.fit(X_train, y_train)</span>
<span id="cb23-12">modelo_reducido.fit(X_train, y_train)</span>
<span id="cb23-13">acc_completo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> accuracy_score(y_test, modelo_completo.predict(X_test))</span>
<span id="cb23-14">acc_reducido <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> accuracy_score(y_test, modelo_reducido.predict(X_test))</span>
<span id="cb23-15"></span>
<span id="cb23-16">comparacion_modelos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb23-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'modelo'</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'13 variables estandarizadas'</span>, <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_k<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> componentes principales'</span>],</span>
<span id="cb23-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dimensiones'</span>: [X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], mejor_k],</span>
<span id="cb23-19">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'exactitud_test'</span>: [acc_completo, acc_reducido],</span>
<span id="cb23-20">})</span>
<span id="cb23-21">display(comparacion_modelos.style.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">format</span>({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'exactitud_test'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{:.2%}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>}))</span>
<span id="cb23-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Diferencia absoluta: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(acc_completo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> acc_reducido)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb23-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Reducción dimensional: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> mejor_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<style type="text/css">
</style>

<table id="T_1d220" class="caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th class="blank level0" data-quarto-table-cell-role="th">&nbsp;</th>
<th id="T_1d220_level0_col0" class="col_heading level0 col0" data-quarto-table-cell-role="th">modelo</th>
<th id="T_1d220_level0_col1" class="col_heading level0 col1" data-quarto-table-cell-role="th">dimensiones</th>
<th id="T_1d220_level0_col2" class="col_heading level0 col2" data-quarto-table-cell-role="th">exactitud_test</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th id="T_1d220_level0_row0" class="row_heading level0 row0" data-quarto-table-cell-role="th">0</th>
<td id="T_1d220_row0_col0" class="data row0 col0">13 variables estandarizadas</td>
<td id="T_1d220_row0_col1" class="data row0 col1">13</td>
<td id="T_1d220_row0_col2" class="data row0 col2">98.15%</td>
</tr>
<tr class="even">
<th id="T_1d220_level0_row1" class="row_heading level0 row1" data-quarto-table-cell-role="th">1</th>
<td id="T_1d220_row1_col0" class="data row1 col0">4 componentes principales</td>
<td id="T_1d220_row1_col1" class="data row1 col1">4</td>
<td id="T_1d220_row1_col2" class="data row1 col2">94.44%</td>
</tr>
</tbody>
</table>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Diferencia absoluta: 3.70%
Reducción dimensional: 69.23%</code></pre>
</div>
</div>
<section id="cómo-leer-la-comparación-final" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-la-comparación-final">Cómo leer la comparación final</h3>
<p>Con las 13 variables, la exactitud de prueba es <strong>98.15%</strong>. Con solo <strong>4 componentes</strong>, es <strong>94.44%</strong>: una diferencia de <strong>3.70 puntos porcentuales</strong> a cambio de reducir la representación en <strong>69.23%</strong>. Con 54 vinos de prueba, esa diferencia son <strong>dos vinos</strong> (53 frente a 51 aciertos).</p>
<p>En este conjunto pequeño, PCA conserva un desempeño cercano con muchas menos dimensiones. El modelo completo acierta dos vinos más en la prueba, mientras que en la validación cruzada el orden fue el inverso (<strong>0.967</strong> frente a <strong>0.984</strong>): con muestras de este tamaño, ninguna de las dos diferencias es concluyente. No concluyas que PCA siempre mejora la predicción: su valor puede estar en compresión, visualización, reducción de ruido o estabilidad ante variables correlacionadas. La comparación debe validarse en cada problema.</p>
</section>
</section>
<section id="qué-hace-y-qué-no-hace-pca" class="level2">
<h2 class="anchored" data-anchor-id="qué-hace-y-qué-no-hace-pca">Qué hace y qué no hace PCA</h2>
<p>PCA <strong>sí</strong>:</p>
<ul>
<li>encuentra combinaciones lineales que capturan máxima varianza;</li>
<li>ordena componentes de mayor a menor varianza explicada;</li>
<li>produce direcciones ortogonales y <em>scores</em> no correlacionados;</li>
<li>permite visualizar, comprimir y reconstruir aproximadamente datos multivariados.</li>
</ul>
<p>PCA <strong>no</strong>:</p>
<ul>
<li>usa etiquetas ni optimiza la separación entre clases;</li>
<li>demuestra causalidad;</li>
<li>garantiza que las direcciones de mayor varianza sean las más predictivas;</li>
<li>separa fuentes estadísticamente independientes.</li>
</ul>
<p>Ese último límite abre el próximo tema. <strong>ICA (Análisis de Componentes Independientes)</strong> no busca máxima varianza ni solo ausencia de correlación: intenta recuperar componentes <strong>independientes</strong>, una meta más fuerte y especialmente útil cuando observamos mezclas de señales.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>variables-latentes</category>
  <category>pca</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/avanzado/12-pca/</guid>
  <pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Análisis Avanzado de Datos — 12. Variables latentes II: Análisis de Componentes Independientes (ICA)</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/avanzado/13-ica/</link>
  <description><![CDATA[ 




<section id="análisis-avanzado-de-datos-12.-variables-latentes-ii-análisis-de-componentes-independientes-ica" class="level1">
<h1>Análisis Avanzado de Datos — 12. Variables latentes II: Análisis de Componentes Independientes (ICA)</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado convierte datos en decisiones. Científico de Datos, Arquitecto de IA y asesor tecnológico con más de 20 años de experiencia en analítica avanzada, machine learning, Big Data e IoT. Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), asesora a entidades gubernamentales y empresas privadas en Colombia y es referente en analítica y normatividad para los sectores postal y logístico del país. Una serie pensada para ir de la teoría a la práctica, con ejemplos concretos en cada paso.</p>
<p>📌 <em>Parte de la serie <strong>Análisis Avanzado de Datos</strong>.</em></p>
</section>
<section id="cuando-la-varianza-ya-no-es-la-pregunta-correcta" class="level2">
<h2 class="anchored" data-anchor-id="cuando-la-varianza-ya-no-es-la-pregunta-correcta">Cuando la varianza ya no es la pregunta correcta</h2>
<p>En el artículo anterior usaste <strong>PCA</strong> para encontrar direcciones nuevas: las de <strong>máxima varianza</strong>. Esa es la herramienta natural cuando quieres comprimir, visualizar o quitar redundancia entre columnas.</p>
<p>Ahora cambia la pregunta. Imagina una fiesta con tres conversaciones a la vez y tres micrófonos en sitios distintos. Cada grabación es una <strong>mezcla</strong> de las tres voces. Tú no oyes a nadie por separado: oyes un enredo. ¿Se puede recuperar cada voz si solo tienes las mezclas?</p>
<p>Eso es el <strong>problema del cóctel</strong>. PCA no lo resuelve: decorrelaciona y ordena por varianza, pero no separa fuentes. El <strong>análisis de componentes independientes (ICA)</strong> busca otra cosa: direcciones <strong>estadísticamente independientes</strong>. En este notebook vas a ver el contraste que importa, con señales sintéticas que puedes reconocer a simple vista: PCA no recupera las fuentes; ICA sí.</p>
</section>
<section id="objetivos-de-aprendizaje" class="level2">
<h2 class="anchored" data-anchor-id="objetivos-de-aprendizaje">Objetivos de aprendizaje</h2>
<p>Al terminar este notebook vas a ser capaz de:</p>
<ul>
<li><strong>Plantear</strong> el problema del cóctel: recuperar fuentes independientes a partir de mezclas lineales.</li>
<li><strong>Escribir</strong> el modelo generativo <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bx%7D(t)%20=%20A%5Cmathbf%7Bs%7D(t)"> y el papel de la matriz de separación <img src="https://latex.codecogs.com/png.latex?W">.</li>
<li><strong>Explicar</strong> por qué ICA exige fuentes independientes y <strong>no gaussianas</strong>.</li>
<li><strong>Mostrar</strong> con datos por qué PCA decorrelaciona pero no separa las voces.</li>
<li><strong>Aplicar</strong> FastICA y comparar visualmente fuentes, componentes de PCA y señales recuperadas.</li>
<li><strong>Reconocer</strong> las ambigüedades de orden y de escala/signo, y el caso en el que ICA no es identificable.</li>
<li><strong>Decidir</strong> cuándo usar PCA y cuándo usar ICA.</li>
</ul>
</section>
<section id="preparación-del-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparación-del-entorno">Preparación del entorno</h2>
<div id="a6725436" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:05:59.660233Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:05:59.660036Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:01.758108Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:01.757248Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.decomposition <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PCA, FastICA</span>
<span id="cb1-5"></span>
<span id="cb1-6">SEMILLA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2026</span></span>
<span id="cb1-7">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb1-8"></span>
<span id="cb1-9">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'figure.figsize'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.2</span>)</span>
<span id="cb1-10">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.top'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span></span>
<span id="cb1-11">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.right'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span></span>
<span id="cb1-12"></span>
<span id="cb1-13">NOMBRES_FUENTES <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'senoidal'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cuadrada'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'diente de sierra'</span>]</span>
<span id="cb1-14">NOMBRES_MICROS <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'micrófono 1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'micrófono 2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'micrófono 3'</span>]</span>
<span id="cb1-15"></span>
<span id="cb1-16"></span>
<span id="cb1-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> kurtosis_exceso(x):</span>
<span id="cb1-18">    z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> np.mean(x)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.std(x)</span>
<span id="cb1-19">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.mean(z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span></span>
<span id="cb1-20"></span>
<span id="cb1-21"></span>
<span id="cb1-22"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_senales(series, titulos, color, titulo_figura):</span>
<span id="cb1-23">    n_senales <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> series.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb1-24">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(n_senales, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.6</span>), sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb1-25">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(n_senales):</span>
<span id="cb1-26">        axes[i].plot(t, series[:, i], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.85</span>)</span>
<span id="cb1-27">        axes[i].set_ylabel(titulos[i], fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span>
<span id="cb1-28">        axes[i].set_xlim(t.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), t.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>())</span>
<span id="cb1-29">    axes[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb1-30">    fig.suptitle(titulo_figura, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.01</span>)</span>
<span id="cb1-31">    plt.tight_layout()</span>
<span id="cb1-32">    plt.show()</span></code></pre></div></div>
</div>
</section>
<section id="el-problema-del-cóctel" class="level2">
<h2 class="anchored" data-anchor-id="el-problema-del-cóctel">El problema del cóctel</h2>
<p>Tres personas hablan al mismo tiempo. Tres micrófonos, colocados a distintas distancias, graban. El micrófono cercano a la primera voz la capta más fuerte, pero también capta las otras dos. Nadie te entrega las pistas por separado: solo tienes tres pistas mezcladas.</p>
<p>La pregunta de ICA no es “¿cuál combinación explica más varianza?”. Es esta: <strong>si las voces originales eran independientes, ¿puedo deshacer la mezcla y recuperar cada una?</strong></p>
<p>Para poder juzgar a simple vista si el método funciona, vamos a <strong>fabricar</strong> las voces. En un problema real no las verías; aquí sí, y eso convierte el experimento en una prueba visible.</p>
</section>
<section id="tres-fuentes-que-puedes-reconocer" class="level2">
<h2 class="anchored" data-anchor-id="tres-fuentes-que-puedes-reconocer">Tres fuentes que puedes reconocer</h2>
<p>Generamos <img src="https://latex.codecogs.com/png.latex?n%20=%202000"> instantes de tres señales construidas por separado —ninguna se obtiene a partir de otra— y muy distintas entre sí. Cada instante cuenta como una observación, y en ese sentido tratamos las tres señales como fuentes independientes:</p>
<ul>
<li>una <strong>senoidal</strong> suave,</li>
<li>una <strong>cuadrada</strong>, que solo toma dos niveles,</li>
<li>un <strong>diente de sierra</strong>, con subidas lineales y caídas bruscas.</li>
</ul>
<p>Les añadimos un ruido de medición pequeño y las estandarizamos. La semilla queda fija para que el experimento sea reproducible.</p>
<div id="b3e75965" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:01.760116Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:01.759834Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:01.766006Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:01.765210Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span></span>
<span id="cb2-2">t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, n)</span>
<span id="cb2-3"></span>
<span id="cb2-4">senoidal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sin(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> t)</span>
<span id="cb2-5">cuadrada <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sign(np.sin(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> t))</span>
<span id="cb2-6">diente <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (np.mod(t, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)</span>
<span id="cb2-7"></span>
<span id="cb2-8">fuentes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([senoidal, cuadrada, diente])</span>
<span id="cb2-9">fuentes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fuentes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> rng.normal(size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>fuentes.shape)</span>
<span id="cb2-10">fuentes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (fuentes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> fuentes.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> fuentes.std(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb2-11"></span>
<span id="cb2-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> instantes | </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>fuentes<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> fuentes'</span>)</span>
<span id="cb2-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Media de cada fuente:'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">', '</span>.join(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(m), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> m <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> fuentes.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)))</span>
<span id="cb2-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Desviación de cada fuente:'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">', '</span>.join(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>s<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> s <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> fuentes.std(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>2000 instantes | 3 fuentes
Media de cada fuente: -0.000, 0.000, 0.000
Desviación de cada fuente: 1.000, 1.000, 1.000</code></pre>
</div>
</div>
<div id="914b99c8" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:01.767959Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:01.767730Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:01.954290Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:01.953413Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">graficar_senales(</span>
<span id="cb4-2">    fuentes,</span>
<span id="cb4-3">    NOMBRES_FUENTES,</span>
<span id="cb4-4">    color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>,</span>
<span id="cb4-5">    titulo_figura<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Fuentes originales: tres voces independientes y reconocibles'</span>,</span>
<span id="cb4-6">)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/13-ica/index_files/figure-html/cell-4-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado">Cómo leer este resultado</h3>
<p>Las tres trazas son <strong>distintas a simple vista</strong>. La senoidal oscila con suavidad, la cuadrada salta entre dos valores y el diente de sierra sube en rampa. Esas formas características son la referencia verdadera (<em>ground truth</em>) del experimento: más adelante vas a preguntarte si PCA o ICA te las devuelven.</p>
<p>Las medias quedan en <strong>0.000</strong> y las desviaciones en <strong>1.000</strong> porque estandarizamos. ICA (y PCA) trabajan con esa escala; la forma de cada señal es lo que importa, no su unidad original.</p>
</section>
</section>
<section id="lo-que-captan-los-micrófonos" class="level2">
<h2 class="anchored" data-anchor-id="lo-que-captan-los-micrófonos">Lo que captan los micrófonos</h2>
<p>Cada micrófono graba una <strong>combinación lineal</strong> de las tres fuentes. Eso se resume en una matriz de mezcla <img src="https://latex.codecogs.com/png.latex?A">: la fila <img src="https://latex.codecogs.com/png.latex?i"> dice con qué peso entra cada voz en el micrófono <img src="https://latex.codecogs.com/png.latex?i">.</p>
<p>En la fiesta no conoces <img src="https://latex.codecogs.com/png.latex?A">. Aquí sí la fijamos, para fabricar las grabaciones y después <strong>olvidarla</strong>: PCA e ICA solo van a ver las mezclas.</p>
<div id="48a2dec4" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:01.956029Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:01.955813Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:01.966908Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:01.966168Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([</span>
<span id="cb5-2">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>],</span>
<span id="cb5-3">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>],</span>
<span id="cb5-4">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>],</span>
<span id="cb5-5">])</span>
<span id="cb5-6">mezclas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fuentes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> A.T</span>
<span id="cb5-7"></span>
<span id="cb5-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Matriz de mezcla A (filas = micrófonos, columnas = fuentes):'</span>)</span>
<span id="cb5-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame(</span>
<span id="cb5-10">    A,</span>
<span id="cb5-11">    index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>NOMBRES_MICROS,</span>
<span id="cb5-12">    columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>NOMBRES_FUENTES,</span>
<span id="cb5-13">))</span>
<span id="cb5-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb5-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Forma de las mezclas:'</span>, mezclas.shape)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Matriz de mezcla A (filas = micrófonos, columnas = fuentes):
             senoidal  cuadrada  diente de sierra
micrófono 1       1.0       1.0               1.0
micrófono 2       0.5       2.0               1.0
micrófono 3       1.5       1.0               2.0

Forma de las mezclas: (2000, 3)</code></pre>
</div>
</div>
<div id="3ba684a4" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:01.969040Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:01.968762Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:02.113376Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:02.112606Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">graficar_senales(</span>
<span id="cb7-2">    mezclas,</span>
<span id="cb7-3">    NOMBRES_MICROS,</span>
<span id="cb7-4">    color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'darkorange'</span>,</span>
<span id="cb7-5">    titulo_figura<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Mezclas observadas: lo único que verías en la fiesta'</span>,</span>
<span id="cb7-6">)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/13-ica/index_files/figure-html/cell-6-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-1">Cómo leer este resultado</h3>
<p>Fíjate en el cambio: <strong>ya no ves ninguna de las tres formas limpias</strong>. Las rampas del diente siguen asomando, pero mezcladas con los saltos de la cuadrada y la ondulación de la senoidal. Cada micrófono capta las tres voces con pesos distintos. El micrófono 2, por ejemplo, carga más la cuadrada (peso <strong>2.0</strong>) que la senoidal (peso <strong>0.5</strong>), pero aun así la pista sigue siendo un enredo.</p>
<p>Este es el dato de trabajo. A partir de aquí, finge que las fuentes azules desaparecieron. Solo existen las naranjas.</p>
<div id="1128fea9" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:02.115019Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:02.114822Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:02.124411Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:02.123147Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">corr_mezclas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb8-2">    np.corrcoef(mezclas.T).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb8-3">    index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>NOMBRES_MICROS,</span>
<span id="cb8-4">    columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>NOMBRES_MICROS,</span>
<span id="cb8-5">)</span>
<span id="cb8-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Correlación entre micrófonos:'</span>)</span>
<span id="cb8-7">corr_mezclas</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Correlación entre micrófonos:</code></pre>
</div>
<div class="cell-output cell-output-display" data-execution_count="6">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">micrófono 1</th>
<th data-quarto-table-cell-role="th">micrófono 2</th>
<th data-quarto-table-cell-role="th">micrófono 3</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">micrófono 1</th>
<td>1.000</td>
<td>0.891</td>
<td>0.963</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">micrófono 2</th>
<td>0.891</td>
<td>1.000</td>
<td>0.778</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">micrófono 3</th>
<td>0.963</td>
<td>0.778</td>
<td>1.000</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
<section id="cómo-leer-este-resultado-2" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-2">Cómo leer este resultado</h3>
<p>Las tres grabaciones están <strong>fuertemente correlacionadas</strong>: <img src="https://latex.codecogs.com/png.latex?0.891"> entre los micrófonos 1 y 2, <img src="https://latex.codecogs.com/png.latex?0.963"> entre 1 y 3, <img src="https://latex.codecogs.com/png.latex?0.778"> entre 2 y 3. Eso es esperable: comparten las mismas voces, solo que con pesos distintos.</p>
<p>Correlación y dependencia no son lo mismo, pero una correlación tan alta ya te avisa de que hay redundancia. PCA va a aprovechar esa redundancia para comprimir. ICA va a intentar algo más ambicioso: <strong>desenredar</strong> las voces que produjeron esa redundancia.</p>
</section>
</section>
<section id="el-modelo-generativo" class="level2">
<h2 class="anchored" data-anchor-id="el-modelo-generativo">El modelo generativo</h2>
<p>El cóctel se escribe en una línea. En cada instante <img src="https://latex.codecogs.com/png.latex?t">, el vector de micrófonos <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bx%7D(t)"> es una mezcla lineal de las fuentes <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bs%7D(t)">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathbf%7Bx%7D(t)%20=%20A%5Cmathbf%7Bs%7D(t).%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?A"> es la <strong>matriz de mezcla</strong> (desconocida). Lo único observado es <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bx%7D(t)">. ICA busca una <strong>matriz de separación</strong> <img src="https://latex.codecogs.com/png.latex?W"> tal que</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7B%5Cmathbf%7Bs%7D%7D(t)%20=%20W%5Cmathbf%7Bx%7D(t)%0A"></p>
<p>recupere las fuentes. Si el modelo es identificable, <img src="https://latex.codecogs.com/png.latex?W"> coincide con <img src="https://latex.codecogs.com/png.latex?A%5E%7B-1%7D"> <strong>salvo</strong> una permutación de filas y un reescalado (incluido un cambio de signo). Esas dos ambigüedades no son un error del software: son parte del método, y las vamos a ver en los datos.</p>
<p>En forma matricial, con cada fila de <img src="https://latex.codecogs.com/png.latex?S"> y de <img src="https://latex.codecogs.com/png.latex?X"> como un instante,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AX%20=%20S%20A%5E%7B%5Ctop%7D.%0A"></p>
<p>Esa es exactamente la cuenta que usamos para fabricar <code>mezclas</code>.</p>
</section>
<section id="el-supuesto-que-pca-no-usa" class="level2">
<h2 class="anchored" data-anchor-id="el-supuesto-que-pca-no-usa">El supuesto que PCA no usa</h2>
<p>Dos condiciones hacen que ICA pueda deshacer la mezcla:</p>
<ol type="1">
<li><strong>Independencia estadística.</strong> Las fuentes no solo están incorrelacionadas; su densidad conjunta se factoriza:</li>
</ol>
<p><img src="https://latex.codecogs.com/png.latex?%0Ap(s_1,%20s_2,%20s_3)%20=%20p(s_1)%5C,p(s_2)%5C,p(s_3).%0A"></p>
<p>Incorrelación es más débil: <img src="https://latex.codecogs.com/png.latex?%5Coperatorname%7BCov%7D(s_i,%20s_j)%20=%200"> para <img src="https://latex.codecogs.com/png.latex?i%20%5Cneq%20j">. Independencia implica incorrelación (si las varianzas existen); lo contrario <strong>no</strong> es cierto. PCA solo consigue incorrelación.</p>
<ol start="2" type="1">
<li><strong>No gaussianidad.</strong> Como máximo una fuente puede ser gaussiana. ICA se apoya en que una mezcla lineal de variables independientes tiende a parecerse <strong>más a una gaussiana</strong> que las fuentes originales (es el teorema del límite central trabajando en tu contra si miras las mezclas, y a tu favor si buscas proyecciones poco gaussianas). FastICA maximiza una aproximación de la <strong>negentropía</strong> (cuánto se aleja una variable de la gaussiana con su misma varianza; vale <img src="https://latex.codecogs.com/png.latex?0"> solo para la gaussiana): busca las direcciones más no gaussianas después de <strong>blanquear</strong> los datos, es decir, de transformarlos para que queden incorrelacionados y con varianza 1 (en la práctica, PCA seguido de un reescalado de cada componente).</li>
</ol>
<p>Si todas las fuentes son gaussianas, el modelo deja de ser identificable: después de blanquear, cualquier rotación sigue siendo una solución válida. Más adelante lo comprobamos.</p>
</section>
<section id="las-mezclas-se-ven-más-gaussianas-que-las-voces" class="level2">
<h2 class="anchored" data-anchor-id="las-mezclas-se-ven-más-gaussianas-que-las-voces">Las mezclas se ven más gaussianas que las voces</h2>
<p>Una forma concreta de medir no gaussianidad es el <strong>exceso de curtosis</strong>:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ckappa%20=%20%5Cmathbb%7BE%7D%5BZ%5E4%5D%20-%203,%0A"></p>
<p>donde <img src="https://latex.codecogs.com/png.latex?Z"> está estandarizada. Vale <img src="https://latex.codecogs.com/png.latex?0"> para una gaussiana, es negativo en distribuciones de colas más livianas que la campana (subgaussianas: senoidal, cuadrada, diente) y positivo en distribuciones de colas pesadas (supergaussianas).</p>
<div id="f6bcc99e" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:02.126358Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:02.126072Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:02.570949Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:02.570202Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.2</span>))</span>
<span id="cb10-2"></span>
<span id="cb10-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb10-4">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, j].hist(fuentes[:, j], bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'white'</span>)</span>
<span id="cb10-5">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, j].set_title(NOMBRES_FUENTES[j], fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb10-6">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, j].hist(mezclas[:, j], bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'darkorange'</span>, edgecolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'white'</span>)</span>
<span id="cb10-7">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, j].set_title(NOMBRES_MICROS[j], fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb10-8"></span>
<span id="cb10-9">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'fuentes'</span>)</span>
<span id="cb10-10">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mezclas'</span>)</span>
<span id="cb10-11">fig.suptitle(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Histogramas: las voces son menos gaussianas que los micrófonos'</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.02</span>)</span>
<span id="cb10-12">plt.tight_layout()</span>
<span id="cb10-13">plt.show()</span>
<span id="cb10-14"></span>
<span id="cb10-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Exceso de curtosis de las fuentes:'</span>)</span>
<span id="cb10-16"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb10-17">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>NOMBRES_FUENTES[j]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&gt;18}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>kurtosis_exceso(fuentes[:, j])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">: .3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb10-18"></span>
<span id="cb10-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Exceso de curtosis de las mezclas:'</span>)</span>
<span id="cb10-20"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb10-21">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>NOMBRES_MICROS[j]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&gt;18}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>kurtosis_exceso(mezclas[:, j])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">: .3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/13-ica/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Exceso de curtosis de las fuentes:
            senoidal: -1.347
            cuadrada: -1.981
    diente de sierra: -1.174
Exceso de curtosis de las mezclas:
         micrófono 1: -0.494
         micrófono 2: -1.188
         micrófono 3: -0.422</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-3" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-3">Cómo leer este resultado</h3>
<p>Las tres fuentes tienen curtosis <strong>negativa y marcada</strong>: <strong>-1.347</strong> la senoidal, <strong>-1.981</strong> la cuadrada y <strong>-1.174</strong> el diente. Están lejos de <img src="https://latex.codecogs.com/png.latex?0">, que sería el valor gaussiano.</p>
<p>Las mezclas se acercan a la campana: <strong>-0.494</strong>, <strong>-1.188</strong> y <strong>-0.422</strong>. El micrófono 2 todavía hereda bastante de la cuadrada (la fuente más subgaussiana y la de mayor peso en esa fila de <img src="https://latex.codecogs.com/png.latex?A">): su <strong>-1.188</strong> incluso queda por debajo del <strong>-1.174</strong> del diente. Lo que se cumple siempre es otra cosa: para una mezcla <img src="https://latex.codecogs.com/png.latex?%5Csum_i%20a_i%20s_i"> de fuentes independientes estandarizadas, el exceso de curtosis vale <img src="https://latex.codecogs.com/png.latex?%5Csum_i%20a_i%5E4%20%5Ckappa_i%20/%20%5Cleft(%5Csum_i%20a_i%5E2%5Cright)%5E2">, una combinación que diluye las curtosis de las fuentes, así que ninguna mezcla puede ser más no gaussiana que la fuente más no gaussiana. Es la idea del teorema del límite central a pequeña escala: <strong>mezclar independencias empuja hacia lo gaussiano</strong>. ICA va a buscar proyecciones que desandan ese camino.</p>
</section>
<section id="antes-de-seguir-pregúntate" class="level3">
<h3 class="anchored" data-anchor-id="antes-de-seguir-pregúntate">Antes de seguir, pregúntate</h3>
<p>Si PCA encuentra las direcciones de máxima varianza en las mezclas, ¿esperas que esas direcciones coincidan con las tres voces originales? ¿O solo con combinaciones que concentren energía?</p>
<p>Quédate con tu respuesta. En la siguiente sección la contrastamos con el gráfico: si PCA resolviera el cóctel, las componentes se verían como la senoidal, la cuadrada y el diente. Si no, verás otro enredo, quizá más ordenado, pero enredo al fin.</p>
</section>
</section>
<section id="por-qué-pca-no-basta-aquí" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-pca-no-basta-aquí">Por qué PCA no basta aquí</h2>
<p>PCA centra los datos, los rota hacia ejes ortogonales y ordena esos ejes por varianza explicada. Eso <strong>decorrelaciona</strong> las pistas (blanquear sería, además, reescalar cada componente a varianza 1; con los valores por defecto de scikit-learn, PCA no lo hace). El cóctel pide más: las voces originales no son “las que más varían”, son las que son <strong>independientes</strong>. Nada en el criterio de PCA busca esa independencia.</p>
<p>Ajustamos PCA sobre las mezclas —sin usar las fuentes— y miramos las tres componentes.</p>
<div id="7dbfb9ad" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:02.572641Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:02.572432Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:02.734810Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:02.734156Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA)</span>
<span id="cb12-2">comp_pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca.fit_transform(mezclas)</span>
<span id="cb12-3"></span>
<span id="cb12-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Varianza explicada por PCA:'</span>)</span>
<span id="cb12-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, v <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(pca.explained_variance_ratio_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>):</span>
<span id="cb12-6">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> v<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%'</span>)</span>
<span id="cb12-7"></span>
<span id="cb12-8">graficar_senales(</span>
<span id="cb12-9">    comp_pca,</span>
<span id="cb12-10">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC3'</span>],</span>
<span id="cb12-11">    color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'0.35'</span>,</span>
<span id="cb12-12">    titulo_figura<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Componentes de PCA: decorrelacionadas, pero no son las voces'</span>,</span>
<span id="cb12-13">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Varianza explicada por PCA:
  PC1: 90.98%
  PC2: 8.68%
  PC3: 0.34%</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/13-ica/index_files/figure-html/cell-9-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<div id="90c05ba6" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:02.736614Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:02.736417Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:02.745985Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:02.745265Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">filas_pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC3'</span>]</span>
<span id="cb14-2">corr_pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>filas_pca, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>NOMBRES_FUENTES, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb14-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb14-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb14-5">        corr_pca.iloc[i, j] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.corrcoef(comp_pca[:, i], fuentes[:, j])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb14-6"></span>
<span id="cb14-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Correlación (con signo) entre componentes PCA y fuentes:'</span>)</span>
<span id="cb14-8">display_corr_pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> corr_pca.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb14-9">display_corr_pca</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Correlación (con signo) entre componentes PCA y fuentes:</code></pre>
</div>
<div class="cell-output cell-output-display" data-execution_count="9">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">senoidal</th>
<th data-quarto-table-cell-role="th">cuadrada</th>
<th data-quarto-table-cell-role="th">diente de sierra</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">PC1</th>
<td>0.515</td>
<td>0.614</td>
<td>0.604</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">PC2</th>
<td>-0.410</td>
<td>0.780</td>
<td>-0.433</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">PC3</th>
<td>0.753</td>
<td>0.119</td>
<td>-0.670</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-este-resultado-4" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-4">Cómo leer este resultado</h3>
<p>PC1 se queda con el <strong>90.98%</strong> de la varianza; PC2 con el <strong>8.68%</strong>; PC3 con el <strong>0.34%</strong>. PCA está haciendo exactamente su trabajo: comprimir. El cóctel, sin embargo, no es un problema de compresión. Las tres voces importan, aunque una de las direcciones de mezcla tenga poca varianza.</p>
<p>Las correlaciones lo confirman. Ninguna componente se corresponde con una sola fuente: el mejor <img src="https://latex.codecogs.com/png.latex?%7Cr%7C"> es <strong>0.780</strong> (PC2 con la cuadrada), y PC1 se reparte entre las tres (<strong>0.515</strong>, <strong>0.614</strong>, <strong>0.604</strong>). Visualmente, las trazas grises <strong>no</strong> son la senoidal, ni la cuadrada, ni el diente. PCA desenredó la correlación, no las voces.</p>
</section>
</section>
<section id="el-mismo-contraste-ahora-en-el-plano" class="level2">
<h2 class="anchored" data-anchor-id="el-mismo-contraste-ahora-en-el-plano">El mismo contraste, ahora en el plano</h2>
<p>Otra manera de verlo: toma la senoidal contra la cuadrada. Como son independientes, su nube no tiene una dirección privilegiada de asociación. Las mezclas sí: al compartir voces, los micrófonos 1 y 2 se estiran en diagonal. PCA rota esa nube hacia los ejes de varianza —ortogonales—, pero no alinea los ejes con las voces.</p>
<div id="80a218b3" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:02.747666Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:02.747467Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:02.825123Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:02.824330Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.1</span>))</span>
<span id="cb16-2">nubes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb16-3">    (fuentes[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], fuentes[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'fuentes</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">(senoidal vs cuadrada)'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>),</span>
<span id="cb16-4">    (mezclas[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], mezclas[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mezclas</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">(mic. 1 vs mic. 2)'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'darkorange'</span>),</span>
<span id="cb16-5">    (comp_pca[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], comp_pca[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PCA</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">(PC1 vs PC2)'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'0.35'</span>),</span>
<span id="cb16-6">]</span>
<span id="cb16-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax, (x, y, titulo, color) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(axes, nubes):</span>
<span id="cb16-8">    ax.scatter(x, y, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color)</span>
<span id="cb16-9">    ax.set_title(titulo, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span>
<span id="cb16-10">    ax.set_xticks([])</span>
<span id="cb16-11">    ax.set_yticks([])</span>
<span id="cb16-12">    ax.set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'equal'</span>, adjustable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'datalim'</span>)</span>
<span id="cb16-13">fig.suptitle(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Independencia (fuentes) frente a correlación (mezclas) y a la rotación de PCA'</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.08</span>)</span>
<span id="cb16-14">plt.tight_layout()</span>
<span id="cb16-15">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/13-ica/index_files/figure-html/cell-11-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-5" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-5">Cómo leer este resultado</h3>
<p>La primera nube es la de dos fuentes independientes: <strong>dos bandas horizontales</strong> (los dos niveles de la cuadrada) que la senoidal recorre de extremo a extremo, sin diagonal dominante. Saber en qué punto de la senoidal estás no te dice en qué banda estás. La segunda nube se <strong>estira en diagonal</strong> porque los micrófonos comparten voces. PCA la rota hacia ejes ortogonales, pero la forma sigue siendo la de una mezcla: las bandas quedan inclinadas y no reaparece la forma de las fuentes.</p>
<p>Si ICA hace lo que promete, más adelante esas dos bandas horizontales deberían volver. Primero, las señales en el tiempo.</p>
</section>
</section>
<section id="ica-separar-por-independencia" class="level2">
<h2 class="anchored" data-anchor-id="ica-separar-por-independencia">ICA: separar por independencia</h2>
<p>FastICA blanquea las mezclas (PCA seguido de un reescalado a varianza 1) y después <strong>rota</strong> buscando independencia: maximiza la no gaussianidad de las componentes. La llamada es la de scikit-learn; <code>random_state</code> fija la inicialización y <code>whiten='unit-variance'</code> deja cada componente con varianza 1 (es el valor por defecto en la versión instalada; lo escribimos para dejarlo explícito).</p>
<div id="f65440b7" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:02.827170Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:02.826878Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:02.978861Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:02.977918Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1">ica <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> FastICA(</span>
<span id="cb17-2">    n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,</span>
<span id="cb17-3">    random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA,</span>
<span id="cb17-4">    whiten<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'unit-variance'</span>,</span>
<span id="cb17-5">    max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>,</span>
<span id="cb17-6">)</span>
<span id="cb17-7">comp_ica <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ica.fit_transform(mezclas)</span>
<span id="cb17-8"></span>
<span id="cb17-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Iteraciones hasta converger: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>ica<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>n_iter_<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb17-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Curtosis de las componentes ICA:'</span>)</span>
<span id="cb17-11"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb17-12">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  IC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>kurtosis_exceso(comp_ica[:, i])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">: .3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb17-13"></span>
<span id="cb17-14">graficar_senales(</span>
<span id="cb17-15">    comp_ica,</span>
<span id="cb17-16">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC3'</span>],</span>
<span id="cb17-17">    color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>,</span>
<span id="cb17-18">    titulo_figura<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Componentes ICA tal como las entrega FastICA (aún sin reordenar)'</span>,</span>
<span id="cb17-19">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Iteraciones hasta converger: 3
Curtosis de las componentes ICA:
  IC1: -1.976
  IC2: -1.360
  IC3: -1.158</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/13-ica/index_files/figure-html/cell-12-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<div id="2226641a" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:02.980665Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:02.980459Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:02.989857Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:02.989179Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1">corr_ica <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC3'</span>], columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>NOMBRES_FUENTES, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb19-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb19-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb19-4">        corr_ica.iloc[i, j] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.corrcoef(comp_ica[:, i], fuentes[:, j])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb19-5"></span>
<span id="cb19-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Correlación (con signo) entre componentes ICA y fuentes:'</span>)</span>
<span id="cb19-7">corr_ica.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Correlación (con signo) entre componentes ICA y fuentes:</code></pre>
</div>
<div class="cell-output cell-output-display" data-execution_count="12">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">senoidal</th>
<th data-quarto-table-cell-role="th">cuadrada</th>
<th data-quarto-table-cell-role="th">diente de sierra</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">IC1</th>
<td>0.056</td>
<td>0.999</td>
<td>-0.029</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">IC2</th>
<td>0.997</td>
<td>0.031</td>
<td>-0.071</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">IC3</th>
<td>-0.056</td>
<td>0.015</td>
<td>-0.997</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<section id="cómo-leer-este-resultado-6" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-6">Cómo leer este resultado</h3>
<p>Ahora sí reconoces las voces, <strong>con dos matices</strong> que no vamos a esconder. IC1 es la cuadrada (<img src="https://latex.codecogs.com/png.latex?r%20=%200.999">), IC2 es la senoidal (<img src="https://latex.codecogs.com/png.latex?r%20=%200.997">) e IC3 es el diente <strong>invertido</strong> (<img src="https://latex.codecogs.com/png.latex?r%20=%20-0.997">). El orden no coincide con el de las fuentes originales, y una componente salió con el signo cambiado.</p>
<p>Eso no es un fallo de recuperación: <img src="https://latex.codecogs.com/png.latex?%7Cr%7C"> vale <strong>0.997</strong>, <strong>0.999</strong> y <strong>0.997</strong>. PCA, en el mejor emparejamiento, no pasaba de <strong>0.780</strong>. ICA separó las voces; PCA no.</p>
</section>
</section>
<section id="fuentes-ica-y-pca-lado-a-lado" class="level2">
<h2 class="anchored" data-anchor-id="fuentes-ica-y-pca-lado-a-lado">Fuentes, ICA y PCA, lado a lado</h2>
<p>Para comparar formas, recorremos las fuentes en orden, a cada una le asignamos la componente todavía libre con mayor <img src="https://latex.codecogs.com/png.latex?%7Cr%7C"> (un emparejamiento voraz) y corregimos el signo. ICA <strong>no</strong> te entrega ese alineamiento: lo hacemos nosotros, solo para que el ojo no tenga que perseguir permutaciones. El código deja explícito el emparejamiento.</p>
<div id="1714c91b" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:02.991647Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:02.991436Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:03.001924Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:03.001192Z&quot;}}" data-execution_count="13">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> alinear_con_fuentes(componentes, fuentes, nombres<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>):</span>
<span id="cb21-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> nombres <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>:</span>
<span id="cb21-3">        nombres <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> NOMBRES_FUENTES</span>
<span id="cb21-4">    n_comp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fuentes.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb21-5">    usadas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb21-6">    alineadas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros_like(componentes)</span>
<span id="cb21-7">    detalle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb21-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(n_comp):</span>
<span id="cb21-9">        mejor_i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span></span>
<span id="cb21-10">        mejor_r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span></span>
<span id="cb21-11">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(n_comp):</span>
<span id="cb21-12">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> usadas:</span>
<span id="cb21-13">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">continue</span></span>
<span id="cb21-14">            r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.corrcoef(componentes[:, i], fuentes[:, j])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb21-15">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> mejor_i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(r) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(mejor_r):</span>
<span id="cb21-16">                mejor_i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> i</span>
<span id="cb21-17">                mejor_r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> r</span>
<span id="cb21-18">        signo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> mejor_r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span></span>
<span id="cb21-19">        alineadas[:, j] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> signo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> componentes[:, mejor_i]</span>
<span id="cb21-20">        usadas.append(mejor_i)</span>
<span id="cb21-21">        detalle.append({</span>
<span id="cb21-22">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'fuente'</span>: nombres[j],</span>
<span id="cb21-23">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'componente'</span>: mejor_i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb21-24">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'signo'</span>: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(signo),</span>
<span id="cb21-25">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>: mejor_r,</span>
<span id="cb21-26">        })</span>
<span id="cb21-27">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> alineadas, pd.DataFrame(detalle)</span>
<span id="cb21-28"></span>
<span id="cb21-29"></span>
<span id="cb21-30">ica_alineada, detalle_ica <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> alinear_con_fuentes(comp_ica, fuentes)</span>
<span id="cb21-31">pca_alineada, detalle_pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> alinear_con_fuentes(comp_pca, fuentes)</span>
<span id="cb21-32"></span>
<span id="cb21-33"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Emparejamiento ICA (después de alinear orden y signo):'</span>)</span>
<span id="cb21-34"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(detalle_ica.assign(r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> d: d[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)))</span>
<span id="cb21-35"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb21-36"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Emparejamiento PCA (mismo criterio voraz):'</span>)</span>
<span id="cb21-37"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(detalle_pca.assign(r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> d: d[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Emparejamiento ICA (después de alinear orden y signo):
             fuente  componente  signo      r
0          senoidal           2      1  0.997
1          cuadrada           1      1  0.999
2  diente de sierra           3     -1 -0.997

Emparejamiento PCA (mismo criterio voraz):
             fuente  componente  signo      r
0          senoidal           3      1  0.753
1          cuadrada           2      1  0.780
2  diente de sierra           1      1  0.604</code></pre>
</div>
</div>
<div id="2c871af6" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:03.003736Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:03.003531Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:03.464710Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:03.463893Z&quot;}}" data-execution_count="14">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1">paneles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb23-2">    (fuentes, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'fuente original'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>),</span>
<span id="cb23-3">    (ica_alineada, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ICA alineada'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>),</span>
<span id="cb23-4">    (pca_alineada, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PCA alineada'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'0.35'</span>),</span>
<span id="cb23-5">]</span>
<span id="cb23-6"></span>
<span id="cb23-7">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">10.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.2</span>), sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb23-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> fila, (series, etiqueta, color) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(paneles):</span>
<span id="cb23-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> col <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb23-10">        ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> axes[fila, col]</span>
<span id="cb23-11">        ax.plot(t, series[:, col], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb23-12">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> fila <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb23-13">            ax.set_title(NOMBRES_FUENTES[col], fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb23-14">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> col <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb23-15">            ax.set_ylabel(etiqueta, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span>
<span id="cb23-16">        ax.set_xlim(t.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), t.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>())</span>
<span id="cb23-17">axes[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb23-18">fig.suptitle(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Tres filas: originales, ICA (sí separa) y PCA (no separa)'</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.02</span>)</span>
<span id="cb23-19">plt.tight_layout()</span>
<span id="cb23-20">plt.show()</span>
<span id="cb23-21"></span>
<span id="cb23-22">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">11.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.1</span>))</span>
<span id="cb23-23">nubes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb23-24">    (fuentes[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], fuentes[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'fuentes'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>),</span>
<span id="cb23-25">    (mezclas[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], mezclas[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mezclas'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'darkorange'</span>),</span>
<span id="cb23-26">    (pca_alineada[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], pca_alineada[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PCA alineada'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'0.35'</span>),</span>
<span id="cb23-27">    (ica_alineada[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], ica_alineada[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ICA alineada'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>),</span>
<span id="cb23-28">]</span>
<span id="cb23-29"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax, (x, y, titulo, color) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(axes, nubes):</span>
<span id="cb23-30">    ax.scatter(x, y, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color)</span>
<span id="cb23-31">    ax.set_title(titulo, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span>
<span id="cb23-32">    ax.set_xticks([])</span>
<span id="cb23-33">    ax.set_yticks([])</span>
<span id="cb23-34">    ax.set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'equal'</span>, adjustable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'datalim'</span>)</span>
<span id="cb23-35">fig.suptitle(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Las dos bandas de las fuentes reaparecen con ICA, no con PCA'</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.08</span>)</span>
<span id="cb23-36">plt.tight_layout()</span>
<span id="cb23-37">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/13-ica/index_files/figure-html/cell-15-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/13-ica/index_files/figure-html/cell-15-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-7" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-7">Cómo leer este resultado</h3>
<p>Lee la figura de las series por columnas. En cada una, la fila verde (ICA) copia la forma azul (la fuente). La fila gris (PCA) no: incluso después de elegir la componente más parecida y de corregir el signo, las trazas siguen mezcladas.</p>
<p>Los <img src="https://latex.codecogs.com/png.latex?%7Cr%7C"> del emparejamiento exclusivo resumen lo mismo en un número: ICA queda en <strong>0.997</strong>, <strong>0.999</strong> y <strong>0.997</strong>; PCA, en <strong>0.753</strong>, <strong>0.780</strong> y <strong>0.604</strong>.</p>
<p>La nube de abajo cierra el argumento: las dos bandas horizontales de las fuentes reaparecen con ICA; la nube de PCA, en cambio, no se parece a la de las fuentes. El contraste del cóctel no es de matices. Es de método.</p>
</section>
</section>
<section id="matices-honestos-orden-escala-y-signo" class="level2">
<h2 class="anchored" data-anchor-id="matices-honestos-orden-escala-y-signo">Matices honestos: orden, escala y signo</h2>
<p>ICA recupera la <strong>forma</strong> de las fuentes, no su etiquetado ni su unidad. Hay dos ambigüedades inherentes:</p>
<ul>
<li><strong>Orden.</strong> Nada en <img src="https://latex.codecogs.com/png.latex?X%20=%20S%20A%5E%7B%5Ctop%7D"> dice cuál fuente es la primera. Permutar las columnas de <img src="https://latex.codecogs.com/png.latex?S"> y las filas de <img src="https://latex.codecogs.com/png.latex?A%5E%7B%5Ctop%7D"> deja las mezclas iguales. FastICA numera componentes según el camino de optimización, no según tu lista original.</li>
<li><strong>Escala y signo.</strong> Multiplicar una fuente por <img src="https://latex.codecogs.com/png.latex?-c"> y dividir la columna correspondiente de <img src="https://latex.codecogs.com/png.latex?A"> por <img src="https://latex.codecogs.com/png.latex?-c"> tampoco cambia <img src="https://latex.codecogs.com/png.latex?X">. Por eso IC3 salió como diente <strong>invertido</strong> (<img src="https://latex.codecogs.com/png.latex?r%20=%20-0.997">) y todas las componentes tienen varianza 1.</li>
</ul>
<p>En la práctica eso rara vez es un problema grave: si recuperas una voz, la reconoces aunque suene un poco más baja o con la polaridad cambiada. Lo que no debes hacer es interpretar el índice <code>IC1</code> como “la primera fuente que imaginabas”.</p>
<div id="4cc54069" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:03.467043Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:03.466686Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:03.471986Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:03.471334Z&quot;}}" data-execution_count="15">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Varianza de cada componente ICA (deben ser 1 por el blanqueo):'</span>)</span>
<span id="cb24-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb24-3">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  IC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>comp_ica[:, i]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>var()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb24-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb24-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Producto signo × |r| ya visto en el emparejamiento ICA:'</span>)</span>
<span id="cb24-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> fila <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> detalle_ica.itertuples(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>):</span>
<span id="cb24-7">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(</span>
<span id="cb24-8">        <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>fila<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>fuente<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:&gt;18}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> &lt;- IC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>fila<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>componente<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> '</span></span>
<span id="cb24-9">        <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'(signo </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>fila<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>signo<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:+d}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, r = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>fila<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>r<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span></span>
<span id="cb24-10">    )</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Varianza de cada componente ICA (deben ser 1 por el blanqueo):
  IC1: 1.000
  IC2: 1.000
  IC3: 1.000

Producto signo × |r| ya visto en el emparejamiento ICA:
            senoidal &lt;- IC2 (signo +1, r = 0.997)
            cuadrada &lt;- IC1 (signo +1, r = 0.999)
    diente de sierra &lt;- IC3 (signo -1, r = -0.997)</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-8" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-8">Cómo leer este resultado</h3>
<p>Las tres varianzas valen <strong>1.000</strong>: ICA te entrega formas, no las amplitudes originales de cada fuente. El diente quedó asociado a IC3 con signo <strong>-1</strong>. Si graficas IC3 sin corregir, la rampa se ve hacia abajo; la señal es la misma.</p>
<p>Cuando reportes un ICA, reporta las formas y, si el dominio lo permite, reordena y voltea con un criterio externo (por ejemplo, correlacionar con una fuente piloto). No trates el orden del software como un hallazgo.</p>
</section>
</section>
<section id="cuando-ica-no-funciona-fuentes-gaussianas" class="level2">
<h2 class="anchored" data-anchor-id="cuando-ica-no-funciona-fuentes-gaussianas">Cuando ICA no funciona: fuentes gaussianas</h2>
<p>El supuesto de no gaussianidad no es cosmética. Si las tres voces fueran ruido blanco gaussiano independiente, cualquier rotación de las mezclas blanqueadas seguiría viéndose como “fuentes independientes”. El modelo deja de tener una solución única, y FastICA no tiene un criterio con el que preferir las voces verdaderas.</p>
<p>Repetimos el experimento con las <strong>mismas</strong> <img src="https://latex.codecogs.com/png.latex?A"> y <img src="https://latex.codecogs.com/png.latex?n">, pero reemplazando las tres señales reconocibles por gaussianas independientes.</p>
<div id="4fbef9a7" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:03.473920Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:03.473721Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:03.486182Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:03.485319Z&quot;}}" data-execution_count="16">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb26" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb26-1">fuentes_g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb26-2">fuentes_g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (fuentes_g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> fuentes_g.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> fuentes_g.std(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb26-3">mezclas_g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fuentes_g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> A.T</span>
<span id="cb26-4"></span>
<span id="cb26-5">ica_g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> FastICA(</span>
<span id="cb26-6">    n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,</span>
<span id="cb26-7">    random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>SEMILLA,</span>
<span id="cb26-8">    whiten<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'unit-variance'</span>,</span>
<span id="cb26-9">    max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>,</span>
<span id="cb26-10">)</span>
<span id="cb26-11">comp_ica_g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ica_g.fit_transform(mezclas_g)</span>
<span id="cb26-12">ica_g_alineada, detalle_ica_g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> alinear_con_fuentes(</span>
<span id="cb26-13">    comp_ica_g,</span>
<span id="cb26-14">    fuentes_g,</span>
<span id="cb26-15">    nombres<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'fuente 1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'fuente 2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'fuente 3'</span>],</span>
<span id="cb26-16">)</span>
<span id="cb26-17"></span>
<span id="cb26-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Exceso de curtosis de las fuentes gaussianas:'</span>)</span>
<span id="cb26-19"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb26-20">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  fuente </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>kurtosis_exceso(fuentes_g[:, j])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">: .3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb26-21"></span>
<span id="cb26-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb26-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Mejor emparejamiento ICA frente a gaussianas:'</span>)</span>
<span id="cb26-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(detalle_ica_g.assign(r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> d: d[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)))</span>
<span id="cb26-25"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb26-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'|r| máximo por fuente (ICA en el cóctel original):'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">', '</span>.join(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(r)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> r <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> detalle_ica[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>]))</span>
<span id="cb26-27"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'|r| máximo por fuente (ICA con gaussianas):     '</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">', '</span>.join(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(r)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> r <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> detalle_ica_g[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>]))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Exceso de curtosis de las fuentes gaussianas:
  fuente 1: -0.070
  fuente 2: -0.144
  fuente 3:  0.047

Mejor emparejamiento ICA frente a gaussianas:
     fuente  componente  signo      r
0  fuente 1           3     -1 -0.706
1  fuente 2           1      1  0.793
2  fuente 3           2     -1 -0.501

|r| máximo por fuente (ICA en el cóctel original): 0.997, 0.999, 0.997
|r| máximo por fuente (ICA con gaussianas):      0.706, 0.793, 0.501</code></pre>
</div>
</div>
<div id="a2f935f3" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:03.487806Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:03.487617Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:03.776203Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:03.775193Z&quot;}}" data-execution_count="17">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb28" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb28-1">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">10.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.4</span>), sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb28-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> col <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb28-3">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, col].plot(t, fuentes_g[:, col], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb28-4">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, col].set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'fuente gaussiana </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>col <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb28-5">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col].plot(t, ica_g_alineada[:, col], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seagreen'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb28-6">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col].set_xlim(t.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), t.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>())</span>
<span id="cb28-7">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'original'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span>
<span id="cb28-8">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ICA alineada'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span>
<span id="cb28-9">axes[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb28-10">fig.suptitle(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Con fuentes gaussianas, ICA ya no recupera las voces'</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.03</span>)</span>
<span id="cb28-11">plt.tight_layout()</span>
<span id="cb28-12">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/13-ica/index_files/figure-html/cell-18-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-9" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-9">Cómo leer este resultado</h3>
<p>Las curtosis de las fuentes gaussianas quedan cerca de cero (<strong>-0.070</strong>, <strong>-0.144</strong>, <strong>0.047</strong>): son campanas, como corresponde. El mejor <img src="https://latex.codecogs.com/png.latex?%7Cr%7C"> de ICA cae a <strong>0.706</strong>, <strong>0.793</strong> y <strong>0.501</strong>. Compáralo con <strong>0.997–0.999</strong> del cóctel no gaussiano. En la figura, las dos filas se ven como ruido y la inspección visual no basta para compararlas: la evidencia está en los <img src="https://latex.codecogs.com/png.latex?%7Cr%7C">, que ya no se acercan a 1.</p>
<p>No es que FastICA “falle al optimizar”. Es que, con gaussianas, <strong>no hay una rotación correcta que el criterio pueda elegir</strong>. Si tus fuentes se parecen a una campana, ICA no es la herramienta.</p>
</section>
</section>
<section id="pca-frente-a-ica" class="level2">
<h2 class="anchored" data-anchor-id="pca-frente-a-ica">PCA frente a ICA</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th></th>
<th>PCA</th>
<th>ICA</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Objetivo</strong></td>
<td>Direcciones de máxima varianza</td>
<td>Componentes estadísticamente independientes</td>
</tr>
<tr class="even">
<td><strong>Criterio</strong></td>
<td>Autovectores de la covarianza (momentos de orden 2)</td>
<td>No gaussianidad / independencia (momentos de orden superior)</td>
</tr>
<tr class="odd">
<td><strong>Supuesto clave</strong></td>
<td>La varianza concentra la información útil</td>
<td>Fuentes independientes y no gaussianas</td>
</tr>
<tr class="even">
<td><strong>Ortogonalidad</strong></td>
<td>Direcciones (cargas) ortogonales; componentes incorrelacionadas</td>
<td>Componentes incorrelacionadas; la matriz de separación <img src="https://latex.codecogs.com/png.latex?W"> no es ortogonal en el espacio original (solo la rotación posterior al blanqueo lo es)</td>
</tr>
<tr class="odd">
<td><strong>Orden de las componentes</strong></td>
<td>Decreciente en varianza explicada</td>
<td>Arbitrario</td>
</tr>
<tr class="even">
<td><strong>Escala / signo</strong></td>
<td>Signo del autovector es arbitrario; la escala sigue a la varianza</td>
<td>Escala y signo son arbitrarios</td>
</tr>
<tr class="odd">
<td><strong>Cuándo usarlo</strong></td>
<td>Reducir dimensión, visualizar, quitar colinealidad</td>
<td>Separar señales mezcladas, desenredar fuentes latentes</td>
</tr>
<tr class="even">
<td><strong>Cuándo no</strong></td>
<td>Cuando la dirección útil no es la de más varianza</td>
<td>Cuando las fuentes son gaussianas o la mezcla no es lineal</td>
</tr>
</tbody>
</table>
<p>No eliges el “más moderno”. Eliges el que responde a tu pregunta. Si quieres un plano que conserve energía, PCA. Si quieres las voces de la fiesta, ICA.</p>
</section>
<section id="incorrelación-no-es-independencia" class="level2">
<h2 class="anchored" data-anchor-id="incorrelación-no-es-independencia">Incorrelación no es independencia</h2>
<p>Un último control, para que el contraste no quede solo en el gráfico de las series. Tanto PCA como ICA producen componentes <strong>incorrelacionadas</strong> (la correlación entre componentes vale ~0). Esa condición la cumplen los dos. Lo que distingue a ICA es haber recuperado la no gaussianidad de las voces originales.</p>
<div id="cd2a4713" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:06:03.777871Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:06:03.777667Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:06:03.786790Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:06:03.786066Z&quot;}}" data-execution_count="18">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb29" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb29-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Correlación entre componentes PCA:'</span>)</span>
<span id="cb29-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame(np.corrcoef(comp_pca.T).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC3'</span>], columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC3'</span>]))</span>
<span id="cb29-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb29-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Correlación entre componentes ICA:'</span>)</span>
<span id="cb29-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame(np.corrcoef(comp_ica.T).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC3'</span>], columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC3'</span>]))</span>
<span id="cb29-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb29-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Curtosis | fuentes:'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">', '</span>.join(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>kurtosis_exceso(fuentes[:, j])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)))</span>
<span id="cb29-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Curtosis | PCA:    '</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">', '</span>.join(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>kurtosis_exceso(comp_pca[:, j])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)))</span>
<span id="cb29-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Curtosis | ICA:    '</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">', '</span>.join(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>kurtosis_exceso(comp_ica[:, j])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Correlación entre componentes PCA:
     PC1  PC2  PC3
PC1  1.0  0.0  0.0
PC2  0.0  1.0  0.0
PC3  0.0  0.0  1.0

Correlación entre componentes ICA:
     IC1  IC2  IC3
IC1  1.0  0.0  0.0
IC2  0.0  1.0  0.0
IC3  0.0  0.0  1.0

Curtosis | fuentes: -1.347, -1.981, -1.174
Curtosis | PCA:     -0.497, -0.769, -0.783
Curtosis | ICA:     -1.976, -1.360, -1.158</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-10" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-10">Cómo leer este resultado</h3>
<p>Las dos matrices de correlación son la identidad: PCA e ICA <strong>decorrelacionan</strong>. Si te quedaras ahí, parecerían equivalentes.</p>
<p>La curtosis los separa. Las fuentes estaban en <strong>-1.347</strong>, <strong>-1.981</strong>, <strong>-1.174</strong>. ICA recupera valores del mismo orden (<strong>-1.976</strong>, <strong>-1.360</strong>, <strong>-1.158</strong>), permutados como las componentes. PCA se queda a medio camino (<strong>-0.497</strong>, <strong>-0.769</strong>, <strong>-0.783</strong>): más gaussiana, como las mezclas. Incorrelación lograda; independencia, no.</p>
</section>
</section>
<section id="dos-caras-de-las-variables-latentes" class="level2">
<h2 class="anchored" data-anchor-id="dos-caras-de-las-variables-latentes">Dos caras de las variables latentes</h2>
<p>PCA e ICA responden a la misma idea de fondo: las columnas que ves no son necesariamente las variables que importan. A veces el patrón útil está escondido en una combinación de las observadas.</p>
<ul>
<li><strong>PCA</strong> comprime. Encuentra pocas direcciones que conserven la varianza. Es reducción de dimensionalidad.</li>
<li><strong>ICA</strong> separa. Encuentra direcciones que recuperen fuentes independientes. Es separación de señales.</li>
</ul>
<p>Son dos caras de las <strong>variables latentes</strong>: factores no observados que organizan lo que mides. No compiten en abstracto. Compiten —o se complementan— según la pregunta. En el cóctel de este artículo, la pregunta era separar voces, y el ganador no fue la máxima varianza.</p>
</section>
<section id="qué-sigue" class="level2">
<h2 class="anchored" data-anchor-id="qué-sigue">¿Qué sigue?</h2>
<p>Hasta aquí cada instante se podía tratar como un punto: el orden temporal no era el objeto de estudio, solo el soporte de las señales. El próximo tema cambia esa premisa. Los datos llegan <strong>en el tiempo</strong>, y lo que ocurrió antes informa lo que puede ocurrir después.</p>
<p>Ahí entran las <strong>series de tiempo</strong> y, en general, los <strong>datos dependientes</strong>: correlación serial, tendencias, estacionalidad y modelos que respetan el orden. La independencia entre observaciones, que ICA asume entre fuentes y que buena parte de lo anterior asume entre filas, deja de ser el caso por defecto.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>variables-latentes</category>
  <category>ica</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/avanzado/13-ica/</guid>
  <pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Análisis Avanzado de Datos — 14. Series de tiempo</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/</link>
  <description><![CDATA[ 




<section id="análisis-avanzado-de-datos-14.-series-de-tiempo" class="level1">
<h1>Análisis Avanzado de Datos — 14. Series de tiempo</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado convierte datos en decisiones. Científico de Datos, Arquitecto de IA y asesor tecnológico con más de 20 años de experiencia en analítica avanzada, machine learning, Big Data e IoT. Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), asesora a entidades gubernamentales y empresas privadas en Colombia y es referente en analítica y normatividad para los sectores postal y logístico del país. Una serie pensada para ir de la teoría a la práctica, con ejemplos concretos en cada paso.</p>
<p>📌 <em>Parte de la serie <strong>Análisis Avanzado de Datos</strong>.</em></p>
</section>
<section id="un-cambio-de-paradigma-las-observaciones-ya-no-son-independientes" class="level2">
<h2 class="anchored" data-anchor-id="un-cambio-de-paradigma-las-observaciones-ya-no-son-independientes">Un cambio de paradigma: las observaciones ya no son independientes</h2>
<p>Hasta ahora, casi todos los métodos que usaste partían de un supuesto silencioso: <strong>cada fila es independiente de las demás</strong>. Una entrega no informaba sobre la siguiente; un vino no informaba sobre el otro. Podías barajar las filas, partir al azar en entrenamiento y prueba, y los p-valores seguían queriendo decir lo que aparentaban.</p>
<p>Ese supuesto se cae en cuanto los datos vienen <strong>ordenados en el tiempo</strong>. El número de pasajeros de este mes se parece al del mes pasado. La demanda de envíos de diciembre se parece a la de diciembre anterior. Si ignoras esa dependencia, ocurren tres fallos graves:</p>
<ul>
<li>los errores estándar salen demasiado pequeños y los p-valores se vuelven optimistas;</li>
<li>un corte aleatorio entrenamiento/prueba <strong>filtra el futuro hacia el pasado</strong>;</li>
<li>el modelo “aprende” patrones que en producción nunca tendría a mano.</li>
</ul>
<p>Este artículo abre el territorio de los <strong>datos dependientes</strong>. El primer caso es una sola serie observada a lo largo del tiempo. Trabajarás con el clásico de pasajeros aéreos (1949-1960) para aprender los conceptos, y luego con una demanda mensual de envíos para aplicar el mismo flujo a un problema de planificación logística.</p>
</section>
<section id="objetivos-de-aprendizaje" class="level2">
<h2 class="anchored" data-anchor-id="objetivos-de-aprendizaje">Objetivos de aprendizaje</h2>
<p>Al terminar este notebook vas a ser capaz de:</p>
<ul>
<li><strong>Explicar</strong> por qué una serie de tiempo no se puede barajar ni partir al azar sin romper el orden.</li>
<li><strong>Descomponer</strong> una serie en tendencia, estacionalidad y residuo, y decidir si el patrón es aditivo o multiplicativo.</li>
<li><strong>Reconocer</strong> la no estacionariedad (media o varianza que se escapan) y aplicar la prueba de Dickey–Fuller aumentada <strong>sin sobreinterpretar el p-valor</strong>.</li>
<li><strong>Transformar</strong> una serie (logaritmo, diferencias regular y estacional) y comprobar si la transformación basta.</li>
<li><strong>Leer</strong> la ACF y la PACF, incluyendo los picos en rezagos estacionales.</li>
<li><strong>Ajustar</strong> un pronóstico de Holt–Winters eligiendo la especificación con <strong>validación temporal</strong> sobre el pasado, y reportar el error solo en el futuro reservado.</li>
<li><strong>Trasladar</strong> el mismo flujo a una serie de demanda de envíos para anticipar picos de temporada.</li>
</ul>
</section>
<section id="preparación-del-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparación-del-entorno">Preparación del entorno</h2>
<p>Cargamos <code>numpy</code>, <code>pandas</code>, <code>matplotlib</code> y las herramientas de series de tiempo de <code>statsmodels</code>, y fijamos una semilla global <code>SEMILLA</code> para que el barajado, el corte aleatorio y la simulación de envíos sean reproducibles.</p>
<div id="b076c892" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:31.463838Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:31.463558Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:34.380817Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:34.379197Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> warnings</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.tsa.seasonal <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seasonal_decompose</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.tsa.stattools <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> adfuller, acf</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.tsa.holtwinters <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> ExponentialSmoothing</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.graphics.tsaplots <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plot_acf, plot_pacf</span>
<span id="cb1-9"></span>
<span id="cb1-10">SEMILLA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2026</span></span>
<span id="cb1-11">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb1-12">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'figure.figsize'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb1-13">warnings.filterwarnings(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ignore'</span>, category<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">FutureWarning</span>)</span></code></pre></div></div>
</div>
</section>
<section id="qué-hace-única-a-una-serie-de-tiempo" class="level2">
<h2 class="anchored" data-anchor-id="qué-hace-única-a-una-serie-de-tiempo">Qué hace única a una serie de tiempo</h2>
<p>Una serie de tiempo es una sucesión <img src="https://latex.codecogs.com/png.latex?%5C%7BY_t%5C%7D_%7Bt=1%7D%5E%7BT%7D"> <strong>indexada por el calendario</strong>. El subíndice <img src="https://latex.codecogs.com/png.latex?t"> no es un identificador cosmético: es el orden en el que ocurrieron los hechos. La propiedad que la define es la <strong>dependencia temporal</strong>:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7BCorr%7D(Y_t,%20Y_%7Bt-k%7D)%20%5Cneq%200%0A%5Cquad%20%5Ctext%7Bpara%20alg%C3%BAn%20rezago%20%7D%20k%20%5Cgeq%201.%0A"></p>
<p>En el mundo independiente que venías usando,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathbb%7BP%7D(Y_t%20%5Cmid%20Y_%7Bt-1%7D,%5Cldots,Y_1)%20=%20%5Cmathbb%7BP%7D(Y_t).%0A"></p>
<p>Aquí esa igualdad <strong>no vale</strong>: conocer el ayer cambia lo que esperas del hoy. Por eso no puedes:</p>
<ol type="1">
<li><strong>Barajar las filas.</strong> Destruirías la única estructura que hace que la serie sea una serie.</li>
<li><strong>Hacer un <code>train_test_split</code> aleatorio.</strong> Algunos puntos de 1960 acabarían en entrenamiento y algunos de 1949 en prueba. Estarías usando el futuro para “predecir” el pasado.</li>
</ol>
<p>El corte honesto es <strong>temporal</strong>: entrenas con el pasado y reservas los <strong>últimos</strong> periodos para evaluar. En producción nunca tendrás el futuro dentro del entrenamiento. Vamos a verlo con datos, no solo con el argumento.</p>
</section>
<section id="los-datos-pasajeros-aéreos-1949-1960" class="level2">
<h2 class="anchored" data-anchor-id="los-datos-pasajeros-aéreos-1949-1960">Los datos: pasajeros aéreos, 1949-1960</h2>
<p>El conjunto <strong>Air Passengers</strong> registra el total mensual de pasajeros de líneas aéreas internacionales, en miles, de enero de 1949 a diciembre de 1960. Es el ejemplo canónico de Box y Jenkins: una tendencia clara de crecimiento y un ciclo anual que se amplifica con el nivel. Lo usamos precisamente porque esos dos ingredientes —tendencia y estacionalidad— son los que rompen los métodos pensados para observaciones independientes.</p>
<div id="7704a622" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:34.383834Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:34.383313Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:34.627229Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:34.625756Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Air Passengers (1949-1960) embebido para que el notebook sea autocontenido (sin internet).</span></span>
<span id="cb2-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Serie clásica de pasajeros aéreos internacionales mensuales, en miles.</span></span>
<span id="cb2-3">_ap <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">112</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">118</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">132</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">129</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">121</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">135</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">148</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">148</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">136</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">119</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">104</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">118</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">115</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">126</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">141</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">135</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">125</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">149</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">170</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">170</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">158</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">133</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">114</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">140</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">145</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">150</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">178</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">163</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">172</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">178</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">199</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">199</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">184</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">162</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">146</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">166</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">171</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">193</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">181</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">183</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">218</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">230</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">242</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">209</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">191</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">172</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">194</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">196</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">196</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">236</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">235</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">229</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">243</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">264</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">272</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">237</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">211</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">201</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">204</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">188</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">235</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">227</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">234</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">264</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">302</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">293</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">259</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">229</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">203</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">229</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">242</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">233</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">267</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">269</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">270</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">315</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">364</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">347</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">312</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">274</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">237</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">278</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">284</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">277</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">317</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">313</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">318</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">374</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">413</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">405</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">355</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">306</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">271</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">306</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">315</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">301</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">356</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">348</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">355</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">422</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">465</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">467</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">404</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">347</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">305</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">336</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">340</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">318</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">362</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">348</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">363</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">435</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">491</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">505</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">404</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">359</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">310</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">337</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">360</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">342</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">406</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">396</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">420</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">472</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">548</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">559</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">463</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">407</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">362</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">405</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">417</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">391</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">419</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">461</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">472</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">535</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">622</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">606</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">508</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">461</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">390</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">432</span>]</span>
<span id="cb2-4">pasajeros <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(</span>
<span id="cb2-5">    np.array(_ap, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>),</span>
<span id="cb2-6">    index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>pd.date_range(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'1949-01-01'</span>, periods<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(_ap), freq<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MS'</span>),</span>
<span id="cb2-7">    name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pasajeros'</span>,</span>
<span id="cb2-8">)</span>
<span id="cb2-9"></span>
<span id="cb2-10">anual <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb2-11">    pasajeros.groupby(pasajeros.index.year)</span>
<span id="cb2-12">    .agg(media<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean'</span>, desv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'std'</span>, minimo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'min'</span>, maximo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'max'</span>)</span>
<span id="cb2-13">)</span>
<span id="cb2-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(pasajeros)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> meses | </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pasajeros<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>index<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>date()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> → </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pasajeros<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>index<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>date()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'mínimo = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pasajeros<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   máximo = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pasajeros<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb2-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb2-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(anual.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb2-18"></span>
<span id="cb2-19">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb2-20">ax.plot(pasajeros.index, pasajeros.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb2-21">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb2-22">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pasajeros (miles)'</span>)</span>
<span id="cb2-23">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Pasajeros aéreos internacionales, 1949-1960'</span>)</span>
<span id="cb2-24">plt.tight_layout()</span>
<span id="cb2-25">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>144 meses | 1949-01-01 → 1960-12-01
mínimo = 104   máximo = 622

      media  desv  minimo  maximo
1949  126.7  13.7   104.0   148.0
1950  139.7  19.1   114.0   170.0
1951  170.2  18.4   145.0   199.0
1952  197.0  23.0   171.0   242.0
1953  225.0  28.5   180.0   272.0
1954  238.9  34.9   188.0   302.0
1955  284.0  42.1   233.0   364.0
1956  328.2  47.9   271.0   413.0
1957  368.4  57.9   301.0   467.0
1958  381.0  64.5   310.0   505.0
1959  428.3  69.8   342.0   559.0
1960  476.2  77.7   390.0   622.0</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-3-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado">Cómo leer este resultado</h3>
<p>Son <strong>144 meses</strong> (enero 1949 a diciembre 1960). El mínimo es <strong>104</strong> miles de pasajeros y el máximo <strong>622</strong>. La media anual pasa de <strong>126.7</strong> en 1949 a <strong>476.2</strong> en 1960: la serie no oscila alrededor de un nivel fijo, <strong>sube</strong>. Fíjate también en la columna <code>desv</code>: <strong>13.7</strong> al inicio y <strong>77.7</strong> al final. No solo crece el nivel; crece la amplitud de las oscilaciones. Ese abanico que se abre es la firma de una estacionalidad <strong>multiplicativa</strong>: los picos de verano son cada vez más altos porque el negocio es cada vez más grande.</p>
</section>
</section>
<section id="experimento-qué-se-rompe-si-barajas-el-tiempo" class="level2">
<h2 class="anchored" data-anchor-id="experimento-qué-se-rompe-si-barajas-el-tiempo">Experimento: qué se rompe si barajas el tiempo</h2>
<p>Toma los mismos 144 números y ponlos en orden aleatorio, dejando el eje de fechas intacto. Si el tiempo fuera solo una etiqueta, las dos gráficas contarían la misma historia. No la cuentan. Para medirlo usamos la <strong>autocorrelación</strong> (ACF, por <em>autocorrelation function</em>): la correlación de la serie con ella misma desplazada <img src="https://latex.codecogs.com/png.latex?k"> meses, lo que se llama el <strong>rezago</strong> <img src="https://latex.codecogs.com/png.latex?k">. Más adelante la verás con detalle.</p>
<div id="98f07986" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:34.630128Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:34.629585Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:34.890217Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:34.888135Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">pasajeros_barajados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(</span>
<span id="cb4-2">    rng.permutation(pasajeros.to_numpy()),</span>
<span id="cb4-3">    index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>pasajeros.index,</span>
<span id="cb4-4">)</span>
<span id="cb4-5"></span>
<span id="cb4-6">acf_orig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> acf(pasajeros, nlags<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, fft<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb4-7">acf_baraj <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> acf(pasajeros_barajados, nlags<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, fft<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb4-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'ACF lag 1  | original = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acf_orig[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  | barajada = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acf_baraj[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb4-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'ACF lag 12 | original = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acf_orig[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | barajada = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acf_baraj[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb4-10"></span>
<span id="cb4-11">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>), sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, sharey<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb4-12">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(pasajeros.index, pasajeros.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb4-13">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pasajeros (miles)'</span>)</span>
<span id="cb4-14">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Serie original: el orden cuenta'</span>)</span>
<span id="cb4-15">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(pasajeros_barajados.index, pasajeros_barajados.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>)</span>
<span id="cb4-16">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pasajeros (miles)'</span>)</span>
<span id="cb4-17">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb4-18">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Mismos valores, orden aleatorio'</span>)</span>
<span id="cb4-19">plt.tight_layout()</span>
<span id="cb4-20">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>ACF lag 1  | original = 0.948  | barajada = -0.162
ACF lag 12 | original = 0.760 | barajada = -0.136</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-4-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-1">Cómo leer este resultado</h3>
<p>En la serie original, la autocorrelación en el rezago 1 es <strong>0.948</strong>: cada mes se parece muchísimo al anterior. En el rezago 12 es <strong>0.760</strong>: cada julio se parece al julio previo. Al barajar, esas cifras caen a <strong>-0.162</strong> y <strong>-0.136</strong>, compatibles con ruido (con 144 datos, la banda aproximada del 95% para una serie sin dependencia es ±0.16). No perdiste datos; perdiste el <strong>orden</strong>. Una serie de tiempo sin su orden es un histograma, no un proceso.</p>
</section>
</section>
<section id="el-corte-entrenamientoprueba-también-tiene-que-respetar-el-tiempo" class="level2">
<h2 class="anchored" data-anchor-id="el-corte-entrenamientoprueba-también-tiene-que-respetar-el-tiempo">El corte entrenamiento/prueba también tiene que respetar el tiempo</h2>
<p>El mismo argumento se aplica a cómo evalúas un modelo. Si reservas 12 meses al azar como “prueba”, algunos serán de 1949 y otros de 1959 —o, peor, de 1960—. El modelo podría entrenarse <strong>viendo el futuro</strong> y luego “predecir” el pasado. Eso no es pronóstico: es filtrar información que en producción no tendrías.</p>
<p>El único corte honesto es <strong>temporal</strong>: los últimos <img src="https://latex.codecogs.com/png.latex?N"> periodos quedan fuera, intactos, hasta el reporte final. Cualquier decisión de modelo (aditivo o multiplicativo, cuántas diferencias, qué rezagos) se toma <strong>solo con el pasado</strong>.</p>
<div id="28363f7c" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:34.892884Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:34.892634Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:35.143595Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:35.142570Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">n_prueba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span></span>
<span id="cb6-2">idx_tiempo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(pasajeros))</span>
<span id="cb6-3">es_prueba_temporal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> idx_tiempo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> (<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(pasajeros) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> n_prueba)</span>
<span id="cb6-4">es_prueba_aleatoria <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(pasajeros), dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">bool</span>)</span>
<span id="cb6-5">es_prueba_aleatoria[rng.choice(idx_tiempo, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_prueba, replace<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb6-6"></span>
<span id="cb6-7">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>), sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, sharey<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb6-8">paneles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb6-9">    (es_prueba_temporal, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Corte temporal: los últimos 12 meses son prueba'</span>),</span>
<span id="cb6-10">    (es_prueba_aleatoria, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Corte aleatorio: la prueba aparece en cualquier año'</span>),</span>
<span id="cb6-11">]</span>
<span id="cb6-12"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax, (mask, titulo) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(axes, paneles):</span>
<span id="cb6-13">    ax.plot(pasajeros.index[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>mask], pasajeros.values[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>mask],</span>
<span id="cb6-14">            color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'entrenamiento'</span>)</span>
<span id="cb6-15">    ax.plot(pasajeros.index[mask], pasajeros.values[mask],</span>
<span id="cb6-16">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'prueba'</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb6-17">    ax.set_title(titulo)</span>
<span id="cb6-18">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pasajeros (miles)'</span>)</span>
<span id="cb6-19">    ax.legend(loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'upper left'</span>)</span>
<span id="cb6-20">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb6-21">plt.tight_layout()</span>
<span id="cb6-22">plt.show()</span>
<span id="cb6-23"></span>
<span id="cb6-24">anios_aleatorios <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(pasajeros.index[es_prueba_aleatoria].year.tolist())</span>
<span id="cb6-25">anios_temporales <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(pasajeros.index[es_prueba_temporal].year.unique().tolist())</span>
<span id="cb6-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Años que caerían en la prueba aleatoria:'</span>, anios_aleatorios)</span>
<span id="cb6-27"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Años en la prueba temporal:            '</span>, anios_temporales)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-5-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Años que caerían en la prueba aleatoria: [1949, 1952, 1952, 1953, 1953, 1955, 1955, 1956, 1956, 1956, 1958, 1959]
Años en la prueba temporal:             [1960]</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-2" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-2">Cómo leer este resultado</h3>
<p>En el corte temporal, <strong>toda</strong> la prueba es 1960: el año que un pronóstico real tendría que adivinar. En el corte aleatorio, los 12 puntos rojos caen en 1949, 1952, 1953, 1955, 1956, 1958 y 1959. Ninguno es de 1960: el futuro queda <strong>dentro del entrenamiento</strong> y el pasado, en la prueba. Un modelo así puede “acertar” 1949 porque ya vio 1959. Eso no se sostiene el día en que tengas que publicar el número del mes que todavía no ocurrió.</p>
<blockquote class="blockquote">
<p><strong>Punto clave.</strong> En series de tiempo, barajar y partir al azar no son atajos inocentes: <strong>rompen la dependencia y filtran el futuro</strong>. El protocolo es siempre el mismo: el pasado entrena, el futuro reciente valida, el último tramo se reserva para el error que sí vas a reportar.</p>
</blockquote>
</section>
</section>
<section id="los-tres-componentes-tendencia-estacionalidad-y-residuo" class="level2">
<h2 class="anchored" data-anchor-id="los-tres-componentes-tendencia-estacionalidad-y-residuo">Los tres componentes: tendencia, estacionalidad y residuo</h2>
<p>Una forma útil de mirar una serie es partirla en tres piezas:</p>
<ul>
<li><strong>Tendencia</strong> <img src="https://latex.codecogs.com/png.latex?T_t">: el movimiento de fondo, lento. Aquí, el crecimiento del tráfico aéreo.</li>
<li><strong>Estacionalidad</strong> <img src="https://latex.codecogs.com/png.latex?S_t">: el patrón que se repite cada <img src="https://latex.codecogs.com/png.latex?m"> periodos. Con datos mensuales, <img src="https://latex.codecogs.com/png.latex?m=12">: veranos altos, inviernos bajos.</li>
<li><strong>Residuo</strong> <img src="https://latex.codecogs.com/png.latex?R_t">: lo que no explican los dos anteriores.</li>
</ul>
<p>En una descomposición <strong>aditiva</strong>, <img src="https://latex.codecogs.com/png.latex?Y_t%20=%20T_t%20+%20S_t%20+%20R_t">. En una <strong>multiplicativa</strong>, <img src="https://latex.codecogs.com/png.latex?Y_t%20=%20T_t%20%5Ccdot%20S_t%20%5Ccdot%20R_t">. La segunda es la natural cuando la amplitud de la estación crece con el nivel: el pico de julio no suma siempre la misma cantidad de pasajeros (una descomposición aditiva le asignaría unos 64 mil cada julio, lo mismo en 1949 que en 1960); <strong>multiplica</strong> la tendencia por un factor cercano a 1.23.</p>
<p><code>seasonal_decompose</code> de statsmodels estima esas tres piezas con medias móviles. No es un modelo de pronóstico; es una radiografía.</p>
<div id="65219116" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:35.145650Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:35.145437Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:35.409529Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:35.408668Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">decomp_mul <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> seasonal_decompose(pasajeros, model<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'multiplicative'</span>, period<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb8-2">decomp_add <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> seasonal_decompose(pasajeros, model<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'additive'</span>, period<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb8-3"></span>
<span id="cb8-4">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>), sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb8-5">piezas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb8-6">    (pasajeros, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Observada'</span>),</span>
<span id="cb8-7">    (decomp_mul.trend, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Tendencia'</span>),</span>
<span id="cb8-8">    (decomp_mul.seasonal, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Estacionalidad'</span>),</span>
<span id="cb8-9">    (decomp_mul.resid, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Residuo'</span>),</span>
<span id="cb8-10">]</span>
<span id="cb8-11"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax, (serie, nombre) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(axes, piezas):</span>
<span id="cb8-12">    ax.plot(serie.index, serie.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb8-13">    ax.set_ylabel(nombre)</span>
<span id="cb8-14">axes[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb8-15">fig.suptitle(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Descomposición multiplicativa, periodo = 12 meses'</span>)</span>
<span id="cb8-16">plt.tight_layout()</span>
<span id="cb8-17">plt.show()</span>
<span id="cb8-18"></span>
<span id="cb8-19">factor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> decomp_mul.seasonal.groupby(decomp_mul.seasonal.index.month).first()</span>
<span id="cb8-20">factor.index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ene'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'feb'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mar'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'abr'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'may'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'jun'</span>,</span>
<span id="cb8-21">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'jul'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ago'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'sep'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'oct'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nov'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dic'</span>]</span>
<span id="cb8-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Factor estacional (multiplicativo):'</span>)</span>
<span id="cb8-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(factor.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string())</span>
<span id="cb8-24">tendencia_valida <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> decomp_mul.trend.dropna()</span>
<span id="cb8-25"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb8-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Tendencia en </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>tendencia_valida<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>index[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>strftime(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%Y-%m"</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: '</span></span>
<span id="cb8-27">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>tendencia_valida<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb8-28"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Tendencia en </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>tendencia_valida<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>index[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>strftime(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%Y-%m"</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: '</span></span>
<span id="cb8-29">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>tendencia_valida<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>iloc[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-6-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Factor estacional (multiplicativo):
ene    0.910
feb    0.884
mar    1.007
abr    0.976
may    0.981
jun    1.113
jul    1.227
ago    1.220
sep    1.060
oct    0.922
nov    0.801
dic    0.899

Tendencia en 1949-07: 126.8
Tendencia en 1960-06: 475.0</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-3" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-3">Cómo leer este resultado</h3>
<p>La tendencia sube de <strong>126.8</strong> en julio de 1949 a <strong>475.0</strong> en junio de 1960 (los extremos se pierden porque la media móvil de 12 meses necesita vecindario a ambos lados). El factor estacional de <strong>julio es 1.227</strong>: ese mes está un 23% por encima de la tendencia. <strong>Noviembre es 0.801</strong>: un 20% por debajo. Agosto (1.220) acompaña a julio; febrero (0.884) es el otro valle. El residuo oscila cerca de 1, que es el “cero” de una descomposición multiplicativa: un 1.03 significa un 3% no explicado por tendencia ni estación.</p>
<p>Esa radiografía ya te sirve para planear: si operas una aerolínea, julio no es un mes con “un poco más de tráfico”; es sistemáticamente un 23% más que el nivel de fondo.</p>
</section>
</section>
<section id="aditiva-o-multiplicativa" class="level2">
<h2 class="anchored" data-anchor-id="aditiva-o-multiplicativa">¿Aditiva o multiplicativa?</h2>
<p>Si la estación <strong>suma</strong> la misma cantidad cada año, el residuo aditivo debería verse estable. Si <strong>multiplica</strong>, el residuo aditivo se abre en abanico a medida que crece el nivel, y el multiplicativo se ve más parejo. Comparemos los dos residuos sobre la misma serie.</p>
<div id="b87f55eb" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:35.411349Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:35.411140Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:35.617524Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:35.616630Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb10-2">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(decomp_add.resid.index, decomp_add.resid.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb10-3">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb10-4">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Residuo aditivo'</span>)</span>
<span id="cb10-5">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pasajeros (miles)'</span>)</span>
<span id="cb10-6">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(decomp_mul.resid.index, decomp_mul.resid.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb10-7">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb10-8">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Residuo multiplicativo'</span>)</span>
<span id="cb10-9">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cociente'</span>)</span>
<span id="cb10-10"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> axes:</span>
<span id="cb10-11">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb10-12">plt.tight_layout()</span>
<span id="cb10-13">plt.show()</span>
<span id="cb10-14"></span>
<span id="cb10-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Desv. residual aditiva:         </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>decomp_add<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>resid<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>std()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb10-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Desv. residual multiplicativa:  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>decomp_mul<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>resid<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>std()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  (centrada en 1)'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-7-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Desv. residual aditiva:         19.34
Desv. residual multiplicativa:  0.033  (centrada en 1)</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-4" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-4">Cómo leer este resultado</h3>
<p>El residuo aditivo es amplio en los extremos y alcanza sus mayores valores en 1958–1960 (picos cercanos a 60 mil pasajeros), justo cuando los veranos son más altos: un pico estacional de tamaño fijo no alcanza a explicar veranos cada vez mayores. El multiplicativo no crece con el nivel: se mantiene dentro de ±10% alrededor de 1 (desviación <strong>0.033</strong>), y sus oscilaciones más amplias están, de hecho, al inicio (1950–1953), no al final. Las dos desviaciones no se comparan en la misma unidad —19.34 miles de pasajeros frente a un cociente—, así que la comparación es visual y modesta: el residuo aditivo conserva parte del patrón que depende del nivel; el multiplicativo, no. El argumento más fuerte sigue siendo la tabla anual, con una desviación que pasa de 13.7 a 77.7. Nos quedamos con la versión multiplicativa.</p>
</section>
</section>
<section id="estacionariedad-media-y-varianza-que-no-se-escapan" class="level2">
<h2 class="anchored" data-anchor-id="estacionariedad-media-y-varianza-que-no-se-escapan">Estacionariedad: media y varianza que no se escapan</h2>
<p>Muchos modelos de series —los autorregresivos (AR), los de medias móviles (MA) y su combinación ARMA— están derivados bajo <strong>estacionariedad débil</strong> (la familia ARIMA, que verás mencionada más adelante, primero diferencia la serie para llegar a esa condición):</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BE%7D(Y_t)=%5Cmu"> constante,</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BVar%7D(Y_t)=%5Csigma%5E2"> constante,</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BCov%7D(Y_t,%20Y_%7Bt-k%7D)=%5Cgamma(k)"> que depende solo del rezago, no de <img src="https://latex.codecogs.com/png.latex?t">.</li>
</ul>
<p>Si la media crece, “el promedio de la serie” no existe como ancla. Si la varianza crece, un error de 20 pasajeros no significa lo mismo en 1949 que en 1960. Antes de modelar, hay que <strong>ver</strong> si la serie se queda quieta y, si no, transformarla.</p>
<p>Una media móvil de 12 meses y una desviación móvil de 12 meses hacen visible lo que la tabla anual ya sugería.</p>
<div id="75636c9a" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:35.619987Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:35.619756Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:35.856953Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:35.856257Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">media_mov <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pasajeros.rolling(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>).mean()</span>
<span id="cb12-2">desv_mov <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pasajeros.rolling(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>).std()</span>
<span id="cb12-3"></span>
<span id="cb12-4">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>), sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb12-5">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(pasajeros.index, pasajeros.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>,</span>
<span id="cb12-6">             alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'serie'</span>)</span>
<span id="cb12-7">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(media_mov.index, media_mov.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>,</span>
<span id="cb12-8">             label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'media móvil (12 meses)'</span>)</span>
<span id="cb12-9">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].legend(loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'upper left'</span>)</span>
<span id="cb12-10">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pasajeros (miles)'</span>)</span>
<span id="cb12-11">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'La media no se queda quieta'</span>)</span>
<span id="cb12-12">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(desv_mov.index, desv_mov.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>)</span>
<span id="cb12-13">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'desv. móvil (12 meses)'</span>)</span>
<span id="cb12-14">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb12-15">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'La dispersión tampoco'</span>)</span>
<span id="cb12-16">plt.tight_layout()</span>
<span id="cb12-17">plt.show()</span>
<span id="cb12-18"></span>
<span id="cb12-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Media 1949: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pasajeros<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1949"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  |  '</span></span>
<span id="cb12-20">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'media 1960: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pasajeros<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1960"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb12-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Desv. 1949: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pasajeros<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1949"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>std()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   |  '</span></span>
<span id="cb12-22">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'desv. 1960: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pasajeros<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1960"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>std()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Media 1949: 126.7  |  media 1960: 476.2
Desv. 1949: 13.7   |  desv. 1960: 77.7</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-5" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-5">Cómo leer este resultado</h3>
<p>Las dos curvas móviles confirman lo que ya mostraba la tabla anual, ahora sin saltos entre años: la media pasa de <strong>126.7</strong> miles en 1949 a <strong>476.2</strong> en 1960, y la desviación, de <strong>13.7</strong> a <strong>77.7</strong>. Air Passengers <strong>no es estacionaria</strong>: ni la media ni la varianza son propiedades de “la serie”, sino de <strong>en qué año</strong> la mires. Un ARMA ajustado sobre esto interpretaría tendencia como persistencia y te daría pronósticos e intervalos engañosos.</p>
</section>
</section>
<section id="la-prueba-de-dickeyfuller-aumentada" class="level2">
<h2 class="anchored" data-anchor-id="la-prueba-de-dickeyfuller-aumentada">La prueba de Dickey–Fuller aumentada</h2>
<p>La inspección visual ya basta para no tratar esta serie como estacionaria. La prueba de Dickey–Fuller aumentada (ADF) pone números a esa intuición, y hay que leerla con cuidado.</p>
<p>La versión más simple de una <strong>raíz unitaria</strong> es el paseo aleatorio</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AY_t%20=%20Y_%7Bt-1%7D%20+%20%5Cvarepsilon_t,%0A"></p>
<p>donde cada choque se acumula y la serie no vuelve a una media. La ADF estima una regresión aumentada con rezagos de <img src="https://latex.codecogs.com/png.latex?%5CDelta%20Y_t"> para controlar autocorrelación. En la especificación con constante que usa <code>adfuller</code> por defecto:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CDelta%20Y_t%20=%20%5Calpha%20+%20%5Cgamma%20Y_%7Bt-1%7D%20+%20%5Csum_%7Bj=1%7D%5E%7Bp%7D%20%5Cdelta_j%20%5CDelta%20Y_%7Bt-j%7D%20+%20%5Cvarepsilon_t.%0A"></p>
<ul>
<li><strong>H0:</strong> <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20=%200"> (hay raíz unitaria; la serie no es estacionaria).</li>
<li><strong>H1:</strong> <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20%3C%200"> (la serie es estacionaria alrededor de un nivel).</li>
</ul>
<p>Un p-valor <strong>pequeño</strong> es evidencia <strong>en contra</strong> de H0, es decir, a favor de estacionariedad. Un p-valor <strong>grande</strong> no demuestra que haya raíz unitaria: solo dice que <strong>no hay evidencia suficiente para rechazarla</strong>. El número de rezagos <img src="https://latex.codecogs.com/png.latex?p"> lo elige el criterio de información de Akaike (AIC), que es la opción por defecto de <code>adfuller</code> (<code>autolag='AIC'</code>), dentro de un máximo que la función fija según el tamaño de la muestra.</p>
<p>Vamos a aplicar la prueba a la serie original y a transformaciones sucesivas: logaritmo (para la varianza), primera diferencia (para la tendencia) y diferencia estacional de 12 meses (para el ciclo anual).</p>
<div id="cccfa2cf" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:35.858832Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:35.858633Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:35.884309Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:35.883422Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> resumen_adf(serie, etiqueta):</span>
<span id="cb14-2">    serie <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(serie).dropna()</span>
<span id="cb14-3">    estadistico, p_valor, rezagos, n_obs, criticos, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> adfuller(serie, autolag<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'AIC'</span>)</span>
<span id="cb14-4">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>etiqueta<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb14-5">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  n = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n_obs<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   rezagos (AIC) = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>rezagos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb14-6">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  estadístico ADF = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>estadistico<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:7.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   crítico 5% = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>criticos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"5%"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb14-7">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  p-valor         = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>p_valor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4g}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb14-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> p_valor</span>
<span id="cb14-9"></span>
<span id="cb14-10"></span>
<span id="cb14-11">log_pax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.log(pasajeros)</span>
<span id="cb14-12">d1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pasajeros.diff()</span>
<span id="cb14-13">log_d1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> log_pax.diff()</span>
<span id="cb14-14">log_d1_est <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> log_d1.diff(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb14-15"></span>
<span id="cb14-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'H0: la serie tiene raíz unitaria (no estacionaria).</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb14-17">resumen_adf(pasajeros, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Original (regresión con constante)'</span>)</span>
<span id="cb14-18">_, p_ct, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> adfuller(pasajeros.dropna(), regression<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ct'</span>, autolag<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'AIC'</span>)</span>
<span id="cb14-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Original (constante y tendencia determinística)'</span>)</span>
<span id="cb14-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  p-valor         = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>p_ct<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4g}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb14-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb14-22">resumen_adf(log_pax, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Logaritmo'</span>)</span>
<span id="cb14-23">resumen_adf(d1, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Primera diferencia'</span>)</span>
<span id="cb14-24">resumen_adf(log_d1, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Log + primera diferencia'</span>)</span>
<span id="cb14-25">_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> resumen_adf(log_d1_est, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Log + 1ª diferencia + diferencia estacional (12)'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>H0: la serie tiene raíz unitaria (no estacionaria).

Original (regresión con constante)
  n = 130   rezagos (AIC) = 13
  estadístico ADF =   0.815   crítico 5% = -2.884
  p-valor         = 0.9919
Original (constante y tendencia determinística)
  p-valor         = 0.5457

Logaritmo
  n = 130   rezagos (AIC) = 13
  estadístico ADF =  -1.717   crítico 5% = -2.884
  p-valor         = 0.4224
Primera diferencia
  n = 130   rezagos (AIC) = 12
  estadístico ADF =  -2.829   crítico 5% = -2.884
  p-valor         = 0.05421
Log + primera diferencia
  n = 128   rezagos (AIC) = 14
  estadístico ADF =  -2.717   crítico 5% = -2.884
  p-valor         = 0.07112
Log + 1ª diferencia + diferencia estacional (12)
  n = 118   rezagos (AIC) = 12
  estadístico ADF =  -4.443   crítico 5% = -2.886
  p-valor         = 0.0002486</code></pre>
</div>
</div>
<section id="cómo-leer-estos-p-valores" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estos-p-valores">Cómo leer estos p-valores</h3>
<p>El p-valor de la serie original es <strong>0.9919</strong>: no hay evidencia contra H0. Eso <strong>no prueba</strong> que exista una raíz unitaria; la prueba simplemente no la rechaza. Aun permitiendo una tendencia determinística (<code>regression='ct'</code>), el p-valor sigue alto (<strong>0.5457</strong>). Junto con la media que pasa de 126.7 a 476.2, es razonable tratarla como no estacionaria.</p>
<p>El logaritmo deja el p-valor en <strong>0.4224</strong>: homogeneiza la varianza, pero la deriva permanece. La primera diferencia cae a <strong>0.05421</strong> y el log más la primera diferencia a <strong>0.07112</strong>. Ambos están <strong>en el borde</strong> de 0.05. Un umbral de significancia no es un interruptor: 0.054 y 0.049 no cuentan historias opuestas. Todavía queda el ciclo anual.</p>
<p>Después de logaritmo, primera diferencia <strong>y</strong> diferencia estacional de 12 meses, el p-valor es <strong>0.0002486</strong>. Ahora sí hay evidencia fuerte contra H0: la serie transformada es compatible con estacionariedad. Ese es el tratamiento clásico de esta serie (el de los “modelos de aerolínea”).</p>
<div id="ff1816ea" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:35.886380Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:35.886170Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:36.160879Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:36.160065Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>), sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb16-2">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(log_pax.index, log_pax.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb16-3">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Logaritmo: la varianza se homogeneiza, la tendencia permanece'</span>)</span>
<span id="cb16-4">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(log_d1.index, log_d1.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb16-5">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Log + primera diferencia: se va la deriva, queda la estación'</span>)</span>
<span id="cb16-6">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].plot(log_d1_est.index, log_d1_est.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb16-7">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb16-8">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Log + diferencia regular y estacional: ya no hay deriva evidente'</span>)</span>
<span id="cb16-9">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb16-10">plt.tight_layout()</span>
<span id="cb16-11">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-10-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="cómo-leer-esta-transformación" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-transformación">Cómo leer esta transformación</h3>
<p>El logaritmo aplana el abanico: los veranos grandes ya no dominan la escala. La primera diferencia quita la rampa, pero sigue viéndose un diente de sierra cada año. La diferencia estacional (<img src="https://latex.codecogs.com/png.latex?%5CDelta_%7B12%7D">) elimina ese diente de sierra: la serie resultante oscila alrededor de cero, que es exactamente el aspecto de algo que <strong>podrías</strong> modelar con un ARMA. Transformar no es un rito; es conseguir que media y varianza dejen de ser funciones del tiempo.</p>
</section>
<section id="antes-de-seguir-pregúntate" class="level3">
<h3 class="anchored" data-anchor-id="antes-de-seguir-pregúntate">Antes de seguir, pregúntate</h3>
<p>Si la media crece y la ADF no rechaza la raíz unitaria, ¿puedes leer un pico de la ACF como “la correlación real” de la serie, o estás mezclando <strong>tendencia</strong> con <strong>dependencia</strong>? En el siguiente bloque vas a ver las dos ACF: la de la serie cruda y la de la serie ya diferenciada. La diferencia entre ambas es precisamente esa mezcla.</p>
</section>
</section>
<section id="autocorrelación-la-serie-contra-sí-misma" class="level2">
<h2 class="anchored" data-anchor-id="autocorrelación-la-serie-contra-sí-misma">Autocorrelación: la serie contra sí misma</h2>
<p>La <strong>función de autocorrelación</strong> (ACF) en el rezago <img src="https://latex.codecogs.com/png.latex?k"> es la correlación de <img src="https://latex.codecogs.com/png.latex?Y_t"> con <img src="https://latex.codecogs.com/png.latex?Y_%7Bt-k%7D">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Crho(k)%20=%20%5Cfrac%7B%5Cmathrm%7BCov%7D(Y_t,%20Y_%7Bt-k%7D)%7D%7B%5Cmathrm%7BVar%7D(Y_t)%7D.%0A"></p>
<p>La <strong>PACF</strong> (autocorrelación parcial) mide lo mismo <strong>después de quitar</strong> el efecto lineal de los rezagos intermedios <img src="https://latex.codecogs.com/png.latex?1,%5Cldots,k-1">. Sirve para no contar dos veces la misma persistencia: si <img src="https://latex.codecogs.com/png.latex?Y_t"> se parece a <img src="https://latex.codecogs.com/png.latex?Y_%7Bt-1%7D"> y <img src="https://latex.codecogs.com/png.latex?Y_%7Bt-1%7D"> se parece a <img src="https://latex.codecogs.com/png.latex?Y_%7Bt-2%7D">, la ACF en el rezago 2 saldrá alta aunque no haya un canal directo de dos meses.</p>
<p>En una serie con tendencia, la ACF <strong>decae muy lento</strong> (todo se parece a todo porque todos están subiendo). En una serie con estacionalidad mensual, aparecen <strong>picos en 12, 24, 36, …</strong>. Esos picos son el ciclo anual escrito en lenguaje de rezagos.</p>
<div id="7852df1c" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:36.162724Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:36.162518Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:36.510032Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:36.509407Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>))</span>
<span id="cb17-2">plot_acf(pasajeros, lags<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">36</span>, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ACF — original'</span>)</span>
<span id="cb17-3">plot_pacf(pasajeros, lags<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">36</span>, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PACF — original'</span>)</span>
<span id="cb17-4">plot_acf(log_d1.dropna(), lags<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">36</span>, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ACF — log + diferencia'</span>)</span>
<span id="cb17-5">plot_pacf(log_d1.dropna(), lags<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">36</span>, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PACF — log + diferencia'</span>)</span>
<span id="cb17-6">plt.tight_layout()</span>
<span id="cb17-7">plt.show()</span>
<span id="cb17-8"></span>
<span id="cb17-9">acf_orig36 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> acf(pasajeros, nlags<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">36</span>, fft<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb17-10">acf_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> acf(log_d1.dropna(), nlags<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">36</span>, fft<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb17-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Original | lag 1 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acf_orig36[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   lag 12 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acf_orig36[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   '</span></span>
<span id="cb17-12">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'lag 24 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acf_orig36[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb17-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Log-diff | lag 1 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acf_d[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   lag 12 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acf_d[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   '</span></span>
<span id="cb17-14">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'lag 24 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acf_d[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-11-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Original | lag 1 = 0.948   lag 12 = 0.760   lag 24 = 0.532
Log-diff | lag 1 = 0.200   lag 12 = 0.841   lag 24 = 0.737</code></pre>
</div>
</div>
<section id="cómo-leer-estos-correlogramas" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-estos-correlogramas">Cómo leer estos correlogramas</h3>
<p>En la serie original, el rezago 1 vale <strong>0.948</strong>, el 12 vale <strong>0.760</strong> y el 24 todavía <strong>0.532</strong>. Esa cola larga no es “memoria de dos años”: es sobre todo la tendencia disfrazada de correlación, con ondulaciones en 12 y 24 que delatan la estación. La PACF original está dominada por el primer rezago (cerca de 0.95), lo que es coherente con una raíz unitaria; el otro pico claro es negativo, en el rezago 13, y es la huella del ciclo anual.</p>
<p>Después del log y la primera diferencia, el rezago 1 baja a <strong>0.200</strong> —ya no hay esa rampa— pero el rezago 12 <strong>sube a 0.841</strong>. Quitaste la tendencia y <strong>apareció</strong> el ciclo anual, que estaba tapado. Ese pico en el rezago estacional es exactamente lo que un modelo tiene que respetar: o con una diferencia <img src="https://latex.codecogs.com/png.latex?%5CDelta_%7B12%7D">, o con un factor estacional explícito, como el de Holt–Winters.</p>
</section>
</section>
<section id="un-modelo-sencillo-de-pronóstico-holtwinters" class="level2">
<h2 class="anchored" data-anchor-id="un-modelo-sencillo-de-pronóstico-holtwinters">Un modelo sencillo de pronóstico: Holt–Winters</h2>
<p>Holt–Winters (suavizamiento exponencial con tendencia y estación) es el modelo natural <strong>después</strong> de descomponer. Trabaja con tres estados que ya conoces:</p>
<ul>
<li>un <strong>nivel</strong> <img src="https://latex.codecogs.com/png.latex?%5Cell_t">,</li>
<li>una <strong>tendencia</strong> <img src="https://latex.codecogs.com/png.latex?b_t">,</li>
<li>un <strong>factor estacional</strong> <img src="https://latex.codecogs.com/png.latex?s_t"> de periodo <img src="https://latex.codecogs.com/png.latex?m=12">.</li>
</ul>
<p>Por ejemplo, con tendencia aditiva y estacionalidad multiplicativa, el pronóstico a <img src="https://latex.codecogs.com/png.latex?h%20%5Cle%20m"> pasos es</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7By%7D_%7Bt+h%7D%20=%20(%5Cell_t%20+%20h%20b_t)%5C,%20s_%7Bt+h-m%7D.%0A"></p>
<p>(para horizontes mayores que <img src="https://latex.codecogs.com/png.latex?m"> se reutiliza el factor del último ciclo observado). Nivel, pendiente y estación se actualizan cada mes con pesos de suavizamiento entre 0 y 1, que el ajuste estima con los datos: más peso al dato reciente, menos a un pasado lejano. Si un peso sale 0, ese estado queda fijo. No necesitas decidir “cuántos rezagos AR”; el modelo trabaja con las mismas piezas de la descomposición.</p>
<p>La familia <strong>SARIMA</strong> (ARIMA estacional) cuenta la misma historia en el lenguaje de diferencias y rezagos. El clásico de esta serie es el “modelo de aerolínea” <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BSARIMA%7D(0,1,1)(0,1,1)_%7B12%7D">. Aquí nos quedamos con Holt–Winters porque puedes leerlo con lo que ya viste: nivel, tendencia y factor mensual.</p>
</section>
<section id="validación-temporal-el-futuro-no-se-usa-para-elegir-el-modelo" class="level2">
<h2 class="anchored" data-anchor-id="validación-temporal-el-futuro-no-se-usa-para-elegir-el-modelo">Validación temporal: el futuro no se usa para elegir el modelo</h2>
<p>Hay cuatro combinaciones simples de tendencia y estacionalidad (<code>add</code> / <code>mul</code>). Elegir mirando el error de 1960 sería hacer trampa: 1960 es el examen. El protocolo es:</p>
<ol type="1">
<li>Reservar <strong>1960 entero</strong> (12 meses) como prueba, intocable.</li>
<li>Sobre <strong>1949-1959</strong>, hacer pronósticos a 12 meses con origen expansivo (tras 8, 9 y 10 años de historia). Eso son tres pliegues (<em>folds</em>), todos dentro del entrenamiento.</li>
<li>Quedarse con la especificación de menor MAE medio en esos pliegues. El MAE (error absoluto medio) es el promedio de <img src="https://latex.codecogs.com/png.latex?%7Cy_t%20-%20%5Chat%7By%7D_t%7C">, en miles de pasajeros; más adelante reportamos también el RMSE (raíz del error cuadrático medio, que castiga más los errores grandes) y el MAPE (error porcentual absoluto medio: el error absoluto como porcentaje del valor real, promediado).</li>
<li>Reajustar esa especificación con todo 1949-1959 y <strong>entonces</strong> evaluar 1960.</li>
</ol>
<p>Como punto de referencia, dos pronósticos ingenuos: predecir siempre la media del entrenamiento, y copiar el mismo mes del año anterior (<strong>ingenuo estacional</strong>, <em>seasonal naive</em>; en las salidas aparece como <code>naive estacional</code>). Si Holt–Winters no gana a “lo mismo que el año pasado”, no vale la pena.</p>
<div id="667716e2" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:36.511851Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:36.511650Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:37.593826Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:37.593048Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1">n_prueba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span></span>
<span id="cb19-2">train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pasajeros.iloc[:<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>n_prueba]</span>
<span id="cb19-3">test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pasajeros.iloc[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>n_prueba:]</span>
<span id="cb19-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Entrenamiento: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>train<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>index<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>strftime(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%Y-%m"</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> → '</span></span>
<span id="cb19-5">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>train<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>index<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>strftime(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%Y-%m"</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(train)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> meses)'</span>)</span>
<span id="cb19-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Prueba:        </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>index<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>strftime(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%Y-%m"</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> → '</span></span>
<span id="cb19-7">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>index<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>strftime(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%Y-%m"</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(test)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> meses)'</span>)</span>
<span id="cb19-8"></span>
<span id="cb19-9">naive_media <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(np.full(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(test), train.mean()), index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test.index)</span>
<span id="cb19-10">naive_estacional <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(train.iloc[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>:].to_numpy(), index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test.index)</span>
<span id="cb19-11"></span>
<span id="cb19-12"></span>
<span id="cb19-13"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> mae(y_real, y_pred):</span>
<span id="cb19-14">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.mean(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(np.asarray(y_real) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> np.asarray(y_pred)))</span>
<span id="cb19-15"></span>
<span id="cb19-16"></span>
<span id="cb19-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> rmse(y_real, y_pred):</span>
<span id="cb19-18">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.sqrt(np.mean((np.asarray(y_real) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> np.asarray(y_pred)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb19-19"></span>
<span id="cb19-20"></span>
<span id="cb19-21"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> mape(y_real, y_pred):</span>
<span id="cb19-22">    y_real <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(y_real)</span>
<span id="cb19-23">    y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(y_pred)</span>
<span id="cb19-24">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.mean(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(y_real <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y_pred) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> y_real)</span>
<span id="cb19-25"></span>
<span id="cb19-26"></span>
<span id="cb19-27">horizonte <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span></span>
<span id="cb19-28">min_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">96</span></span>
<span id="cb19-29">origenes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(min_train, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(train) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> horizonte <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>))</span>
<span id="cb19-30"></span>
<span id="cb19-31"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">Validación temporal (MAE medio a 12 meses, solo entrenamiento):'</span>)</span>
<span id="cb19-32">resultados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb19-33"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> tendencia <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'add'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mul'</span>]:</span>
<span id="cb19-34">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> estacional <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'add'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mul'</span>]:</span>
<span id="cb19-35">        errores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb19-36">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> origen <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> origenes:</span>
<span id="cb19-37">            modelo_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ExponentialSmoothing(</span>
<span id="cb19-38">                train.iloc[:origen],</span>
<span id="cb19-39">                trend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>tendencia,</span>
<span id="cb19-40">                seasonal<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>estacional,</span>
<span id="cb19-41">                seasonal_periods<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>,</span>
<span id="cb19-42">            ).fit()</span>
<span id="cb19-43">            pred_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_cv.forecast(horizonte)</span>
<span id="cb19-44">            errores.append(mae(train.iloc[origen:origen <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> horizonte], pred_cv))</span>
<span id="cb19-45">        mae_medio <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.mean(errores))</span>
<span id="cb19-46">        resultados.append((mae_medio, tendencia, estacional))</span>
<span id="cb19-47">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  tendencia=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>tendencia<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  estacional=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>estacional<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  '</span></span>
<span id="cb19-48">              <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'MAE medio = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mae_medio<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   por pliegue = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(errores, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>tolist()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb19-49"></span>
<span id="cb19-50">mejor_mae, mejor_tendencia, mejor_estacional <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(resultados)</span>
<span id="cb19-51"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">Elegida: tendencia=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_tendencia<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, estacional=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_estacional<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> '</span></span>
<span id="cb19-52">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'(MAE de validación = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_mae<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb19-53"></span>
<span id="cb19-54">modelo_hw <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ExponentialSmoothing(</span>
<span id="cb19-55">    train,</span>
<span id="cb19-56">    trend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mejor_tendencia,</span>
<span id="cb19-57">    seasonal<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mejor_estacional,</span>
<span id="cb19-58">    seasonal_periods<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>,</span>
<span id="cb19-59">).fit()</span>
<span id="cb19-60">pred_hw <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_hw.forecast(n_prueba)</span>
<span id="cb19-61"></span>
<span id="cb19-62"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">Error en el tramo de PRUEBA (1960), no usado para elegir:'</span>)</span>
<span id="cb19-63"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  MAE  media global      = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mae(test, naive_media)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb19-64"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  MAE  naive estacional  = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mae(test, naive_estacional)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb19-65"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  MAE  Holt-Winters      = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mae(test, pred_hw)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb19-66"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  RMSE Holt-Winters      = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>rmse(test, pred_hw)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb19-67"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  MAPE Holt-Winters      = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mape(test, pred_hw)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%'</span>)</span>
<span id="cb19-68"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  MAPE naive estacional  = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mape(test, naive_estacional)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%'</span>)</span>
<span id="cb19-69"></span>
<span id="cb19-70">comparacion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb19-71">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'real'</span>: test.astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>),</span>
<span id="cb19-72">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'holt_winters'</span>: pred_hw.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb19-73">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'naive_estacional'</span>: naive_estacional.astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>),</span>
<span id="cb19-74">})</span>
<span id="cb19-75"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb19-76"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(comparacion.to_string())</span>
<span id="cb19-77"></span>
<span id="cb19-78">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb19-79">ax.plot(train.index, train.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'entrenamiento'</span>)</span>
<span id="cb19-80">ax.plot(test.index, test.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'black'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'prueba (real)'</span>)</span>
<span id="cb19-81">ax.plot(pred_hw.index, pred_hw.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>,</span>
<span id="cb19-82">        label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Holt-Winters'</span>)</span>
<span id="cb19-83">ax.axvline(test.index[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb19-84">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb19-85">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pasajeros (miles)'</span>)</span>
<span id="cb19-86">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Pronóstico de 1960 entrenado solo con 1949-1959'</span>)</span>
<span id="cb19-87">ax.legend(loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'upper left'</span>)</span>
<span id="cb19-88">plt.tight_layout()</span>
<span id="cb19-89">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Entrenamiento: 1949-01 → 1959-12  (132 meses)
Prueba:        1960-01 → 1960-12  (12 meses)

Validación temporal (MAE medio a 12 meses, solo entrenamiento):
  tendencia=add  estacional=add  MAE medio = 19.37   por pliegue = [12.66, 24.62, 20.82]
  tendencia=add  estacional=mul  MAE medio = 16.78   por pliegue = [14.57, 15.56, 20.22]
  tendencia=mul  estacional=add  MAE medio = 20.23   por pliegue = [11.12, 37.36, 12.22]
  tendencia=mul  estacional=mul  MAE medio = 19.48   por pliegue = [8.0, 39.05, 11.38]

Elegida: tendencia=add, estacional=mul (MAE de validación = 16.78)

Error en el tramo de PRUEBA (1960), no usado para elegir:
  MAE  media global      = 213.67
  MAE  naive estacional  = 47.83
  MAE  Holt-Winters      = 10.30
  RMSE Holt-Winters      = 15.81
  MAPE Holt-Winters      = 2.21%
  MAPE naive estacional  = 9.99%

            real  holt_winters  naive_estacional
1960-01-01   417         417.3               360
1960-02-01   391         394.1               342
1960-03-01   419         462.4               406
1960-04-01   461         448.6               396
1960-05-01   472         471.9               420
1960-06-01   535         539.9               472
1960-07-01   622         623.8               548
1960-08-01   606         631.2               559
1960-09-01   508         515.6               463
1960-10-01   461         449.9               407
1960-11-01   390         394.3               362
1960-12-01   432         422.5               405</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-12-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-el-pronóstico" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-el-pronóstico">Cómo leer el pronóstico</h3>
<p>La validación temporal, <strong>sin mirar 1960</strong>, elige tendencia aditiva y estacionalidad multiplicativa: MAE medio de <strong>16.78</strong> frente a 19.37, 20.23 y 19.48 de las otras tres. Gana en promedio, no en cada pliegue: en los orígenes de 1957 y 1959 la variante multiplicativa-multiplicativa tiene menor error (<strong>8.0</strong> y <strong>11.38</strong>, frente a <strong>14.57</strong> y <strong>20.22</strong> de la elegida), y la ventaja de la elegida viene sobre todo del pliegue de 1958, donde las dos variantes de tendencia multiplicativa se disparan (<strong>37.36</strong> y <strong>39.05</strong>, frente a <strong>15.56</strong>). Con tres pliegues, la elección es razonable, no concluyente. El óptimo no está en un borde de un rango continuo: es una de cuatro especificaciones.</p>
<p>En el año reservado, Holt–Winters obtiene <strong>MAE = 10.30</strong>, <strong>RMSE = 15.81</strong> y <strong>MAPE = 2.21%</strong>. El ingenuo estacional (copiar 1959) llega a un MAE de <strong>47.83</strong> y un MAPE de <strong>9.99%</strong>. La media global, que ignora tiempo y estación, queda en MAE <strong>213.67</strong>: un recordatorio de lo que se pierde al tratar la serie como un conjunto de números sin orden.</p>
<p>El mayor desajuste es <strong>marzo de 1960</strong>: real 419 frente a 462.4. Julio, el pico, sale casi exacto (622 frente a 623.8). Un MAPE del 2.21% con un horizonte de un año, con el ciclo y la rampa incluidos, es un pronóstico usable. Y lo importante del protocolo: <strong>1960 no participó en la elección del modelo</strong>.</p>
</section>
</section>
<section id="de-aviones-a-envíos-un-caso-logístico" class="level2">
<h2 class="anchored" data-anchor-id="de-aviones-a-envíos-un-caso-logístico">De aviones a envíos: un caso logístico</h2>
<p>El mismo trío —tendencia, estación, ruido— aparece en operación. Simulamos <strong>84 meses</strong> de demanda de un operador de envíos (enero 2018 a diciembre 2024), con semilla fija. La regla oculta, que en la práctica no verías, es:</p>
<ul>
<li>una <strong>tendencia</strong> creciente (el volumen del negocio se expande);</li>
<li>un <strong>ciclo anual</strong> con picos de temporada: noviembre y diciembre (fin de año), un pico menor en mayo (Día de la Madre) y un valle en enero (contracción tras la temporada alta);</li>
<li>ruido multiplicativo pequeño.</li>
</ul>
<p>El objetivo no es redescubrir la receta. Es repetir el flujo —descomponer, preguntarse por la estacionariedad, pronosticar respetando el tiempo— y leer el resultado como <strong>capacidad que hay que tener lista</strong> antes del pico.</p>
<div id="32601785" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:37.596737Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:37.596362Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:37.727991Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:37.727052Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">84</span></span>
<span id="cb21-2">idx_envios <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.date_range(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'2018-01-01'</span>, periods<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n, freq<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MS'</span>)</span>
<span id="cb21-3">t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(n)</span>
<span id="cb21-4">factor_mes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([</span>
<span id="cb21-5">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.82</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.88</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.96</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.94</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.18</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.06</span>,</span>
<span id="cb21-6">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.98</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.97</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.02</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.08</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.28</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.42</span>,</span>
<span id="cb21-7">])</span>
<span id="cb21-8">estacional <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> factor_mes[idx_envios.month <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb21-9">tendencia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8500</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">55</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb21-10">rng_envios <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb21-11">ruido <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng_envios.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.035</span>, n)</span>
<span id="cb21-12">envios <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(</span>
<span id="cb21-13">    tendencia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> estacional <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> ruido),</span>
<span id="cb21-14">    index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>idx_envios,</span>
<span id="cb21-15">    name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'envios'</span>,</span>
<span id="cb21-16">).asfreq(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MS'</span>)</span>
<span id="cb21-17"></span>
<span id="cb21-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(envios)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> meses | </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>envios<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>index<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>date()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> → </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>envios<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>index<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>date()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb21-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'mínimo = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>envios<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   máximo = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>envios<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb21-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'media 2018 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>envios<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2018"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  |  '</span></span>
<span id="cb21-21">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'media 2024 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>envios<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2024"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb21-22"></span>
<span id="cb21-23">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb21-24">ax.plot(envios.index, envios.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb21-25">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb21-26">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'envíos mensuales'</span>)</span>
<span id="cb21-27">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Demanda mensual de envíos, 2018-2024'</span>)</span>
<span id="cb21-28">plt.tight_layout()</span>
<span id="cb21-29">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>84 meses | 2018-01-01 → 2024-12-01
mínimo = 6777   máximo = 22334
media 2018 = 9295  |  media 2024 = 15845</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-13-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-este-resultado-6" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-6">Cómo leer este resultado</h3>
<p>Son <strong>84 meses</strong>. El volumen medio pasa de <strong>9295</strong> envíos en 2018 a <strong>15845</strong> en 2024, con un mínimo de <strong>6777</strong> y un máximo de <strong>22334</strong>. La forma recuerda a la de Air Passengers: rampa hacia arriba y dientes de sierra cada vez más altos. Si operas la red, esa gráfica ya te dice que <strong>el diciembre de este año no se parece al de hace seis</strong>: planear con el promedio histórico te deja sin capacidad suficiente en temporada alta.</p>
<div id="55a4bd45" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:37.729845Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:37.729624Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:38.065263Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:38.064054Z&quot;}}" data-execution_count="13">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1">decomp_envios <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> seasonal_decompose(envios, model<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'multiplicative'</span>, period<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb23-2">factor_e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> decomp_envios.seasonal.groupby(decomp_envios.seasonal.index.month).first()</span>
<span id="cb23-3">factor_e.index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ene'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'feb'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mar'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'abr'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'may'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'jun'</span>,</span>
<span id="cb23-4">                  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'jul'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ago'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'sep'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'oct'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nov'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dic'</span>]</span>
<span id="cb23-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Factor estacional estimado:'</span>)</span>
<span id="cb23-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(factor_e.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string())</span>
<span id="cb23-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb23-8">resumen_adf(envios, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Envíos original'</span>)</span>
<span id="cb23-9">resumen_adf(np.log(envios).diff(), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Envíos log + primera diferencia'</span>)</span>
<span id="cb23-10">resumen_adf(np.log(envios).diff().diff(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>),</span>
<span id="cb23-11">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Envíos log + diferencia regular y estacional'</span>)</span>
<span id="cb23-12"></span>
<span id="cb23-13">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>), sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb23-14">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(envios.index, envios.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'demanda'</span>)</span>
<span id="cb23-15">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(decomp_envios.trend.index, decomp_envios.trend.values,</span>
<span id="cb23-16">             color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tendencia'</span>)</span>
<span id="cb23-17">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].legend(loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'upper left'</span>)</span>
<span id="cb23-18">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Demanda y tendencia'</span>)</span>
<span id="cb23-19">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(decomp_envios.seasonal.index, decomp_envios.seasonal.values,</span>
<span id="cb23-20">             color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb23-21">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Estacionalidad anual (picos de temporada)'</span>)</span>
<span id="cb23-22">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].plot(decomp_envios.resid.index, decomp_envios.resid.values,</span>
<span id="cb23-23">             color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>)</span>
<span id="cb23-24">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb23-25">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Residuo'</span>)</span>
<span id="cb23-26">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb23-27">plt.tight_layout()</span>
<span id="cb23-28">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Factor estacional estimado:
ene    0.797
feb    0.850
mar    0.922
abr    0.901
may    1.100
jun    1.015
jul    0.911
ago    0.931
sep    0.964
oct    1.042
nov    1.226
dic    1.341

Envíos original
  n = 72   rezagos (AIC) = 11
  estadístico ADF =   2.583   crítico 5% = -2.903
  p-valor         = 0.9991
Envíos log + primera diferencia
  n = 72   rezagos (AIC) = 10
  estadístico ADF = -18.123   crítico 5% = -2.903
  p-valor         = 2.518e-30
Envíos log + diferencia regular y estacional
  n = 59   rezagos (AIC) = 11
  estadístico ADF =  -2.226   crítico 5% = -2.912
  p-valor         = 0.1969</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-14-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="cómo-leer-esta-descomposición" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-descomposición">Cómo leer esta descomposición</h3>
<p>El factor de <strong>diciembre es 1.341</strong> (un 34% por encima de la tendencia) y el de <strong>noviembre, 1.226</strong>. Mayo, el otro pico operativo, queda en <strong>1.100</strong>. Enero cae a <strong>0.797</strong>: después de temporada alta, el volumen se contrae. La ADF de la serie original da p-valor <strong>0.9991</strong>: no hay evidencia contra la raíz unitaria. Tras logaritmo y primera diferencia, el p-valor es <strong>2.518e-30</strong>: la prueba rechaza con holgura la raíz unitaria. Eso no convierte la serie en estacionaria sin más: el patrón mensual sigue ahí (cada mes tiene su propia media), solo que ahora es un patrón fijo que un factor estacional explícito, como el de Holt–Winters, puede absorber.</p>
<p>Con la diferencia estacional adicional, el p-valor sube a <strong>0.1969</strong>. No leas ese número como prueba de sobre-diferenciación: la ADF no está diseñada para detectarla y, con 59 observaciones y 11 rezagos, tiene poca potencia. Lo que sí sabemos —porque simulamos la serie— es que la estación de los envíos es <strong>fija</strong>: cada diciembre multiplica la tendencia por el mismo factor. En ese caso <img src="https://latex.codecogs.com/png.latex?%5CDelta_%7B12%7D"> sobra: elimina un patrón que no cambia y, a cambio, introduce una dependencia artificial en la serie (eso es la sobre-diferenciación). En Air Passengers, en cambio, <img src="https://latex.codecogs.com/png.latex?%5CDelta_%7B12%7D"> es el tratamiento clásico, y ahí la ADF solo rechazó con claridad después de aplicarla. La prueba y el gráfico orientan, pero no sustituyen el razonamiento sobre de dónde viene el patrón.</p>
<p>Falta el pronóstico. Repetimos la validación temporal de Air Passengers: reservamos 2024 como prueba y elegimos la especificación de Holt–Winters solo con 2018-2023.</p>
<div id="1489f0a0" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:38.067249Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:38.067037Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:38.819318Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:38.818475Z&quot;}}" data-execution_count="14">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb25" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb25-1">n_prueba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span></span>
<span id="cb25-2">train_e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> envios.iloc[:<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>n_prueba]</span>
<span id="cb25-3">test_e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> envios.iloc[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>n_prueba:]</span>
<span id="cb25-4">naive_e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(train_e.iloc[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>:].to_numpy(), index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_e.index)</span>
<span id="cb25-5"></span>
<span id="cb25-6">horizonte <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span></span>
<span id="cb25-7">min_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">48</span></span>
<span id="cb25-8">origenes_e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(min_train, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(train_e) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> horizonte <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>))</span>
<span id="cb25-9">resultados_e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb25-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Validación temporal en envíos (solo entrenamiento):'</span>)</span>
<span id="cb25-11"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> tendencia <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'add'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mul'</span>]:</span>
<span id="cb25-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> estacional <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'add'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mul'</span>]:</span>
<span id="cb25-13">        errores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb25-14">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> origen <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> origenes_e:</span>
<span id="cb25-15">            modelo_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ExponentialSmoothing(</span>
<span id="cb25-16">                train_e.iloc[:origen],</span>
<span id="cb25-17">                trend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>tendencia,</span>
<span id="cb25-18">                seasonal<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>estacional,</span>
<span id="cb25-19">                seasonal_periods<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>,</span>
<span id="cb25-20">            ).fit()</span>
<span id="cb25-21">            pred_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_cv.forecast(horizonte)</span>
<span id="cb25-22">            errores.append(mae(train_e.iloc[origen:origen <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> horizonte], pred_cv))</span>
<span id="cb25-23">        mae_medio <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.mean(errores))</span>
<span id="cb25-24">        resultados_e.append((mae_medio, tendencia, estacional))</span>
<span id="cb25-25">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  tendencia=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>tendencia<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  estacional=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>estacional<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  '</span></span>
<span id="cb25-26">              <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'MAE medio = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mae_medio<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb25-27"></span>
<span id="cb25-28">mejor_mae_e, mejor_t_e, mejor_s_e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(resultados_e)</span>
<span id="cb25-29"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">Elegida: tendencia=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_t_e<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, estacional=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_s_e<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> '</span></span>
<span id="cb25-30">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'(MAE de validación = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mejor_mae_e<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb25-31"></span>
<span id="cb25-32">modelo_e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ExponentialSmoothing(</span>
<span id="cb25-33">    train_e, trend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mejor_t_e, seasonal<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mejor_s_e, seasonal_periods<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span></span>
<span id="cb25-34">).fit()</span>
<span id="cb25-35">pred_e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_e.forecast(n_prueba)</span>
<span id="cb25-36"></span>
<span id="cb25-37"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">Error en prueba (2024):'</span>)</span>
<span id="cb25-38"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  MAE  naive estacional = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mae(test_e, naive_e)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb25-39"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  MAE  Holt-Winters     = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mae(test_e, pred_e)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb25-40"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  RMSE Holt-Winters     = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>rmse(test_e, pred_e)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb25-41"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  MAPE Holt-Winters     = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mape(test_e, pred_e)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%'</span>)</span>
<span id="cb25-42"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  Diciembre 2024 real = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_e<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2024-12-01"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  '</span></span>
<span id="cb25-43">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'pronosticado = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pred_e<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2024-12-01"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb25-44"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  Mayo 2024 real      = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_e<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2024-05-01"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  '</span></span>
<span id="cb25-45">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'pronosticado = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pred_e<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2024-05-01"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb25-46"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'  Meses con pronóstico por debajo del real: '</span></span>
<span id="cb25-47">      <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>((test_e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> pred_e).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> de </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(test_e)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb25-48"></span>
<span id="cb25-49">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb25-50">ax.plot(train_e.index, train_e.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'entrenamiento'</span>)</span>
<span id="cb25-51">ax.plot(test_e.index, test_e.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'black'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'prueba (real)'</span>)</span>
<span id="cb25-52">ax.plot(pred_e.index, pred_e.values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'firebrick'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>,</span>
<span id="cb25-53">        label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Holt-Winters'</span>)</span>
<span id="cb25-54">ax.axvline(test_e.index[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray'</span>, ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">':'</span>)</span>
<span id="cb25-55">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo'</span>)</span>
<span id="cb25-56">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'envíos mensuales'</span>)</span>
<span id="cb25-57">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Pronóstico de demanda 2024 entrenado solo con 2018-2023'</span>)</span>
<span id="cb25-58">ax.legend(loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'upper left'</span>)</span>
<span id="cb25-59">plt.tight_layout()</span>
<span id="cb25-60">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Validación temporal en envíos (solo entrenamiento):
  tendencia=add  estacional=add  MAE medio = 615.0
  tendencia=add  estacional=mul  MAE medio = 441.6
  tendencia=mul  estacional=add  MAE medio = 624.0
  tendencia=mul  estacional=mul  MAE medio = 540.7

Elegida: tendencia=add, estacional=mul (MAE de validación = 441.6)

Error en prueba (2024):
  MAE  naive estacional = 1851.9
  MAE  Holt-Winters     = 778.6
  RMSE Holt-Winters     = 954.5
  MAPE Holt-Winters     = 4.86%
  Diciembre 2024 real = 22334  pronosticado = 20803
  Mayo 2024 real      = 17255  pronosticado = 16479
  Meses con pronóstico por debajo del real: 10 de 12</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/index_files/figure-html/cell-15-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="cómo-leer-el-valor-práctico" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-el-valor-práctico">Cómo leer el valor práctico</h3>
<p>Otra vez la especificación se elige <strong>sin ver 2024</strong>, aquí con solo dos pliegues (orígenes tras 4 y 5 años de historia): gana tendencia aditiva y estacionalidad multiplicativa, con MAE de validación <strong>441.6</strong>. En prueba, Holt–Winters baja el MAE de <strong>1851.9</strong> (ingenuo estacional) a <strong>778.6</strong> y deja un MAPE de <strong>4.86%</strong> (RMSE <strong>954.5</strong>). Diciembre, el mes más exigente para la operación, sale <strong>22334</strong> real frente a <strong>20803</strong> pronosticado: el modelo anticipa el orden de magnitud del pico, aunque se queda corto. Mayo, el segundo pico, es <strong>17255</strong> real frente a <strong>16479</strong> pronosticado.</p>
<p>Ese faltante no es casual: el pronóstico queda por debajo del valor real en <strong>10 de 12</strong> meses. La demanda simulada crece con aceleración (su tendencia tiene un término cuadrático) y la tendencia de este Holt–Winters es lineal. Es un sesgo que conviene vigilar: si la demanda real acelera, el pronóstico tiende a quedarse corto justo en temporada alta.</p>
<p>Eso es lo que justifica el flujo. Con meses de antelación puedes dimensionar turnos, cupo de última milla y inventario de empaque para un diciembre de al menos 21 mil envíos, no para el promedio del año, y con un margen para el sesgo hacia abajo que acabas de ver. Un faltante de unos 1500 envíos en el pico (22334 frente a 20803) es mucho más manejable que descubrir en diciembre que el volumen superó la capacidad.</p>
</section>
</section>
<section id="errores-comunes-en-series-de-tiempo" class="level2">
<h2 class="anchored" data-anchor-id="errores-comunes-en-series-de-tiempo">Errores comunes en series de tiempo</h2>
<ol type="1">
<li><strong>Barajar las observaciones o hacer un corte aleatorio.</strong> Rompes el orden y filtras el futuro. El único corte honesto es temporal.</li>
<li><strong>Leer un p-valor grande de la ADF como prueba de raíz unitaria.</strong> H0 no se “acepta”; simplemente no se rechaza. Combínalo con el gráfico de media y varianza.</li>
<li><strong>Tratar 0.049 y 0.054 como veredictos opuestos.</strong> La primera diferencia de Air Passengers quedó en el borde: el ciclo anual todavía estaba ahí.</li>
<li><strong>Diferenciar por inercia.</strong> En los envíos, cuya estación es fija por construcción, <img src="https://latex.codecogs.com/png.latex?%5CDelta_%7B12%7D"> sobraba. La transformación se justifica con la serie que tienes y con el origen de su patrón, no con una receta.</li>
<li><strong>Elegir el modelo mirando el error de prueba.</strong> La prueba se reserva para el reporte. La especificación se decide en validación temporal sobre el pasado.</li>
<li><strong>Interpretar la ACF de una serie con tendencia como memoria pura.</strong> La cola larga de Air Passengers era la rampa, no un AR de orden 24.</li>
<li><strong>Evaluar solo contra la media global.</strong> El ingenuo estacional es el punto de referencia mínimo; si no lo ganas, el modelo no aporta.</li>
<li><strong>Confundir descomposición con pronóstico.</strong> <code>seasonal_decompose</code> explica el pasado; Holt–Winters (o SARIMA) proyecta el futuro.</li>
</ol>
</section>
<section id="lo-que-debes-llevarte" class="level2">
<h2 class="anchored" data-anchor-id="lo-que-debes-llevarte">Lo que debes llevarte</h2>
<p>La cadena completa es:</p>
<pre class="text"><code>serie ordenada en el tiempo
→ no barajar ni partir al azar
→ descomponer: tendencia, estacionalidad, residuo
→ preguntarse si es estacionaria (gráfico + ADF)
→ transformar (log, diferencias) solo lo necesario
→ leer ACF / PACF, incluidos los rezagos estacionales
→ elegir el modelo con validación TEMPORAL
→ pronosticar el tramo futuro y reportar el error solo ahí</code></pre>
<p>En Air Passengers, ese protocolo eligió Holt–Winters aditivo-multiplicativo y entregó un MAPE del <strong>2.21%</strong> en 1960, frente al <strong>9.99%</strong> de copiar el año anterior (ingenuo estacional). En envíos, el mismo flujo redujo el MAE de prueba de <strong>1851.9</strong> (ingenuo estacional) a <strong>778.6</strong> y anticipó el orden de magnitud del pico de diciembre (<strong>20803</strong> pronosticado frente a <strong>22334</strong> real).</p>
<p>La lección de fondo no es el nombre del modelo. Es que <strong>el tiempo es estructura</strong>, no un índice más.</p>
</section>
<section id="qué-sigue" class="level2">
<h2 class="anchored" data-anchor-id="qué-sigue">¿Qué sigue?</h2>
<p>Aquí la dependencia era de una sola serie consigo misma: hoy con ayer, este diciembre con el pasado. Hay otra forma, igual de frecuente y distinta en el modelo: <strong>datos longitudinales</strong> (o de panel). Varias mediciones del <strong>mismo individuo</strong> —un cliente, un repartidor, una ruta— a lo largo del tiempo. Las observaciones de una misma unidad se parecen entre sí, aunque las unidades sean independientes.</p>
<p>Eso pide otra familia de herramientas: efectos aleatorios, modelos mixtos, el cuidado de no tratar 10 observaciones de 50 personas como si fueran 500 independientes. Es el próximo artículo de la serie, y el otro lado de los datos dependientes.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>series-temporales</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/avanzado/15-series-temporales/</guid>
  <pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Análisis Avanzado de Datos — 15. Datos longitudinales</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/avanzado/16-datos-longitudinales/</link>
  <description><![CDATA[ 




<section id="análisis-avanzado-de-datos-15.-datos-longitudinales" class="level1">
<h1>Análisis Avanzado de Datos — 15. Datos longitudinales</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado convierte datos en decisiones. Científico de Datos, Arquitecto de IA y asesor tecnológico con más de 20 años de experiencia en analítica avanzada, machine learning, Big Data e IoT. Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), asesora a entidades gubernamentales y empresas privadas en Colombia y es referente en analítica y normatividad para los sectores postal y logístico del país. Una serie pensada para ir de la teoría a la práctica, con ejemplos concretos en cada paso.</p>
<p>📌 <em>Parte de la serie <strong>Análisis Avanzado de Datos</strong>.</em></p>
</section>
<section id="el-problema-una-persona-muchas-mediciones" class="level2">
<h2 class="anchored" data-anchor-id="el-problema-una-persona-muchas-mediciones">El problema: una persona, muchas mediciones</h2>
<p>En el artículo anterior la dependencia venía del orden temporal de una sola serie: hoy se parece a ayer. Aquí aparece el otro lado de los datos dependientes. Imagina que registras varias entregas de cada repartidor. Cada fila parece una observación nueva, pero las filas de una misma persona comparten experiencia, ritmo, conocimiento de la zona y forma de trabajar. Esa historia común crea <strong>correlación intraindividual</strong>.</p>
<p>Una regresión clásica supone que, una vez incluidas las variables explicativas, sus errores son independientes. Aquí esa suposición se rompe: dos entregas del mismo repartidor se parecen más que dos entregas elegidas al azar. Si ignoras quién hizo cada entrega, puedes confundir muchas filas con mucha evidencia independiente.</p>
</section>
<section id="objetivos-de-aprendizaje" class="level2">
<h2 class="anchored" data-anchor-id="objetivos-de-aprendizaje">Objetivos de aprendizaje</h2>
<p>Al terminar este notebook vas a ser capaz de:</p>
<ul>
<li><strong>Reconocer</strong> mediciones repetidas y explicar por qué generan dependencia.</li>
<li><strong>Detectar</strong> la variabilidad sistemática entre individuos con tablas y gráficos.</li>
<li><strong>Explicar</strong> por qué una regresión <em>pooled</em> (todas las filas apiladas en una sola regresión, sin identificar al individuo) puede distorsionar la incertidumbre y el efecto estimado.</li>
<li><strong>Distinguir</strong> efectos fijos de efectos aleatorios.</li>
<li><strong>Ajustar e interpretar</strong> un modelo mixto con intercepto aleatorio usando <code>MixedLM</code>.</li>
<li><strong>Comparar</strong> el modelo ingenuo y el mixto sin convertir asociación en causalidad.</li>
</ul>
</section>
<section id="preparación-del-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparación-del-entorno">Preparación del entorno</h2>
<p>Usaremos datos sintéticos para conocer la regla que los generó y comprobar si cada modelo logra recuperarla. En datos reales esa regla nunca está disponible. La semilla fija hace reproducible cada número y cada figura.</p>
<div id="220bb7a7" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:29.792450Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:29.792261Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.208806Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.207174Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> warnings</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> statsmodels.api <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sm</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> statsmodels.formula.api <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> smf</span>
<span id="cb1-8"></span>
<span id="cb1-9">warnings.filterwarnings(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ignore'</span>, category<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">UserWarning</span>, module<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'statsmodels'</span>)</span>
<span id="cb1-10">SEMILLA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2169</span></span>
<span id="cb1-11">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(SEMILLA)</span>
<span id="cb1-12">pd.options.display.float_format <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{:.3f}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">format</span></span>
<span id="cb1-13">plt.rcParams.update({</span>
<span id="cb1-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'figure.figsize'</span>: (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.8</span>),</span>
<span id="cb1-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.top'</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb1-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.spines.right'</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb1-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'axes.titleweight'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'bold'</span>,</span>
<span id="cb1-18">})</span>
<span id="cb1-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'NumPy </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>__version__<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | pandas </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pd<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>__version__<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> | statsmodels </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>sm<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>__version__<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>NumPy 2.5.1 | pandas 3.0.5 | statsmodels 0.14.6</code></pre>
</div>
</div>
</section>
<section id="los-datos-entregas-repetidas-por-repartidor" class="level2">
<h2 class="anchored" data-anchor-id="los-datos-entregas-repetidas-por-repartidor">Los datos: entregas repetidas por repartidor</h2>
<p>Generaremos 30 repartidores con 16 entregas cada uno. La distancia cambia entre entregas, pero cada persona recibe un desplazamiento propio en minutos: algunos son sistemáticamente más rápidos y otros más lentos.</p>
<p>La regla oculta usa una pendiente común de <strong>1.65 minutos por kilómetro</strong>, un efecto individual con desviación estándar de 7 minutos y ruido por entrega con desviación estándar de 2.7 minutos. La columna <code>efecto_real_min</code> se conserva únicamente para auditar la simulación; no existiría en una aplicación real.</p>
<div id="73e96a08" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.211816Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.211368Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.230705Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.229501Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">n_repartidores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span></span>
<span id="cb3-2">entregas_por_repartidor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span></span>
<span id="cb3-3">pendiente_real <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.65</span></span>
<span id="cb3-4"></span>
<span id="cb3-5">media_distancia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>, n_repartidores)</span>
<span id="cb3-6">efecto_repartidor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, n_repartidores)</span>
<span id="cb3-7">filas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb3-8"></span>
<span id="cb3-9"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> indice <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(n_repartidores):</span>
<span id="cb3-10">    distancias <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.clip(</span>
<span id="cb3-11">        media_distancia[indice] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.4</span>, entregas_por_repartidor),</span>
<span id="cb3-12">        <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>,</span>
<span id="cb3-13">    )</span>
<span id="cb3-14">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> numero_entrega, distancia <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(distancias, start<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>):</span>
<span id="cb3-15">        tiempo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb3-16">            <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">28</span></span>
<span id="cb3-17">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> pendiente_real <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> distancia</span>
<span id="cb3-18">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> efecto_repartidor[indice]</span>
<span id="cb3-19">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.7</span>)</span>
<span id="cb3-20">        )</span>
<span id="cb3-21">        filas.append({</span>
<span id="cb3-22">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>: <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'R</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>indice <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:02d}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>,</span>
<span id="cb3-23">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'entrega'</span>: numero_entrega,</span>
<span id="cb3-24">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>: distancia,</span>
<span id="cb3-25">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo_min'</span>: tiempo,</span>
<span id="cb3-26">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'efecto_real_min'</span>: efecto_repartidor[indice],</span>
<span id="cb3-27">        })</span>
<span id="cb3-28"></span>
<span id="cb3-29">datos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(filas)</span>
<span id="cb3-30"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Datos generados: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>datos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> entregas y </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>datos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> columnas'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Datos generados: 480 entregas y 5 columnas</code></pre>
</div>
</div>
<section id="una-primera-mirada" class="level3">
<h3 class="anchored" data-anchor-id="una-primera-mirada">Una primera mirada</h3>
<p>Antes de modelar, verifica la unidad de análisis. Una fila representa una entrega, pero la unidad que se repite es el repartidor. Mostraremos ambas cantidades y algunas filas de tres personas.</p>
<div id="ff8d1544" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.233745Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.233429Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.255236Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.254141Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">conteos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> datos.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>).size()</span>
<span id="cb5-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Entregas: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(datos)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb5-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Repartidores: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>datos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"repartidor"</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nunique()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb5-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Entregas por repartidor: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>conteos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>conteos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb5-5">display(datos[datos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>].isin([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'R01'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'R02'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'R03'</span>])].groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>).head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Entregas: 480
Repartidores: 30
Entregas por repartidor: 16 a 16</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">repartidor</th>
<th data-quarto-table-cell-role="th">entrega</th>
<th data-quarto-table-cell-role="th">distancia_km</th>
<th data-quarto-table-cell-role="th">tiempo_min</th>
<th data-quarto-table-cell-role="th">efecto_real_min</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>R01</td>
<td>1</td>
<td>12.370</td>
<td>51.700</td>
<td>2.930</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>R01</td>
<td>2</td>
<td>16.770</td>
<td>56.210</td>
<td>2.930</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>R01</td>
<td>3</td>
<td>14.880</td>
<td>57.600</td>
<td>2.930</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>R01</td>
<td>4</td>
<td>13.080</td>
<td>53.990</td>
<td>2.930</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">16</th>
<td>R02</td>
<td>1</td>
<td>6.000</td>
<td>41.450</td>
<td>6.440</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">17</th>
<td>R02</td>
<td>2</td>
<td>6.170</td>
<td>48.910</td>
<td>6.440</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">18</th>
<td>R02</td>
<td>3</td>
<td>6.640</td>
<td>45.990</td>
<td>6.440</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">19</th>
<td>R02</td>
<td>4</td>
<td>6.540</td>
<td>50.100</td>
<td>6.440</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">32</th>
<td>R03</td>
<td>1</td>
<td>11.440</td>
<td>51.440</td>
<td>7.780</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">33</th>
<td>R03</td>
<td>2</td>
<td>12.190</td>
<td>58.350</td>
<td>7.780</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">34</th>
<td>R03</td>
<td>3</td>
<td>9.130</td>
<td>47.800</td>
<td>7.780</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">35</th>
<td>R03</td>
<td>4</td>
<td>10.290</td>
<td>56.470</td>
<td>7.780</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
<section id="cómo-leer-este-resultado" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado">Cómo leer este resultado</h3>
<p>Hay <strong>480 entregas</strong>, pero solo <strong>30 repartidores</strong>; cada uno aporta exactamente <strong>16 mediciones</strong>. Por eso <code>480</code> no equivale a 480 fuentes independientes de información. En la tabla, las cuatro filas de R01 comparten el mismo efecto individual (<strong>2.93 min</strong>), las de R02 otro (<strong>6.44</strong>) y las de R03 otro (<strong>7.78</strong>), aunque la distancia y el tiempo cambien de una entrega a otra.</p>
</section>
</section>
<section id="qué-hace-longitudinal-a-estos-datos" class="level2">
<h2 class="anchored" data-anchor-id="qué-hace-longitudinal-a-estos-datos">Qué hace longitudinal a estos datos</h2>
<p>Un conjunto es <strong>longitudinal</strong> (o de panel) cuando observas repetidamente la misma unidad a lo largo del tiempo: personas, vehículos, tiendas o rutas. En este artículo nos concentramos en la consecuencia más inmediata de esa repetición, la semejanza entre mediciones de una misma unidad, y dejamos de lado el orden de las entregas; cuando ese orden importa, hay que añadir estructura temporal (lo retomamos al cierre). Los índices importan: <img src="https://latex.codecogs.com/png.latex?i"> identifica al repartidor y <img src="https://latex.codecogs.com/png.latex?j"> identifica una entrega suya.</p>
<p>Primero vamos a verla.</p>
</section>
<section id="seis-historias-individuales" class="level2">
<h2 class="anchored" data-anchor-id="seis-historias-individuales">Seis historias individuales</h2>
<p>Una nube global puede esconder la estructura. Seleccionemos seis repartidores distribuidos a lo largo del rango de efectos reales y unamos sus entregas ordenadas por distancia. Las líneas no representan tiempo cronológico: ayudan a seguir visualmente a cada persona.</p>
<div id="d56ec29c" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.258518Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.258073Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.506976Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.505749Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">orden_efectos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (datos.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>)[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'efecto_real_min'</span>].first().sort_values())</span>
<span id="cb7-2">posiciones <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(orden_efectos) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)</span>
<span id="cb7-3">seleccionados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> orden_efectos.index[posiciones]</span>
<span id="cb7-4">colores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.cm.viridis(np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.08</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.92</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(seleccionados)))</span>
<span id="cb7-5"></span>
<span id="cb7-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> repartidor, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(seleccionados, colores):</span>
<span id="cb7-7">    parte <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> datos[datos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> repartidor].sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>)</span>
<span id="cb7-8">    plt.plot(parte[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>], parte[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo_min'</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o-'</span>,</span>
<span id="cb7-9">             color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.78</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>repartidor)</span>
<span id="cb7-10"></span>
<span id="cb7-11">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Distancia (km)'</span>)</span>
<span id="cb7-12">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Tiempo de entrega (min)'</span>)</span>
<span id="cb7-13">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'La distancia aumenta el tiempo, pero cada repartidor parte de otro nivel'</span>)</span>
<span id="cb7-14">plt.legend(ncol<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Repartidor'</span>)</span>
<span id="cb7-15">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/16-datos-longitudinales/index_files/figure-html/cell-5-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-esta-figura" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-figura">Cómo leer esta figura</h3>
<p>Dentro de cada color, el tiempo tiende a crecer con la distancia. Entre colores hay desplazamientos verticales persistentes: a una distancia parecida, dos repartidores pueden tardar tiempos distintos. Esa separación vertical es la señal visual de un <strong>intercepto propio por persona</strong>.</p>
</section>
</section>
<section id="cuánta-variabilidad-hay-entre-personas" class="level2">
<h2 class="anchored" data-anchor-id="cuánta-variabilidad-hay-entre-personas">Cuánta variabilidad hay entre personas</h2>
<p>Resumiremos cada repartidor por su distancia y tiempo medios. Si el nivel individual importa, las medias de tiempo deberían ocupar un rango amplio, incluso después de reconocer que no todos recorren las mismas distancias.</p>
<div id="c43cf2f3" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.510037Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.509575Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.540136Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.539015Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">resumen_repartidor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb8-2">    datos.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>)</span>
<span id="cb8-3">    .agg(</span>
<span id="cb8-4">        entregas<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'entrega'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'size'</span>),</span>
<span id="cb8-5">        distancia_media_km<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean'</span>),</span>
<span id="cb8-6">        tiempo_medio_min<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo_min'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean'</span>),</span>
<span id="cb8-7">        efecto_real_min<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'efecto_real_min'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'first'</span>),</span>
<span id="cb8-8">    )</span>
<span id="cb8-9">    .sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo_medio_min'</span>)</span>
<span id="cb8-10">)</span>
<span id="cb8-11">display(resumen_repartidor.head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb8-12">display(resumen_repartidor.tail(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb8-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Rango de medias individuales: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>resumen_repartidor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>tiempo_medio_min<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>resumen_repartidor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>tiempo_medio_min<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> min'</span>)</span>
<span id="cb8-14">corr_distancia_efecto <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> resumen_repartidor[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_media_km'</span>].corr(resumen_repartidor[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'efecto_real_min'</span>])</span>
<span id="cb8-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Correlación entre distancia media y efecto real (auditoría): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>corr_distancia_efecto<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">entregas</th>
<th data-quarto-table-cell-role="th">distancia_media_km</th>
<th data-quarto-table-cell-role="th">tiempo_medio_min</th>
<th data-quarto-table-cell-role="th">efecto_real_min</th>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">repartidor</th>
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th"></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">R24</th>
<td>16</td>
<td>2.540</td>
<td>18.710</td>
<td>-12.600</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">R20</th>
<td>16</td>
<td>3.700</td>
<td>25.000</td>
<td>-8.910</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">R16</th>
<td>16</td>
<td>3.740</td>
<td>28.700</td>
<td>-5.520</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">R17</th>
<td>16</td>
<td>5.770</td>
<td>30.000</td>
<td>-7.970</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">entregas</th>
<th data-quarto-table-cell-role="th">distancia_media_km</th>
<th data-quarto-table-cell-role="th">tiempo_medio_min</th>
<th data-quarto-table-cell-role="th">efecto_real_min</th>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">repartidor</th>
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th"></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">R03</th>
<td>16</td>
<td>11.660</td>
<td>54.600</td>
<td>7.780</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">R01</th>
<td>16</td>
<td>14.550</td>
<td>55.500</td>
<td>2.930</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">R15</th>
<td>16</td>
<td>12.680</td>
<td>56.000</td>
<td>7.410</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">R10</th>
<td>16</td>
<td>14.070</td>
<td>62.370</td>
<td>12.760</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Rango de medias individuales: 18.7 a 62.4 min
Correlación entre distancia media y efecto real (auditoría): 0.288</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-1">Cómo leer este resultado</h3>
<p>Las medias individuales van de <strong>18.7 a 62.4 minutos</strong>. Parte de esa diferencia proviene de las distancias habituales y parte del efecto propio de cada repartidor. La amplitud ya advierte que una única recta, sin identidad individual, tendrá que mezclar niveles muy distintos.</p>
<p>La auditoría revela además un detalle que importará más adelante: la correlación entre la distancia media de cada repartidor y su efecto real es <strong>0.288</strong>. La simulación sortea ambas cosas de forma independiente, pero en esta muestra, por azar, los repartidores con rutas más largas resultaron algo más lentos.</p>
<p>Ordenar las medias permite distinguir una fluctuación aislada de una diferencia persistente. En la siguiente figura, las barras muestran el rango observado de cada persona y el punto marca su media.</p>
<div id="407d531b" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.543468Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.542999Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.819748Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.818201Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">rangos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> datos.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>)[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo_min'</span>].agg([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'min'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'max'</span>])</span>
<span id="cb10-2">rangos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rangos.sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean'</span>)</span>
<span id="cb10-3">y_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(rangos))</span>
<span id="cb10-4"></span>
<span id="cb10-5">plt.hlines(y_pos, rangos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'min'</span>], rangos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'max'</span>], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#9aa0a6'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>)</span>
<span id="cb10-6">plt.scatter(rangos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean'</span>], y_pos, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#15616d'</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">34</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb10-7">plt.axvline(datos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo_min'</span>].mean(), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e76f51'</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>,</span>
<span id="cb10-8">            label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Media global: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>datos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>tiempo_min<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> min'</span>)</span>
<span id="cb10-9">plt.yticks(y_pos, rangos.index, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb10-10">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Tiempo de entrega (min)'</span>)</span>
<span id="cb10-11">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Repartidor'</span>)</span>
<span id="cb10-12">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Rango y media de tiempo por repartidor'</span>)</span>
<span id="cb10-13">plt.legend()</span>
<span id="cb10-14">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/16-datos-longitudinales/index_files/figure-html/cell-7-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="cómo-leer-esta-figura-1" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-figura-1">Cómo leer esta figura</h3>
<p>Los rangos individuales se escalonan alrededor de la media global de <strong>42.3 min</strong>: las medias van de <strong>18.7</strong> (R24) a <strong>62.4 min</strong> (R10), y muchos rangos completos quedan a un solo lado de la línea discontinua. No estás viendo 480 puntos intercambiables: estás viendo 30 conjuntos con centros propios. El siguiente modelo ignorará deliberadamente esa información para mostrar qué sale mal.</p>
</section>
</section>
<section id="el-error-de-ignorar-la-estructura" class="level2">
<h2 class="anchored" data-anchor-id="el-error-de-ignorar-la-estructura">El error de ignorar la estructura</h2>
<p>El modelo <strong><em>pooled</em></strong> apila todas las entregas y ajusta una sola recta:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ay_%7Bij%7D=%5Cbeta_0+%5Cbeta_1x_%7Bij%7D+%5Cvarepsilon_%7Bij%7D.%0A"></p>
<p>La fórmula no contiene al repartidor. Al ajustarla por mínimos cuadrados ordinarios (OLS, por sus siglas en inglés), el modelo tratará los 480 residuos como independientes, aunque cada bloque de 16 comparte un componente omitido.</p>
<div id="ecddfbfc" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.822449Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.822115Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:32.843823Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:32.842366Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1">modelo_pooled <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> smf.ols(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo_min ~ distancia_km'</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>datos).fit()</span>
<span id="cb11-2">ci_pooled <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_pooled.conf_int().loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]</span>
<span id="cb11-3">tabla_pooled <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb11-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'coeficiente'</span>: [modelo_pooled.params[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]],</span>
<span id="cb11-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'error_estandar'</span>: [modelo_pooled.bse[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]],</span>
<span id="cb11-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC_95_inf'</span>: [ci_pooled.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]],</span>
<span id="cb11-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC_95_sup'</span>: [ci_pooled.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]],</span>
<span id="cb11-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'p_valor'</span>: [modelo_pooled.pvalues[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]],</span>
<span id="cb11-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'R2'</span>: [modelo_pooled.rsquared],</span>
<span id="cb11-10">}, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>])</span>
<span id="cb11-11">display(tabla_pooled.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb11-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'N que OLS trata como independiente: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(modelo_pooled.nobs)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">coeficiente</th>
<th data-quarto-table-cell-role="th">error_estandar</th>
<th data-quarto-table-cell-role="th">IC_95_inf</th>
<th data-quarto-table-cell-role="th">IC_95_sup</th>
<th data-quarto-table-cell-role="th">p_valor</th>
<th data-quarto-table-cell-role="th">R2</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">distancia_km</th>
<td>1.951</td>
<td>0.061</td>
<td>1.831</td>
<td>2.071</td>
<td>0.000</td>
<td>0.682</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>N que OLS trata como independiente: 480</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-2" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-2">Cómo leer este resultado</h3>
<p>La recta <em>pooled</em> estima <strong>1.951 min/km</strong>, con error estándar <strong>0.061</strong> e intervalo de confianza del 95% (IC 95%) <strong>[1.831, 2.071]</strong>. El p-valor es menor que 0.001 y <img src="https://latex.codecogs.com/png.latex?R%5E2=0.682">. Parece una estimación extraordinariamente precisa, pero el intervalo ni siquiera contiene el valor generador <strong>1.65</strong>.</p>
<p>Un p-valor pequeño solo evalúa el coeficiente bajo el modelo supuesto. No repara la independencia falsa, no mide importancia práctica y no demuestra que aumentar la distancia cause exactamente ese cambio.</p>
</section>
<section id="antes-de-seguir-pregúntate" class="level3">
<h3 class="anchored" data-anchor-id="antes-de-seguir-pregúntate">Antes de seguir, pregúntate</h3>
<ul>
<li>Si un repartidor aporta 16 entregas, ¿aporta 16 historias independientes o 16 variaciones de una misma historia?</li>
<li>¿Qué parte del tiempo cambia con la distancia y qué parte pertenece a la persona?</li>
<li>Si mañana observas otra entrega de R01, ¿esperas que se parezca más a otra entrega de R01 o a una entrega al azar?</li>
</ul>
<p>Estas preguntas cambian la unidad de razonamiento: la fila sigue siendo útil, pero el grupo ya no puede desaparecer del modelo.</p>
</section>
</section>
<section id="los-residuos-revelan-la-dependencia" class="level2">
<h2 class="anchored" data-anchor-id="los-residuos-revelan-la-dependencia">Los residuos revelan la dependencia</h2>
<p>Si OLS hubiera absorbido la estructura relevante, la media de sus residuos sería cercana a cero no solo globalmente, sino también para cada repartidor. Calcularemos esas medias y las ordenaremos.</p>
<div id="fb77dda2" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:32.846448Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:32.846160Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:33.072329Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:33.071009Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">datos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'residuo_pooled'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_pooled.resid</span>
<span id="cb13-2">residuos_por_repartidor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> datos.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>)[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'residuo_pooled'</span>].mean().sort_values()</span>
<span id="cb13-3"></span>
<span id="cb13-4">colores_residuo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(residuos_por_repartidor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#457b9d'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e76f51'</span>)</span>
<span id="cb13-5">plt.bar(residuos_por_repartidor.index, residuos_por_repartidor, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>colores_residuo)</span>
<span id="cb13-6">plt.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'black'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb13-7">plt.xticks(rotation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>)</span>
<span id="cb13-8">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Residuo pooled medio (min)'</span>)</span>
<span id="cb13-9">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Repartidor'</span>)</span>
<span id="cb13-10">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'El modelo pooled se equivoca sistemáticamente por persona'</span>)</span>
<span id="cb13-11">plt.show()</span>
<span id="cb13-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Residuos medios por repartidor: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>residuos_por_repartidor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>residuos_por_repartidor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> min'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/16-datos-longitudinales/index_files/figure-html/cell-9-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Residuos medios por repartidor: -12.3 a 8.8 min</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-3" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-3">Cómo leer este resultado</h3>
<p>Aunque el residuo medio global de OLS es cero por construcción, las medias por repartidor van de <strong>−12.3 a 8.8 minutos</strong>. Los bloques completos por debajo o por encima de cero muestran que los errores conservan información sobre la identidad. Eso contradice la idea de errores independientes e intercambiables.</p>
<p>El problema no es que una recta sea incapaz de describir el efecto medio de la distancia; es que el modelo atribuye toda desviación a ruido independiente y usa también diferencias <strong>entre</strong> repartidores para estimar una relación que queremos leer <strong>dentro</strong> de cada repartidor. En esta muestra eso tiene un costo visible: como la distancia media y el efecto individual quedaron correlacionados (<strong>0.288</strong>), la comparación entre personas empuja la pendiente hacia arriba. Si esa correlación fuera nula, la recta <em>pooled</em> seguiría centrada, en promedio, en el valor correcto y el problema sería sobre todo la incertidumbre.</p>
</section>
</section>
<section id="medir-la-semejanza-correlación-intraclase" class="level2">
<h2 class="anchored" data-anchor-id="medir-la-semejanza-correlación-intraclase">Medir la semejanza: correlación intraclase</h2>
<p>La <strong>correlación intraclase</strong> (ICC) cuantifica qué proporción de la variabilidad no explicada por el modelo corresponde a diferencias entre repartidores (<img src="https://latex.codecogs.com/png.latex?%5Csigma_b%5E2">, varianza entre repartidores) y qué parte a la variación de una entrega a otra (<img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2">, varianza dentro de cada repartidor). Primero ajustaremos un modelo nulo, sin distancia, para describir la dependencia bruta:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7BICC%7D=%5Cfrac%7B%5Csigma_b%5E2%7D%7B%5Csigma_b%5E2+%5Csigma%5E2%7D.%0A"></p>
<p>Con grupos del mismo tamaño <img src="https://latex.codecogs.com/png.latex?m">, <img src="https://latex.codecogs.com/png.latex?1+(m-1)%5C,%5Cmathrm%7BICC%7D"> es el factor de diseño aproximado: indica cuántas veces se infla la varianza de una media calculada con <img src="https://latex.codecogs.com/png.latex?N"> filas agrupadas respecto de la misma media con <img src="https://latex.codecogs.com/png.latex?N"> observaciones independientes. Por eso <img src="https://latex.codecogs.com/png.latex?N/%5B1+(m-1)%5C,%5Cmathrm%7BICC%7D%5D"> se lee como un tamaño efectivo.</p>
<div id="419c4c1d" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:33.074942Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:33.074591Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:33.149859Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:33.148738Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1">modelo_nulo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> smf.mixedlm(</span>
<span id="cb15-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo_min ~ 1'</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>datos, groups<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>datos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>]</span>
<span id="cb15-3">).fit(reml<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb15-4">varianza_entre_nula <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(modelo_nulo.cov_re.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb15-5">varianza_residual_nula <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_nulo.scale</span>
<span id="cb15-6">icc_nula <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> varianza_entre_nula <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (varianza_entre_nula <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> varianza_residual_nula)</span>
<span id="cb15-7">factor_diseno <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (entregas_por_repartidor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> icc_nula</span>
<span id="cb15-8">n_efectivo_aprox <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(datos) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> factor_diseno</span>
<span id="cb15-9"></span>
<span id="cb15-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Varianza entre repartidores: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>varianza_entre_nula<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb15-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Varianza dentro de repartidores: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>varianza_residual_nula<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb15-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'ICC bruta: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>icc_nula<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb15-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Factor de diseño aproximado: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>factor_diseno<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb15-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Tamaño efectivo aproximado: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n_efectivo_aprox<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Varianza entre repartidores: 100.63
Varianza dentro de repartidores: 12.36
ICC bruta: 0.891
Factor de diseño aproximado: 14.36
Tamaño efectivo aproximado: 33.4</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-4" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-4">Cómo leer este resultado</h3>
<p>La ICC bruta es <strong>0.891</strong>: antes de ajustar por distancia, cerca del 89.1% de la variación se asocia con diferencias entre repartidores. Con 16 entregas por persona, el factor de diseño aproximado es <strong>14.36</strong> y las 480 filas equivalen, de manera muy aproximada, a <strong>33.4 observaciones independientes</strong> para cantidades dominadas por esa correlación.</p>
<p>No uses este tamaño efectivo como sustituto universal de un modelo. Sirve para hacer visible por qué contar filas exagera la información disponible.</p>
</section>
</section>
<section id="la-idea-de-un-modelo-de-efectos-mixtos" class="level2">
<h2 class="anchored" data-anchor-id="la-idea-de-un-modelo-de-efectos-mixtos">La idea de un modelo de efectos mixtos</h2>
<p>Un modelo mixto combina dos fuentes:</p>
<ul>
<li><strong>Efectos fijos:</strong> parámetros comunes a toda la población, como la pendiente media de la distancia.</li>
<li><strong>Efectos aleatorios:</strong> desviaciones específicas de cada grupo, como el nivel propio de cada repartidor.</li>
</ul>
<p>Aquí mantendremos una pendiente común y permitiremos que el intercepto cambie. Es el modelo más pequeño capaz de representar la estructura que vimos.</p>
</section>
<section id="marco-formal" class="level2">
<h2 class="anchored" data-anchor-id="marco-formal">Marco formal</h2>
<p>Para la entrega <img src="https://latex.codecogs.com/png.latex?j"> del repartidor <img src="https://latex.codecogs.com/png.latex?i">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ay_%7Bij%7D=%5Cbeta_0+%5Cbeta_1x_%7Bij%7D+b_%7B0i%7D+%5Cvarepsilon_%7Bij%7D,%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ab_%7B0i%7D%5Csim%5Cmathcal%7BN%7D(0,%5Csigma_b%5E2),%5Cquad%5Cvarepsilon_%7Bij%7D%5Csim%5Cmathcal%7BN%7D(0,%5Csigma%5E2).%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cbeta_1"> es el cambio medio en minutos por kilómetro; <img src="https://latex.codecogs.com/png.latex?b_%7B0i%7D"> desplaza la recta del repartidor <img src="https://latex.codecogs.com/png.latex?i">. Condicionalmente a <img src="https://latex.codecogs.com/png.latex?b_%7B0i%7D">, los errores <img src="https://latex.codecogs.com/png.latex?%5Cvarepsilon_%7Bij%7D"> se suponen independientes; los <img src="https://latex.codecogs.com/png.latex?b_%7B0i%7D"> son independientes entre repartidores y de los <img src="https://latex.codecogs.com/png.latex?%5Cvarepsilon_%7Bij%7D">. También suponemos que los efectos aleatorios son independientes de las covariables; si la asignación de distancias dependiera sistemáticamente de la rapidez no observada, habría que enriquecer el modelo.</p>
<p>Ajustaremos el modelo por máxima verosimilitud restringida (REML), el método habitual para estimar componentes de varianza con menos sesgo que la máxima verosimilitud (ML) ordinaria.</p>
<div id="88f12529" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:33.153196Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:33.152786Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:33.226049Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:33.224714Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1">modelo_mixto <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> smf.mixedlm(</span>
<span id="cb17-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo_min ~ distancia_km'</span>,</span>
<span id="cb17-3">    data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>datos,</span>
<span id="cb17-4">    groups<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>datos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>],</span>
<span id="cb17-5">).fit(reml<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb17-6"></span>
<span id="cb17-7">ci_mixto <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_mixto.conf_int().loc[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]</span>
<span id="cb17-8">varianza_entre <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(modelo_mixto.cov_re.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb17-9">varianza_residual <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_mixto.scale</span>
<span id="cb17-10">icc_ajustada <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> varianza_entre <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (varianza_entre <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> varianza_residual)</span>
<span id="cb17-11"></span>
<span id="cb17-12">tabla_mixta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb17-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'coeficiente'</span>: [modelo_mixto.params[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]],</span>
<span id="cb17-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'error_estandar'</span>: [modelo_mixto.bse[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]],</span>
<span id="cb17-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC_95_inf'</span>: [ci_mixto.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]],</span>
<span id="cb17-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC_95_sup'</span>: [ci_mixto.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]],</span>
<span id="cb17-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'p_valor'</span>: [modelo_mixto.pvalues[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]],</span>
<span id="cb17-18">}, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>])</span>
<span id="cb17-19">display(tabla_mixta.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb17-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Varianza entre repartidores: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>varianza_entre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb17-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Varianza residual: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>varianza_residual<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb17-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'ICC ajustada por distancia: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>icc_ajustada<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb17-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Convergió: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>modelo_mixto<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>converged<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">coeficiente</th>
<th data-quarto-table-cell-role="th">error_estandar</th>
<th data-quarto-table-cell-role="th">IC_95_inf</th>
<th data-quarto-table-cell-role="th">IC_95_sup</th>
<th data-quarto-table-cell-role="th">p_valor</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">distancia_km</th>
<td>1.746</td>
<td>0.089</td>
<td>1.570</td>
<td>1.921</td>
<td>0.000</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Varianza entre repartidores: 29.582
Varianza residual: 7.274
ICC ajustada por distancia: 0.803
Convergió: True</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-5" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-5">Cómo leer este resultado</h3>
<p>El modelo mixto estima <strong>1.746 min/km</strong>, con error estándar <strong>0.089</strong> e IC 95% <strong>[1.570, 1.921]</strong>. Ese intervalo sí contiene el valor generador <strong>1.65</strong>. El p-valor es menor que 0.001: aporta evidencia de una asociación positiva bajo los supuestos del modelo, no prueba causalidad.</p>
<p>Después de ajustar por distancia, la varianza entre repartidores es <strong>29.582</strong> y la residual <strong>7.274</strong>; la ICC ajustada es <strong>0.803</strong>. Dos entregas de la misma persona siguen compartiendo una fracción grande de variabilidad, precisamente la estructura que OLS omitía.</p>
</section>
</section>
<section id="los-interceptos-propios-y-la-contracción-parcial" class="level2">
<h2 class="anchored" data-anchor-id="los-interceptos-propios-y-la-contracción-parcial">Los interceptos propios y la contracción parcial</h2>
<p><code>MixedLM</code> estima un efecto aleatorio para cada repartidor. Estas estimaciones se conocen como BLUP (<em>best linear unbiased predictor</em>, mejor predictor lineal insesgado) y aplican <strong>contracción parcial</strong>: combinan la información individual con la distribución del conjunto. Un grupo con poca información sería atraído más hacia cero; uno con evidencia consistente conservaría una desviación mayor.</p>
<div id="a3481497" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:33.229422Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:33.229098Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:33.525339Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:33.523732Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1">efectos_estimados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series({</span>
<span id="cb19-2">    repartidor: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.asarray(valor)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb19-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> repartidor, valor <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> modelo_mixto.random_effects.items()</span>
<span id="cb19-4">}, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'efecto_estimado_min'</span>).sort_values()</span>
<span id="cb19-5">efectos_reales <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> datos.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>)[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'efecto_real_min'</span>].first()</span>
<span id="cb19-6">auditoria_efectos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.concat([efectos_estimados, efectos_reales], axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>).sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'efecto_estimado_min'</span>)</span>
<span id="cb19-7"></span>
<span id="cb19-8">display(pd.concat([auditoria_efectos.head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), auditoria_efectos.tail(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)]).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb19-9"></span>
<span id="cb19-10">plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb19-11">plt.hlines(np.arange(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(efectos_estimados)), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, efectos_estimados, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#9aa0a6'</span>)</span>
<span id="cb19-12">plt.scatter(efectos_estimados, np.arange(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(efectos_estimados)),</span>
<span id="cb19-13">            c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>efectos_estimados, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'coolwarm'</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">38</span>)</span>
<span id="cb19-14">plt.axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'black'</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb19-15">plt.yticks(np.arange(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(efectos_estimados)), efectos_estimados.index, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb19-16">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Desviación estimada del intercepto (min)'</span>)</span>
<span id="cb19-17">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Repartidor'</span>)</span>
<span id="cb19-18">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Efectos aleatorios estimados por repartidor'</span>)</span>
<span id="cb19-19">plt.show()</span>
<span id="cb19-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Rango estimado: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>efectos_estimados<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> a </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>efectos_estimados<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> min'</span>)</span>
<span id="cb19-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Correlación con efectos reales simulados: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>efectos_estimados<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>corr(efectos_reales)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">efecto_estimado_min</th>
<th data-quarto-table-cell-role="th">efecto_real_min</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">R24</th>
<td>-13.320</td>
<td>-12.600</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">R20</th>
<td>-9.100</td>
<td>-8.910</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">R17</th>
<td>-7.750</td>
<td>-7.970</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">R07</th>
<td>6.920</td>
<td>7.750</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">R02</th>
<td>7.160</td>
<td>6.440</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">R10</th>
<td>9.860</td>
<td>12.760</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/16-datos-longitudinales/index_files/figure-html/cell-12-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Rango estimado: -13.3 a 9.9 min
Correlación con efectos reales simulados: 0.985</code></pre>
</div>
</div>
<section id="cómo-leer-este-resultado-6" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-este-resultado-6">Cómo leer este resultado</h3>
<p>Los interceptos estimados van de <strong>−13.3 a 9.9 minutos</strong> respecto del nivel común. La correlación con los efectos reales simulados es <strong>0.985</strong>, una auditoría posible solo porque fabricamos los datos. Con 16 entregas por persona la contracción es mínima: <img src="https://latex.codecogs.com/png.latex?%5Chat%5Csigma_b%5E2/(%5Chat%5Csigma_b%5E2+%5Chat%5Csigma%5E2/16)=29.582/(29.582+7.274/16)%5Capprox%200.985">, así que cada BLUP conserva cerca del 98.5% de la desviación media observada del repartidor. Diferencias como la de R10 (<strong>9.86</strong> estimado frente a <strong>12.76</strong> real) no se deben a la contracción, sino al ruido y a los pequeños errores de la parte fija. En una aplicación real interpretarías estas desviaciones estimadas y su incertidumbre, pero nunca conocerías el efecto verdadero.</p>
<p>Un valor negativo describe a una persona sistemáticamente más rápida que el promedio condicionado por distancia; no es una calificación absoluta ni una causa identificada.</p>
</section>
</section>
<section id="una-recta-común-varios-niveles" class="level2">
<h2 class="anchored" data-anchor-id="una-recta-común-varios-niveles">Una recta común, varios niveles</h2>
<p>El efecto fijo produce una predicción poblacional para un repartidor promedio. Al sumar cada BLUP obtenemos una predicción específica para una persona ya observada. Dibujaremos cuatro casos para ver ambas capas.</p>
<div id="1433a623" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:33.529625Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:33.529284Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:33.723992Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:33.722941Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1">casos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> efectos_estimados.index[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">19</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">29</span>]]</span>
<span id="cb21-2">x_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(datos.distancia_km.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), datos.distancia_km.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>)</span>
<span id="cb21-3">intercepto_fijo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_mixto.fe_params[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Intercept'</span>]</span>
<span id="cb21-4">pendiente_mixta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo_mixto.fe_params[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]</span>
<span id="cb21-5"></span>
<span id="cb21-6">plt.scatter(datos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>], datos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo_min'</span>], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#b8c0c2'</span>,</span>
<span id="cb21-7">            s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'entregas'</span>)</span>
<span id="cb21-8">plt.plot(x_grid, intercepto_fijo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> pendiente_mixta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x_grid,</span>
<span id="cb21-9">         color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'black'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nivel poblacional'</span>)</span>
<span id="cb21-10"></span>
<span id="cb21-11"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> repartidor, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(casos, [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#264653'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#2a9d8f'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e9c46a'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e76f51'</span>]):</span>
<span id="cb21-12">    efecto <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> efectos_estimados[repartidor]</span>
<span id="cb21-13">    plt.plot(x_grid, intercepto_fijo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> efecto <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> pendiente_mixta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x_grid,</span>
<span id="cb21-14">             color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>repartidor)</span>
<span id="cb21-15"></span>
<span id="cb21-16">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Distancia (km)'</span>)</span>
<span id="cb21-17">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Tiempo estimado (min)'</span>)</span>
<span id="cb21-18">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'El modelo mixto separa pendiente común e interceptos individuales'</span>)</span>
<span id="cb21-19">plt.legend(ncol<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb21-20">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/16-datos-longitudinales/index_files/figure-html/cell-13-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<section id="cómo-leer-esta-figura-2" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-figura-2">Cómo leer esta figura</h3>
<p>Las cinco rectas son paralelas porque supusimos una pendiente común de <strong>1.746 min/km</strong>. La línea discontinua representa a un repartidor promedio; las líneas de color incorporan su historial mediante el intercepto aleatorio. Si las inclinaciones también variaran claramente entre personas, el siguiente paso sería un modelo con pendiente aleatoria.</p>
</section>
</section>
<section id="comparación-pooled-frente-a-mixto" class="level2">
<h2 class="anchored" data-anchor-id="comparación-pooled-frente-a-mixto">Comparación: <em>pooled</em> frente a mixto</h2>
<p>Pondremos ambos intervalos en la misma escala. Para reportar el criterio de información de Akaike (AIC) del modelo mixto ajustaremos además una copia por ML: <code>statsmodels</code> no calcula AIC para ajustes REML, porque la verosimilitud restringida no es comparable entre modelos con distintos efectos fijos. El ajuste REML sigue siendo el principal para estimar componentes de varianza. Con ambos modelos ajustados por ML, la comparación de AIC es legítima (OLS es el caso particular <img src="https://latex.codecogs.com/png.latex?%5Csigma_b%5E2=0">), pero no es el argumento central: la elección parte del diseño con mediciones repetidas.</p>
<div id="aa6f8102" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-28T01:55:33.727151Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-28T01:55:33.726765Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-28T01:55:33.912985Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-28T01:55:33.912150Z&quot;}}" data-execution_count="13">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1">modelo_mixto_ml <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> smf.mixedlm(</span>
<span id="cb22-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tiempo_min ~ distancia_km'</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>datos, groups<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>datos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>]</span>
<span id="cb22-3">).fit(reml<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb22-4"></span>
<span id="cb22-5">comparacion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb22-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'modelo'</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Pooled OLS'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Mixto REML'</span>],</span>
<span id="cb22-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pendiente'</span>: [modelo_pooled.params[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>], modelo_mixto.params[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]],</span>
<span id="cb22-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'error_estandar'</span>: [modelo_pooled.bse[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>], modelo_mixto.bse[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]],</span>
<span id="cb22-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC_95_inf'</span>: [ci_pooled.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], ci_mixto.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]],</span>
<span id="cb22-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC_95_sup'</span>: [ci_pooled.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], ci_mixto.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]],</span>
<span id="cb22-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'p_valor'</span>: [modelo_pooled.pvalues[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>], modelo_mixto.pvalues[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'distancia_km'</span>]],</span>
<span id="cb22-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'contiene_1.65'</span>: [ci_pooled.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> pendiente_real <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> ci_pooled.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb22-13">                      ci_mixto.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> pendiente_real <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> ci_mixto.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]],</span>
<span id="cb22-14">})</span>
<span id="cb22-15">display(comparacion.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb22-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'AIC pooled: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>modelo_pooled<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>aic<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb22-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'AIC mixto ML: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>modelo_mixto_ml<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>aic<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb22-18"></span>
<span id="cb22-19">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.8</span>))</span>
<span id="cb22-20"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> posicion, fila <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> comparacion.iterrows():</span>
<span id="cb22-21">    ax.errorbar(fila[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pendiente'</span>], posicion,</span>
<span id="cb22-22">                xerr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[[fila[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pendiente'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> fila[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC_95_inf'</span>]],</span>
<span id="cb22-23">                      [fila[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'IC_95_sup'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> fila[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pendiente'</span>]]],</span>
<span id="cb22-24">                fmt<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'o'</span>, markersize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, capsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#d1495b'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#00798c'</span>][posicion])</span>
<span id="cb22-25">ax.axvline(pendiente_real, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'black'</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'--'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'valor generador = 1.65'</span>)</span>
<span id="cb22-26">ax.set_yticks([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], comparacion[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'modelo'</span>])</span>
<span id="cb22-27">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Minutos adicionales por kilómetro'</span>)</span>
<span id="cb22-28">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Estimación e intervalo de confianza del 95%'</span>)</span>
<span id="cb22-29">ax.legend()</span>
<span id="cb22-30">plt.show()</span>
<span id="cb22-31"></span>
<span id="cb22-32"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">assert</span> datos.shape <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">480</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cambió el número esperado de filas o columnas'</span></span>
<span id="cb22-33"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">assert</span> datos[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'repartidor'</span>].nunique() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span></span>
<span id="cb22-34"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">assert</span> modelo_mixto.converged <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> modelo_mixto_ml.converged</span>
<span id="cb22-35"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">assert</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> icc_ajustada <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb22-36"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">assert</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> comparacion.loc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'contiene_1.65'</span>]</span>
<span id="cb22-37"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">assert</span> comparacion.loc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'contiene_1.65'</span>]</span>
<span id="cb22-38"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">assert</span> np.isfinite(comparacion.select_dtypes(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'number'</span>).to_numpy()).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">all</span>()</span>
<span id="cb22-39"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Verificaciones numéricas superadas: estructura, convergencia, ICC y contraste.'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">modelo</th>
<th data-quarto-table-cell-role="th">pendiente</th>
<th data-quarto-table-cell-role="th">error_estandar</th>
<th data-quarto-table-cell-role="th">IC_95_inf</th>
<th data-quarto-table-cell-role="th">IC_95_sup</th>
<th data-quarto-table-cell-role="th">p_valor</th>
<th data-quarto-table-cell-role="th">contiene_1.65</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>Pooled OLS</td>
<td>1.951</td>
<td>0.061</td>
<td>1.831</td>
<td>2.071</td>
<td>0.000</td>
<td>False</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>Mixto REML</td>
<td>1.746</td>
<td>0.089</td>
<td>1.570</td>
<td>1.921</td>
<td>0.000</td>
<td>True</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>AIC pooled: 3071.0
AIC mixto ML: 2446.4</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/avanzado/16-datos-longitudinales/index_files/figure-html/cell-14-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Verificaciones numéricas superadas: estructura, convergencia, ICC y contraste.</code></pre>
</div>
</div>
<section id="cómo-leer-esta-comparación" class="level3">
<h3 class="anchored" data-anchor-id="cómo-leer-esta-comparación">Cómo leer esta comparación</h3>
<p>OLS desplaza la pendiente hasta <strong>1.951</strong> y reporta un IC <strong>[1.831, 2.071]</strong>, demasiado estrecho y alejado del valor generador. El mixto estima <strong>1.746</strong>, amplía el error estándar de <strong>0.061 a 0.089</strong> y produce un IC <strong>[1.570, 1.921]</strong> que sí contiene 1.65. Reconocer los grupos cambia sobre todo la honestidad de la incertidumbre y, en esta muestra, también el centro. El desplazamiento de OLS no es inevitable: proviene de la correlación casual entre distancia media y efecto individual (<strong>0.288</strong>), que la recta <em>pooled</em> mezcla con el efecto de la distancia. El mixto lo atenúa porque su estimador se apoya sobre todo en la variación dentro de cada repartidor, pero no es inmune: si esa correlación fuera sistemática, convendría un modelo de efectos fijos por repartidor.</p>
<p>El AIC baja de <strong>3071.0</strong> en OLS a <strong>2446.4</strong> en el mixto ML, coherente con la fuerte heterogeneidad observada, aunque el argumento principal no es ganar una competencia de AIC: el diseño contiene mediciones repetidas y requiere representarlas. Los errores estándar robustos por conglomerado (<em>cluster-robust</em>) de OLS podrían corregir parcialmente la inferencia, pero no estimarían la varianza entre personas ni producirían interceptos individuales.</p>
<p>Antes de usar este modelo revisa sus límites: suficientes grupos, residuos razonables, posibles pendientes aleatorias, orden temporal y autocorrelación, datos faltantes y relación entre efectos individuales y covariables. Este ejemplo gaussiano con intercepto aleatorio es un punto de partida, no una licencia para afirmar causalidad.</p>
</section>
</section>
<section id="cierre-del-modelo-plano-a-la-estructura-real" class="level2">
<h2 class="anchored" data-anchor-id="cierre-del-modelo-plano-a-la-estructura-real">Cierre: del modelo plano a la estructura real</h2>
<p>Cuando varias filas pertenecen a la misma persona, primero identifica <strong>qué se repite</strong>, luego visualiza la variación dentro y entre grupos, cuantifica la dependencia y elige una estructura que la represente. Un intercepto aleatorio sirve cuando cada individuo tiene un nivel propio; una pendiente aleatoria entra en juego cuando también cambia la respuesta a la covariable.</p>
<p>El recorrido completo de la serie queda conectado: empezaste con regresión y regularización para estimar relaciones estables; aprendiste a evaluar si generalizan; usaste suavización para abandonar formas rígidas; extendiste la respuesta con GLM; representaste dimensiones no observadas con variables latentes; y terminaste reconociendo que el orden temporal y las mediciones repetidas hacen dependientes a los datos. La idea que une todo es sencilla: el modelo debe respetar cómo se generó la información, no solo ajustarse a una tabla.</p>
<pre class="text"><code>¿Hay mediciones repetidas por unidad?
├─ No  → un modelo de observaciones independientes puede ser suficiente
└─ Sí  → identifica el grupo y examina la dependencia
        ├─ cambia el nivel entre grupos      → intercepto aleatorio
        ├─ cambia también la pendiente       → pendiente aleatoria
        └─ importa el orden dentro del grupo → añade estructura temporal</code></pre>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>datos-longitudinales</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/avanzado/16-datos-longitudinales/</guid>
  <pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Estadística para IA — 6. Representación vectorial de datos</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/basico/06-representacion-vectorial-datos/</link>
  <description><![CDATA[ 




<section id="sesión-6-representación-vectorial-de-datos" class="level1">
<h1>Sesión 6 — Representación Vectorial de Datos</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado es Científico de Datos, Arquitecto de IA, Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), consultor y docente universitario, trabaja en la intersección entre Data Science, Inteligencia Artificial, Big Data e IoT, transformando problemas reales en soluciones aplicadas.</p>
<p>De la teoría a la práctica, un problema a la vez.</p>
</section>
<section id="representación-vectorial-de-datos-aplicada" class="level2">
<h2 class="anchored" data-anchor-id="representación-vectorial-de-datos-aplicada">Representación Vectorial de Datos Aplicada</h2>
<p>Un modelo de Machine Learning no consume resúmenes sueltos: consume <strong>la fila completa</strong>. Esa fila es un <strong>vector</strong> en <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BR%7D%5Ep">. El dataset entero es una <strong>matriz</strong>.</p>
<p>Este notebook trabaja ese cambio de lenguaje: <strong>dataset como matriz</strong>, <strong>vectorización</strong>, <strong>producto punto</strong>, <strong>norma</strong>, <strong>distancia euclidiana</strong>, <strong>similitud coseno</strong> e <strong>interpretación geométrica</strong>.</p>
<p>Contexto de ejemplo: <strong>perfiles de hábitos de estudio</strong>. Cada estudiante es un punto en el plano <em>lectura–práctica</em>. El conjunto es sintético y <strong>diseñado a propósito</strong>, para que la geometría se lea a ojo: misma dirección con distinta magnitud, distinta dirección con magnitudes parecidas, y una consulta cuyo “vecino” cambia según la métrica.</p>
<p>Electiva I — Estadística Aplicada a la Inteligencia Artificial · Módulo 2 · Sesión 6</p>
</section>
<section id="objetivos" class="level2">
<h2 class="anchored" data-anchor-id="objetivos">Objetivos</h2>
<ul>
<li>Leer un dataset como <strong>matriz</strong> <img src="https://latex.codecogs.com/png.latex?X"> de tamaño <img src="https://latex.codecogs.com/png.latex?n%20%5Ctimes%20p"> y un vector objetivo <img src="https://latex.codecogs.com/png.latex?y">.</li>
<li>Interpretar cada fila como un <strong>vector</strong> en <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BR%7D%5Ep">.</li>
<li>Calcular e interpretar <strong>producto punto</strong>, <strong>norma</strong> y <strong>ángulo</strong>.</li>
<li>Distinguir <strong>distancia euclidiana</strong> (separación) de <strong>similitud coseno</strong> (orientación).</li>
<li>Ver por qué la <strong>escala de las features</strong> cambia quién es cercano.</li>
<li>Verificar la desigualdad de <strong>Cauchy–Schwarz</strong> y construir el <strong>vector unitario</strong>.</li>
<li>Interpretar <strong>ortogonalidad</strong> y la <strong>proyección ortogonal</strong> de un perfil sobre otro.</li>
<li>Relacionar esta geometría con <strong>KNN</strong>, <strong>embeddings</strong> y <strong>PCA</strong>.</li>
</ul>
<blockquote class="blockquote">
<p>Nota: se recomienda ejecutar las celdas en orden. Las fórmulas usan LaTeX (<code>$...$</code> y <code>$$...$$</code>); si no se ven renderizadas, abre el notebook en Jupyter o Colab.</p>
</blockquote>
</section>
<section id="de-la-tabla-al-espacio" class="level2">
<h2 class="anchored" data-anchor-id="de-la-tabla-al-espacio">1. De la tabla al espacio</h2>
<p>Una tabla tiene filas (observaciones) y columnas (variables). En álgebra, esa misma tabla es una matriz <img src="https://latex.codecogs.com/png.latex?X%20%5Cin%20%5Cmathbb%7BR%7D%5E%7Bn%20%5Ctimes%20p%7D">:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?n"> = número de observaciones,</li>
<li><img src="https://latex.codecogs.com/png.latex?p"> = número de <em>features</em>.</li>
</ul>
<p>La fila <img src="https://latex.codecogs.com/png.latex?i"> es el vector <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bx%7D_i%20=%20(x_%7Bi1%7D,%5Cldots,x_%7Bip%7D)">. Vectorizar no es “inventar números”: es <strong>dejar de leer celdas sueltas y leer la fila como un punto</strong>.</p>
<section id="producto-punto" class="level3">
<h3 class="anchored" data-anchor-id="producto-punto">Producto punto</h3>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Cmathbf%7Ba%7D%5Ccdot%5Cmathbf%7Bb%7D%20=%20%5Csum_%7Bj=1%7D%5E%7Bp%7D%20a_j%20b_j%20=%20%5C%7C%5Cmathbf%7Ba%7D%5C%7C%5C,%5C%7C%5Cmathbf%7Bb%7D%5C%7C%5Ccos%5Ctheta%20"></p>
<p>Suma productos coordenada a coordenada. Geométricamente combina <strong>magnitudes</strong> y <strong>alineación</strong>. Si el ángulo <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> es pequeño, el producto punto (con normas fijas) es grande y positivo.</p>
</section>
<section id="norma-euclidiana" class="level3">
<h3 class="anchored" data-anchor-id="norma-euclidiana">Norma (euclidiana)</h3>
<p><img src="https://latex.codecogs.com/png.latex?%20%5C%7C%5Cmathbf%7Ba%7D%5C%7C_2%20=%20%5Csqrt%7B%5Csum_%7Bj=1%7D%5E%7Bp%7D%20a_j%5E2%7D%20"></p>
<p>Es la <strong>longitud</strong> del vector: qué tan intenso es el perfil, no hacia dónde apunta. Un estudiante que hace el doble de horas en las mismas proporciones tiene la misma dirección y <strong>el doble de norma</strong>.</p>
</section>
<section id="distancia-euclidiana" class="level3">
<h3 class="anchored" data-anchor-id="distancia-euclidiana">Distancia euclidiana</h3>
<p><img src="https://latex.codecogs.com/png.latex?%20d(%5Cmathbf%7Ba%7D,%5Cmathbf%7Bb%7D)%20=%20%5C%7C%5Cmathbf%7Ba%7D-%5Cmathbf%7Bb%7D%5C%7C_2%20"></p>
<p>Mide <strong>separación</strong> en el espacio. Es la métrica por defecto de muchos vecindarios (KNN, <em>k-means</em>). Crece si cambia la magnitud <em>o</em> la dirección, y se deja dominar por la <em>feature</em> de mayor rango.</p>
</section>
<section id="similitud-coseno" class="level3">
<h3 class="anchored" data-anchor-id="similitud-coseno">Similitud coseno</h3>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Ccos%5Ctheta%20=%20%5Cfrac%7B%5Cmathbf%7Ba%7D%5Ccdot%5Cmathbf%7Bb%7D%7D%7B%5C%7C%5Cmathbf%7Ba%7D%5C%7C%5C,%5C%7C%5Cmathbf%7Bb%7D%5C%7C%7D%20"></p>
<p>Queda entre <img src="https://latex.codecogs.com/png.latex?-1"> y <img src="https://latex.codecogs.com/png.latex?1">. Ignora el tamaño global del vector: dos perfiles <strong>proporcionales</strong> tienen <img src="https://latex.codecogs.com/png.latex?%5Ccos%5Ctheta%20=%201"> aunque uno sea más “intenso”. Es la medida habitual en texto y <em>embeddings</em>.</p>
</section>
<section id="desigualdad-de-cauchyschwarz" class="level3">
<h3 class="anchored" data-anchor-id="desigualdad-de-cauchyschwarz">Desigualdad de Cauchy–Schwarz</h3>
<p><img src="https://latex.codecogs.com/png.latex?%20%7C%5Cmathbf%7Ba%7D%5Ccdot%5Cmathbf%7Bb%7D%7C%20%5Cle%20%5C%7C%5Cmathbf%7Ba%7D%5C%7C%5C,%5C%7C%5Cmathbf%7Bb%7D%5C%7C%20"></p>
<p>La igualdad se da si y solo si los vectores son <strong>linealmente dependientes</strong> (uno es múltiplo del otro). El coseno no puede salir del intervalo <img src="https://latex.codecogs.com/png.latex?%5B-1,1%5D"> precisamente por esta desigualdad.</p>
</section>
<section id="vector-unitario" class="level3">
<h3 class="anchored" data-anchor-id="vector-unitario">Vector unitario</h3>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Chat%7B%5Cmathbf%7Ba%7D%7D%20=%20%5Cfrac%7B%5Cmathbf%7Ba%7D%7D%7B%5C%7C%5Cmathbf%7Ba%7D%5C%7C%7D%20%5Cqquad%20(%5Cmathbf%7Ba%7D%5Cneq%5Cmathbf%7B0%7D)%20"></p>
<p>Tiene norma <img src="https://latex.codecogs.com/png.latex?1"> y conserva la dirección. Dividir por la norma <strong>quita la intensidad</strong> y deja solo la orientación: es el paso algebraico detrás de la similitud coseno.</p>
</section>
<section id="ortogonalidad" class="level3">
<h3 class="anchored" data-anchor-id="ortogonalidad">Ortogonalidad</h3>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Cmathbf%7Ba%7D%5Cperp%5Cmathbf%7Bb%7D%20%5Ciff%20%5Cmathbf%7Ba%7D%5Ccdot%5Cmathbf%7Bb%7D=0%20"></p>
<p>El ángulo es <img src="https://latex.codecogs.com/png.latex?%5Cpi/2">. En datos, dos perfiles ortogonales no comparten “empuje” en ninguna coordenada ponderada: saber uno no informa la magnitud del otro en la dirección del primero.</p>
</section>
<section id="proyección-ortogonal" class="level3">
<h3 class="anchored" data-anchor-id="proyección-ortogonal">Proyección ortogonal</h3>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Cmathrm%7Bproj%7D_%7B%5Cmathbf%7Bb%7D%7D(%5Cmathbf%7Ba%7D)%20=%20%5Cfrac%7B%5Cmathbf%7Ba%7D%5Ccdot%5Cmathbf%7Bb%7D%7D%7B%5C%7C%5Cmathbf%7Bb%7D%5C%7C%5E2%7D%5C,%5Cmathbf%7Bb%7D%20"></p>
<p>Es la sombra de <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Ba%7D"> sobre la recta de <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bb%7D">: la parte de <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Ba%7D"> que se explica por esa dirección. El residual <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Ba%7D-%5Cmathrm%7Bproj%7D_%7B%5Cmathbf%7Bb%7D%7D(%5Cmathbf%7Ba%7D)"> es ortogonal a <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bb%7D">. Esa descomposición es el esqueleto de la regresión lineal simple y de PCA.</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Pregunta</th>
<th>Herramienta</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>¿Cómo guardo el dataset para un modelo?</td>
<td>Matriz <img src="https://latex.codecogs.com/png.latex?X">, vector <img src="https://latex.codecogs.com/png.latex?y"></td>
</tr>
<tr class="even">
<td>¿Qué tan largo es un perfil?</td>
<td>Norma</td>
</tr>
<tr class="odd">
<td>¿Cuánto se alinean dos perfiles?</td>
<td>Producto punto / coseno</td>
</tr>
<tr class="even">
<td>¿Qué tan lejos están dos observaciones?</td>
<td>Distancia euclidiana</td>
</tr>
<tr class="odd">
<td>¿Se parecen en <em>forma</em>, no en intensidad?</td>
<td>Similitud coseno</td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="por-qué-importa-en-ia-y-machine-learning" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-importa-en-ia-y-machine-learning">2. Por qué importa en IA y Machine Learning</h2>
<p>El modelo no “ve” nombres de columnas: ve coordenadas.</p>
<ul>
<li>En <strong>regresión y redes</strong>, <img src="https://latex.codecogs.com/png.latex?X"> es la entrada; cada fila es un punto que se transforma.</li>
<li>En <strong>KNN</strong> y <strong>clustering</strong>, “parecido” significa <strong>cerca</strong> según una distancia. Si no se escala, una variable en milisegundos aplasta a otra en horas.</li>
<li>En <strong>texto, recomendaciones y embeddings</strong>, dos documentos pueden tener distinta longitud y el mismo tema: ahí suele importar más el <strong>ángulo</strong> (coseno) que la distancia bruta.</li>
<li>En <strong>PCA</strong> se buscan nuevas direcciones que capturen varianza en <em>este</em> espacio.</li>
</ul>
<p><strong>Idea central:</strong> distancia y ángulo no cuentan la misma historia. Dos observaciones pueden ser vecinas en dirección y lejanas en magnitud —o al revés— y el algoritmo tomará una decisión distinta según la métrica.</p>
</section>
<section id="flujo-recomendado-de-trabajo" class="level2">
<h2 class="anchored" data-anchor-id="flujo-recomendado-de-trabajo">3. Flujo recomendado de trabajo</h2>
<ol type="1">
<li><strong>Escribir el dataset como <img src="https://latex.codecogs.com/png.latex?X"></strong></li>
</ol>
<p>Separar <em>features</em> del objetivo. Anotar <img src="https://latex.codecogs.com/png.latex?n"> y <img src="https://latex.codecogs.com/png.latex?p">.</p>
<ol start="2" type="1">
<li><strong>Ver cada fila como un vector</strong></li>
</ol>
<p>Preguntar qué significa una coordenada y en qué unidad está.</p>
<ol start="3" type="1">
<li><strong>Decidir si importa la magnitud o la dirección</strong></li>
</ol>
<p>Intensidad del perfil (norma, euclidiana) frente a forma del perfil (coseno).</p>
<ol start="4" type="1">
<li><strong>Calcular las dos familias de medidas</strong></li>
</ol>
<p>Producto punto y norma primero; con ellas salen distancia y coseno.</p>
<ol start="5" type="1">
<li><strong>Revisar la escala</strong></li>
</ol>
<p>Si las <em>features</em> no comparten unidad o rango, estandarizar <strong>antes</strong> de medir distancias.</p>
<ol start="6" type="1">
<li><strong>Interpretar en el gráfico</strong></li>
</ol>
<p>Un coeficiente sin flechas o sin nube es fácil de malinterpretar.</p>
<p><strong>Criterio general:</strong> la métrica es una decisión de modelado, no un detalle de implementación.</p>
</section>
<section id="preparar-el-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparar-el-entorno">4. Preparar el entorno</h2>
<div id="c009" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:39.522564Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:39.522386Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.366197Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.365353Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb1-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Python:"</span>, sys.version.split()[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-7"></span>
<span id="cb1-8">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-9"></span>
<span id="cb1-10">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"figure.figsize"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-11">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"axes.grid"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb1-12">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grid.alpha"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span></span>
<span id="cb1-13"></span>
<span id="cb1-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Entorno listo: numpy, pandas, matplotlib."</span>)</span>
<span id="cb1-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pandas:"</span>, pd.__version__, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"| numpy:"</span>, np.__version__)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Python: 3.13.9
Entorno listo: numpy, pandas, matplotlib.
pandas: 2.3.3 | numpy: 2.3.5</code></pre>
</div>
</div>
<section id="funciones-de-visualización-definidas-una-sola-vez" class="level3">
<h3 class="anchored" data-anchor-id="funciones-de-visualización-definidas-una-sola-vez">Funciones de visualización (definidas una sola vez)</h3>
<p>Para no interrumpir la lectura de cada etapa con bloques largos de <code>matplotlib</code>, las figuras se definen aquí. Más adelante cada etapa <strong>llama</strong> a la función en una o dos líneas.</p>
<div id="c011" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.369145Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.368705Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.385420Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.384513Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_vectores_2d(nombres, X2, titulo, query<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>, query_nombre<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Consulta"</span>):</span>
<span id="cb3-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Flechas desde el origen: cada fila es un perfil en (lectura, práctica)."""</span></span>
<span id="cb3-3">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.5</span>))</span>
<span id="cb3-4">    colores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.cm.tab10(np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(nombres)))</span>
<span id="cb3-5">    desplazamiento <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana"</span>: (<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Elena"</span>: (<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.65</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>)}   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># evita que choquen las etiquetas</span></span>
<span id="cb3-6">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Se dibuja de la flecha más larga a la más corta: así Bruno no tapa a Ana (misma recta)</span></span>
<span id="cb3-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> rango, i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(np.argsort(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>np.linalg.norm(X2, axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))):</span>
<span id="cb3-8">        nombre, color <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nombres[i], colores[i]</span>
<span id="cb3-9">        x, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X2[i]</span>
<span id="cb3-10">        ax.arrow(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, x, y, head_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>, head_length<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>,</span>
<span id="cb3-11">                 length_includes_head<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rango)</span>
<span id="cb3-12">        dx, dy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> desplazamiento.get(nombre, (<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.15</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.15</span>))</span>
<span id="cb3-13">        ax.text(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> dx, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> dy, nombre, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color)</span>
<span id="cb3-14">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> query <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>:</span>
<span id="cb3-15">        ax.arrow(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, query[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], query[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], head_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>, head_length<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>,</span>
<span id="cb3-16">                 length_includes_head<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>)</span>
<span id="cb3-17">        ax.text(query[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.15</span>, query[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span>, query_nombre, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb3-18">    ax.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb3-19">    ax.axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb3-20">    ax.set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"equal"</span>, adjustable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box"</span>)</span>
<span id="cb3-21">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Horas de lectura / semana"</span>)</span>
<span id="cb3-22">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Horas de práctica / semana"</span>)</span>
<span id="cb3-23">    ax.set_title(titulo)</span>
<span id="cb3-24">    plt.tight_layout()</span>
<span id="cb3-25">    plt.show()</span>
<span id="cb3-26"></span>
<span id="cb3-27"></span>
<span id="cb3-28"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_puntos_y_consulta(nombres, X2, query, vecinos, titulo):</span>
<span id="cb3-29">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Nube 2D: consulta + segmentos hacia los vecinos elegidos por una métrica."""</span></span>
<span id="cb3-30">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.2</span>))</span>
<span id="cb3-31">    ax.scatter(X2[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X2[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">70</span>)</span>
<span id="cb3-32">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, nombre <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(nombres):</span>
<span id="cb3-33">        ax.annotate(nombre, (X2[i, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X2[i, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]), textcoords<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"offset points"</span>,</span>
<span id="cb3-34">                    xytext<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> nombre <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Elena"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>), fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span>
<span id="cb3-35">    ax.scatter(query[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], query[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">110</span>, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"*"</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Consulta"</span>)</span>
<span id="cb3-36">    ax.annotate(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Consulta"</span>, (query[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], query[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]), textcoords<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"offset points"</span>,</span>
<span id="cb3-37">                xytext<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>), fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span>
<span id="cb3-38">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> idx, estilo, etiqueta <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> vecinos:</span>
<span id="cb3-39">        ax.plot([query[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X2[idx, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]], [query[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], X2[idx, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]],</span>
<span id="cb3-40">                linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>estilo, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.8</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>etiqueta)</span>
<span id="cb3-41">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Horas de lectura / semana"</span>)</span>
<span id="cb3-42">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Horas de práctica / semana"</span>)</span>
<span id="cb3-43">    ax.set_title(titulo)</span>
<span id="cb3-44">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span>
<span id="cb3-45">    plt.tight_layout()</span>
<span id="cb3-46">    plt.show()</span>
<span id="cb3-47"></span>
<span id="cb3-48"></span>
<span id="cb3-49"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_barras_metricas(nombres, euclidiana, coseno, titulo):</span>
<span id="cb3-50">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Comparar distancia (menor = más cerca) y coseno (mayor = más parecido)."""</span></span>
<span id="cb3-51">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>), constrained_layout<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-52">    euclidiana, coseno <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(euclidiana), np.asarray(coseno)</span>
<span id="cb3-53">    gana_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.isclose(euclidiana, euclidiana.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>())</span>
<span id="cb3-54">    gana_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.isclose(coseno, coseno.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>())</span>
<span id="cb3-55">    barras_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].bar(nombres, euclidiana, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>np.where(gana_d, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span>))</span>
<span id="cb3-56">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].bar_label(barras_d, fmt<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%.2f</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-57">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Distancia euclidiana"</span>)</span>
<span id="cb3-58">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Separación respecto a la consulta"</span>)</span>
<span id="cb3-59">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].tick_params(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, rotation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)</span>
<span id="cb3-60">    barras_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].bar(nombres, coseno, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>np.where(gana_c, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span>))</span>
<span id="cb3-61">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].bar_label(barras_c, fmt<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%.4f</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-62">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylim(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.12</span>)</span>
<span id="cb3-63">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Similitud coseno"</span>)</span>
<span id="cb3-64">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Alineación respecto a la consulta"</span>)</span>
<span id="cb3-65">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].tick_params(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, rotation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)</span>
<span id="cb3-66">    fig.suptitle(titulo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (naranja: el más cercano según cada medida)"</span>)</span>
<span id="cb3-67">    plt.show()</span>
<span id="cb3-68"></span>
<span id="cb3-69"></span>
<span id="cb3-70"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_proyeccion(a, b, nombre_a, nombre_b, titulo):</span>
<span id="cb3-71">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Vector a, dirección b, proyección de a sobre b y residual."""</span></span>
<span id="cb3-72">    a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(a, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb3-73">    b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(b, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb3-74">    proj <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (np.dot(a, b) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.dot(b, b)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> b</span>
<span id="cb3-75">    residual <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> proj</span>
<span id="cb3-76">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.2</span>))</span>
<span id="cb3-77">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># La proyección va sobre la misma recta que b: se dibuja primero, ancha y translúcida</span></span>
<span id="cb3-78">    ax.plot([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, proj[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]], [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, proj[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span>,</span>
<span id="cb3-79">            solid_capstyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"round"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"proj de </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre_a<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> sobre </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre_b<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-80">    ax.scatter(proj[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], proj[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb3-81">    ax.arrow(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, b[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], b[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], head_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>, head_length<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>,</span>
<span id="cb3-82">             length_includes_head<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombre_b, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb3-83">    ax.arrow(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, a[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], a[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], head_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>, head_length<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>,</span>
<span id="cb3-84">             length_includes_head<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C2"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombre_a, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb3-85">    ax.plot([a[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], proj[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]], [a[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], proj[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]], linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">":"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>,</span>
<span id="cb3-86">            label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"residual"</span>)</span>
<span id="cb3-87">    ax.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb3-88">    ax.axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb3-89">    ax.set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"equal"</span>, adjustable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box"</span>)</span>
<span id="cb3-90">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Horas de lectura / semana"</span>)</span>
<span id="cb3-91">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Horas de práctica / semana"</span>)</span>
<span id="cb3-92">    ax.set_title(titulo)</span>
<span id="cb3-93">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"upper left"</span>)</span>
<span id="cb3-94">    plt.tight_layout()</span>
<span id="cb3-95">    plt.show()</span>
<span id="cb3-96">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> proj, residual</span></code></pre></div></div>
</div>
</section>
</section>
<section id="desarrollo-por-etapas" class="level2">
<h2 class="anchored" data-anchor-id="desarrollo-por-etapas">5. Desarrollo por etapas</h2>
<p>El hilo es uno solo: pasar de la tabla a la geometría, calcular las medidas a mano y con NumPy, y ver que <strong>la métrica decide quién es vecino</strong>. Cada etapa de código incluye una interpretación.</p>
<section id="etapa-1-dataset-como-matriz" class="level3">
<h3 class="anchored" data-anchor-id="etapa-1-dataset-como-matriz">Etapa 1: Dataset como matriz</h3>
<p>Se construye un conjunto <strong>pequeño y legible</strong> de seis estudiantes. Las <em>features</em> son <code>horas_lectura</code> y <code>horas_practica</code>. La puntuación del examen queda fuera de <img src="https://latex.codecogs.com/png.latex?X">: es el objetivo <img src="https://latex.codecogs.com/png.latex?y">, no una coordenada más del espacio de entrada.</p>
<p>Los perfiles están diseñados, no sorteados:</p>
<ul>
<li><strong>Ana</strong> y <strong>Bruno</strong> tienen la <strong>misma dirección</strong>; Bruno hace el doble de horas.</li>
<li><strong>Camila</strong> lee mucho y practica poco; <strong>Diego</strong> hace lo contrario.</li>
<li><strong>Elena</strong> está cerca de Ana en el plano.</li>
<li><strong>Fabián</strong> tiene un perfil bajo y casi plano.</li>
</ul>
<p><strong>Interpretación breve:</strong> un dataset sintético controlado permite saber de antemano qué debería salir en distancia y en coseno, y luego verificarlo con NumPy.</p>
<div id="c014" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.388159Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.387941Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.407152Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.406431Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">nombres <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bruno"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Camila"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Diego"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Elena"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Fabián"</span>]</span>
<span id="cb4-2">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(</span>
<span id="cb4-3">    [</span>
<span id="cb4-4">        [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>],   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Ana: perfil equilibrado</span></span>
<span id="cb4-5">        [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>],   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Bruno: misma dirección, doble magnitud</span></span>
<span id="cb4-6">        [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>],   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Camila: lectora</span></span>
<span id="cb4-7">        [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>],   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Diego: práctica</span></span>
<span id="cb4-8">        [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.8</span>],   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Elena: cercana a Ana</span></span>
<span id="cb4-9">        [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>],   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fabián: intensidad baja</span></span>
<span id="cb4-10">    ]</span>
<span id="cb4-11">)</span>
<span id="cb4-12">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">78.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">91.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">74.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">80.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">76.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">58.0</span>])</span>
<span id="cb4-13"></span>
<span id="cb4-14">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(X, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"horas_lectura"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"horas_practica"</span>], index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres)</span>
<span id="cb4-15">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"puntuacion_examen"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y</span>
<span id="cb4-16"></span>
<span id="cb4-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Tabla (lo que ve el analista):"</span>)</span>
<span id="cb4-18">display(df)</span>
<span id="cb4-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb4-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Matriz X (lo que ve el modelo):"</span>)</span>
<span id="cb4-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(X)</span>
<span id="cb4-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Forma de X:"</span>, X.shape, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"→ n observaciones × p features"</span>)</span>
<span id="cb4-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Vector y:"</span>, y)</span>
<span id="cb4-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Forma de y:"</span>, y.shape)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Tabla (lo que ve el analista):</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">horas_lectura</th>
<th data-quarto-table-cell-role="th">horas_practica</th>
<th data-quarto-table-cell-role="th">puntuacion_examen</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">Ana</th>
<td>4.0</td>
<td>4.0</td>
<td>78.0</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Bruno</th>
<td>8.0</td>
<td>8.0</td>
<td>91.0</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">Camila</th>
<td>8.0</td>
<td>2.0</td>
<td>74.0</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Diego</th>
<td>2.0</td>
<td>8.0</td>
<td>80.0</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">Elena</th>
<td>3.6</td>
<td>3.8</td>
<td>76.0</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Fabián</th>
<td>1.0</td>
<td>1.2</td>
<td>58.0</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>
Matriz X (lo que ve el modelo):
[[4.  4. ]
 [8.  8. ]
 [8.  2. ]
 [2.  8. ]
 [3.6 3.8]
 [1.  1.2]]
Forma de X: (6, 2) → n observaciones × p features
Vector y: [78. 91. 74. 80. 76. 58.]
Forma de y: (6,)</code></pre>
</div>
</div>
<p><strong>Lectura de la Etapa 1.</strong> <code>df</code> es la vista humana: nombres, unidades, un objetivo. <code>X</code> es la vista del algoritmo: solo números, forma <img src="https://latex.codecogs.com/png.latex?(6,%202)">. Vectorizar, en la práctica, es elegir qué columnas entran a <img src="https://latex.codecogs.com/png.latex?X"> y en qué orden. Cambiar el orden de las columnas <strong>no</strong> cambia las distancias si se aplica el mismo orden a todas las filas; mezclar el objetivo dentro de <img src="https://latex.codecogs.com/png.latex?X"> sí cambia la geometría —y suele ser un error.</p>
<p><strong>Conexión con ML:</strong> entrenar es, casi siempre, <code>modelo.fit(X, y)</code>. Esta etapa nombra esos dos objetos.</p>
</section>
<section id="etapa-2-vectorización-la-fila-es-un-punto" class="level3">
<h3 class="anchored" data-anchor-id="etapa-2-vectorización-la-fila-es-un-punto">Etapa 2: Vectorización — la fila es un punto</h3>
<p>Cada fila <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bx%7D_i"> se dibuja como una <strong>flecha desde el origen</strong>. El origen <img src="https://latex.codecogs.com/png.latex?(0,0)"> significa “cero horas de lectura y cero de práctica”: no es un estudiante real, es el ancla geométrica.</p>
<p><strong>Pregunta guía (antes de ejecutar el gráfico):</strong> ¿qué flechas se ven sobre la misma recta? ¿cuáles apuntan a cuadrantes distintos aunque midan “muchas horas” en total?</p>
<div id="c017" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.409894Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.409581Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.547431Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.547006Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">graficar_vectores_2d(</span>
<span id="cb7-2">    nombres,</span>
<span id="cb7-3">    X,</span>
<span id="cb7-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cada estudiante es un vector en el plano lectura–práctica"</span>,</span>
<span id="cb7-5">)</span>
<span id="cb7-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Normas (longitud de cada flecha):"</span>)</span>
<span id="cb7-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, vec <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(nombres, X):</span>
<span id="cb7-8">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  ||x|| = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>linalg<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>norm(vec)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   x = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>vec<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/06-representacion-vectorial-datos/index_files/figure-html/cell-5-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Normas (longitud de cada flecha):
  Ana       ||x|| = 5.657   x = [4. 4.]
  Bruno     ||x|| = 11.314   x = [8. 8.]
  Camila    ||x|| = 8.246   x = [8. 2.]
  Diego     ||x|| = 8.246   x = [2. 8.]
  Elena     ||x|| = 5.235   x = [3.6 3.8]
  Fabián    ||x|| = 1.562   x = [1.  1.2]</code></pre>
</div>
</div>
<p><strong>Después del gráfico.</strong> Ana y Bruno están <strong>sobre la misma semirrecta</strong>: <img src="https://latex.codecogs.com/png.latex?8,8%20=%202%5Ctimes(4,4)">. Camila y Diego tienen longitudes parecidas entre sí, pero <strong>ángulos distintos</strong>. Elena casi coincide con Ana. Fabián apunta cerca de Ana y Bruno, pero es corto.</p>
<p>Vectorizar no añade información nueva; <strong>cambia la pregunta</strong>: ya no es “cuál es la media de lectura”, sino “dónde está esta observación en el espacio y a quién se parece”.</p>
</section>
<section id="reto-técnico" class="level3">
<h3 class="anchored" data-anchor-id="reto-técnico">Reto técnico</h3>
<p>Sin usar el gráfico, decide si <code>np.array([6.0, 6.0])</code> quedaría sobre la recta de Ana–Bruno. Luego compruébalo: su coseno con Ana debe ser <img src="https://latex.codecogs.com/png.latex?1">.</p>
</section>
<section id="etapa-3-producto-punto" class="level3">
<h3 class="anchored" data-anchor-id="etapa-3-producto-punto">Etapa 3: Producto punto</h3>
<p><strong>Idea central.</strong> El producto punto resume, en un solo número, cuánto se <em>empujan</em> dos vectores en la misma dirección.</p>
<p>Cálculo coordenado para Ana <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Ba%7D=(4,4)"> y Bruno <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bb%7D=(8,8)">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%204%5Ccdot%208%20+%204%5Ccdot%208%20=%2064%20"></p>
<p>Y la lectura geométrica:</p>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Cmathbf%7Ba%7D%5Ccdot%5Cmathbf%7Bb%7D%20=%20%5C%7C%5Cmathbf%7Ba%7D%5C%7C%5C,%5C%7C%5Cmathbf%7Bb%7D%5C%7C%5Ccos%5Ctheta%20"></p>
<p>Si <img src="https://latex.codecogs.com/png.latex?%5Ccos%5Ctheta=1"> (misma dirección), el producto punto es exactamente el producto de las longitudes.</p>
<p><strong>Conexión con ML:</strong> el producto punto reaparece en proyección, en la capa lineal de una red ($ + b $) y en la atención de <em>transformers</em>. Aquí se queda en su versión descriptiva.</p>
<div id="c020" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.551053Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.550866Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.561493Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.561058Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> producto_punto(a, b):</span>
<span id="cb9-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.dot(a, b))</span>
<span id="cb9-3"></span>
<span id="cb9-4"></span>
<span id="cb9-5">ana, bruno, camila <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]</span>
<span id="cb9-6"></span>
<span id="cb9-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"A mano (Ana · Bruno):"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb9-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NumPy  (Ana · Bruno):"</span>, producto_punto(ana, bruno))</span>
<span id="cb9-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana · Camila:"</span>, producto_punto(ana, camila))</span>
<span id="cb9-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana · Diego :"</span>, producto_punto(ana, X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>]))</span>
<span id="cb9-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb9-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Verificación geométrica Ana · Bruno:"</span>)</span>
<span id="cb9-13">na, nb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.norm(ana), np.linalg.norm(bruno)</span>
<span id="cb9-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  ||Ana|| = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>na<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, ||Bruno|| = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nb<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb9-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  ||Ana|| × ||Bruno|| × cos(0) = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>na <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> nb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb9-16"></span>
<span id="cb9-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb9-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Matriz de Gram G = X Xᵀ  (producto interno entre cada par de estudiantes):"</span>)</span>
<span id="cb9-19">G <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> X.T</span>
<span id="cb9-20">gram <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(G, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres)</span>
<span id="cb9-21">display(gram)</span>
<span id="cb9-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La diagonal de G son las normas al cuadrado: ||x_i||²."</span>)</span>
<span id="cb9-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Diagonal:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.diag(G), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>A mano (Ana · Bruno): 64
NumPy  (Ana · Bruno): 64.0
Ana · Camila: 40.0
Ana · Diego : 40.0

Verificación geométrica Ana · Bruno:
  ||Ana|| = 5.6569, ||Bruno|| = 11.3137
  ||Ana|| × ||Bruno|| × cos(0) = 64.0000

Matriz de Gram G = X Xᵀ  (producto interno entre cada par de estudiantes):</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">Ana</th>
<th data-quarto-table-cell-role="th">Bruno</th>
<th data-quarto-table-cell-role="th">Camila</th>
<th data-quarto-table-cell-role="th">Diego</th>
<th data-quarto-table-cell-role="th">Elena</th>
<th data-quarto-table-cell-role="th">Fabián</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">Ana</th>
<td>32.0</td>
<td>64.0</td>
<td>40.0</td>
<td>40.0</td>
<td>29.60</td>
<td>8.80</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Bruno</th>
<td>64.0</td>
<td>128.0</td>
<td>80.0</td>
<td>80.0</td>
<td>59.20</td>
<td>17.60</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">Camila</th>
<td>40.0</td>
<td>80.0</td>
<td>68.0</td>
<td>32.0</td>
<td>36.40</td>
<td>10.40</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Diego</th>
<td>40.0</td>
<td>80.0</td>
<td>32.0</td>
<td>68.0</td>
<td>37.60</td>
<td>11.60</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">Elena</th>
<td>29.6</td>
<td>59.2</td>
<td>36.4</td>
<td>37.6</td>
<td>27.40</td>
<td>8.16</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Fabián</th>
<td>8.8</td>
<td>17.6</td>
<td>10.4</td>
<td>11.6</td>
<td>8.16</td>
<td>2.44</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>La diagonal de G son las normas al cuadrado: ||x_i||².
Diagonal: [ 32.   128.    68.    68.    27.4    2.44]</code></pre>
</div>
</div>
<p><strong>Interpretación.</strong> Ana·Bruno <img src="https://latex.codecogs.com/png.latex?=64"> es grande porque están alineados <em>y</em> Bruno es largo. Ana·Camila <img src="https://latex.codecogs.com/png.latex?=40"> es menor: Camila también “tiene horas”, pero parte de su vector apunta a un eje que Ana no comparte tanto. El producto punto <strong>mezcla</strong> tamaño y ángulo; por eso no basta para decir “se parecen” si las normas difieren.</p>
<p>La <strong>matriz de Gram</strong> <img src="https://latex.codecogs.com/png.latex?G=XX%5E%7B%5Ctop%7D"> concentra todos los productos internos. <img src="https://latex.codecogs.com/png.latex?G_%7Bik%7D=%5Cmathbf%7Bx%7D_i%5Ccdot%5Cmathbf%7Bx%7D_k">. En la diagonal aparecen <img src="https://latex.codecogs.com/png.latex?%5C%7C%5Cmathbf%7Bx%7D_i%5C%7C%5E2">. Es el objeto algebraico que luego reaparece en <em>kernel methods</em>. Su “pariente” <img src="https://latex.codecogs.com/png.latex?X%5E%7B%5Ctop%7DX"> (<img src="https://latex.codecogs.com/png.latex?p%5Ctimes%20p">) compara <strong>columnas</strong> en lugar de filas: con las columnas centradas y dividido por <img src="https://latex.codecogs.com/png.latex?n-1">, es la <strong>matriz de covarianzas</strong> que usa PCA en la Sesión 7.</p>
</section>
<section id="etapa-4-norma-el-tamaño-del-perfil" class="level3">
<h3 class="anchored" data-anchor-id="etapa-4-norma-el-tamaño-del-perfil">Etapa 4: Norma — el tamaño del perfil</h3>
<p><strong>Idea central.</strong> La norma euclidiana responde <em>qué tan largo</em> es el vector, no <em>hacia dónde</em> va.</p>
<p><img src="https://latex.codecogs.com/png.latex?%20%5C%7C%5Cmathbf%7Bx%7D%5C%7C_2%20=%20%5Csqrt%7Bx_1%5E2%20+%20x_2%5E2%7D%20"></p>
<p>Ana: <img src="https://latex.codecogs.com/png.latex?%5Csqrt%7B16+16%7D=%5Csqrt%7B32%7D%5Capprox%205.66">. Bruno: <img src="https://latex.codecogs.com/png.latex?%5Csqrt%7B64+64%7D=%5Csqrt%7B128%7D%5Capprox%2011.31">, el doble.</p>
<p>Dos vectores pueden tener la <strong>misma norma</strong> y direcciones opuestas en el trade-off lectura/práctica (Camila frente a Diego, aproximadamente).</p>
<p>Además de <img src="https://latex.codecogs.com/png.latex?L_2">, la norma <img src="https://latex.codecogs.com/png.latex?L_1"> suma valores absolutos:</p>
<p><img src="https://latex.codecogs.com/png.latex?%20%5C%7C%5Cmathbf%7Bx%7D%5C%7C_1%20=%20%5Csum_%7Bj=1%7D%5E%7Bp%7D%7Cx_j%7C%20"></p>
<p><img src="https://latex.codecogs.com/png.latex?L_2"> penaliza más las coordenadas grandes (por el cuadrado). <img src="https://latex.codecogs.com/png.latex?L_1"> trata cada unidad por igual. En regularización, <img src="https://latex.codecogs.com/png.latex?L_2"> (Ridge) encoge coeficientes; <img src="https://latex.codecogs.com/png.latex?L_1"> (Lasso) favorece ceros.</p>
<div id="c023" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.563263Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.563093Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.568111Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.567717Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> norma(v):</span>
<span id="cb12-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.sqrt(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(np.asarray(v) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)))</span>
<span id="cb12-3"></span>
<span id="cb12-4"></span>
<span id="cb12-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Norma a mano (Ana):"</span>, np.sqrt(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb12-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Norma NumPy  (Ana):"</span>, np.linalg.norm(ana), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"| función propia:"</span>, norma(ana))</span>
<span id="cb12-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb12-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, vec <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(nombres, X):</span>
<span id="cb12-9">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  norma = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>norma(vec)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb12-10"></span>
<span id="cb12-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb12-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Camila y Diego (normas parecidas, direcciones distintas):"</span>)</span>
<span id="cb12-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  Camila"</span>, X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"norma"</span>, norma(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]))</span>
<span id="cb12-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  Diego "</span>, X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"norma"</span>, norma(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>]))</span>
<span id="cb12-15"></span>
<span id="cb12-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb12-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nombre'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  L2      L1      L1/L2"</span>)</span>
<span id="cb12-18"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, vec <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(nombres, X):</span>
<span id="cb12-19">    l2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.norm(vec, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">ord</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb12-20">    l1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.norm(vec, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">ord</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb12-21">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>l2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:6.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>l1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:6.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>l1<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>l2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:6.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Norma a mano (Ana): 5.656854249492381
Norma NumPy  (Ana): 5.656854249492381 | función propia: 5.656854249492381

Ana       norma = 5.657
Bruno     norma = 11.314
Camila    norma = 8.246
Diego     norma = 8.246
Elena     norma = 5.235
Fabián    norma = 1.562

Camila y Diego (normas parecidas, direcciones distintas):
  Camila [8. 2.] norma 8.246211251235321
  Diego  [2. 8.] norma 8.246211251235321

nombre    L2      L1      L1/L2
Ana        5.657   8.000   1.414
Bruno     11.314  16.000   1.414
Camila     8.246  10.000   1.213
Diego      8.246  10.000   1.213
Elena      5.235   7.400   1.414
Fabián     1.562   2.200   1.408</code></pre>
</div>
</div>
<p><strong>Después de los números.</strong> Bruno no es “otro tipo de estudiante”: es el <strong>mismo perfil, más intenso</strong>. Fabián sí comparte dirección con Ana, pero su norma es pequeña. Si un modelo usa solo la distancia euclidiana, Fabián puede quedar lejos de Ana <em>aunque apunte igual</em>. Esa distinción se vuelve precisa en las dos etapas siguientes.</p>
<p><strong>Conexión con ML:</strong> regularización <img src="https://latex.codecogs.com/png.latex?L_2">, normalización de embeddings y <em>weight decay</em> hablan de esta misma longitud.</p>
<p>Camila y Diego empatan en <img src="https://latex.codecogs.com/png.latex?L_2"> y también en <img src="https://latex.codecogs.com/png.latex?L_1"> (<img src="https://latex.codecogs.com/png.latex?8+2=10">): aquí el contraste no está en el tamaño, está en la <strong>dirección</strong>.</p>
</section>
<section id="etapa-5-vector-unitario-y-cauchyschwarz" class="level3">
<h3 class="anchored" data-anchor-id="etapa-5-vector-unitario-y-cauchyschwarz">Etapa 5: Vector unitario y Cauchy–Schwarz</h3>
<p>El vector unitario de <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Ba%7D"> es <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Cmathbf%7Ba%7D%7D=%5Cmathbf%7Ba%7D/%5C%7C%5Cmathbf%7Ba%7D%5C%7C">. Dos vectores en la misma semirrecta —Ana y Bruno— deben producir <strong>el mismo</strong> unitario.</p>
<p>Cauchy–Schwarz afirma <img src="https://latex.codecogs.com/png.latex?%7C%5Cmathbf%7Ba%7D%5Ccdot%5Cmathbf%7Bb%7D%7C%5Cle%5C%7C%5Cmathbf%7Ba%7D%5C%7C%5C,%5C%7C%5Cmathbf%7Bb%7D%5C%7C">. El cociente es exactamente <img src="https://latex.codecogs.com/png.latex?%7C%5Ccos%5Ctheta%7C">. La igualdad vale cuando un vector es múltiplo del otro.</p>
<p><strong>Antes de ejecutar:</strong> el unitario de Ana y el de Bruno deben coincidir; el de Camila, no. El valor <img src="https://latex.codecogs.com/png.latex?%7C%5Cmathbf%7Ba%7D%5Ccdot%5Cmathbf%7Bb%7D%7C/%5C%7C%5Cmathbf%7Ba%7D%5C%7C%5C%7C%5Cmathbf%7Bb%7D%5C%7C"> no puede superar <img src="https://latex.codecogs.com/png.latex?1">.</p>
<div id="c026" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.569764Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.569604Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.575297Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.574890Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> unitario(v):</span>
<span id="cb14-2">    v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(v, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb14-3">    n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.norm(v)</span>
<span id="cb14-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb14-5">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">raise</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">ValueError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"el vector nulo no tiene dirección"</span>)</span>
<span id="cb14-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n</span>
<span id="cb14-7"></span>
<span id="cb14-8"></span>
<span id="cb14-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Vectores unitarios (deben tener norma 1):"</span>)</span>
<span id="cb14-10"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, vec <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(nombres, X):</span>
<span id="cb14-11">    u <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> unitario(vec)</span>
<span id="cb14-12">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  û = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(u, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   ||û|| = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>linalg<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>norm(u)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.6f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb14-13"></span>
<span id="cb14-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb14-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"¿Ana y Bruno comparten dirección?  ||û_Ana − û_Bruno|| ="</span>,</span>
<span id="cb14-16">      np.linalg.norm(unitario(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> unitario(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])))</span>
<span id="cb14-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"¿Ana y Camila comparten dirección? ||û_Ana − û_Camila|| ="</span>,</span>
<span id="cb14-18">      np.linalg.norm(unitario(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> unitario(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])))</span>
<span id="cb14-19"></span>
<span id="cb14-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb14-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cauchy–Schwarz: |a·b|  ≤  ||a|| ||b||"</span>)</span>
<span id="cb14-22">pares <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bruno"</span>, X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]),</span>
<span id="cb14-23">         (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Camila"</span>, X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]),</span>
<span id="cb14-24">         (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Camila"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Diego"</span>, X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>])]</span>
<span id="cb14-25"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> na, nb, a, b <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> pares:</span>
<span id="cb14-26">    izq <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(np.dot(a, b))</span>
<span id="cb14-27">    der <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.norm(a) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.linalg.norm(b)</span>
<span id="cb14-28">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>na<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">–</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nb<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">:  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>izq<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  ≤  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>der<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   holgura = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>der <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> izq<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Vectores unitarios (deben tener norma 1):
  Ana       û = [0.7071 0.7071]   ||û|| = 1.000000
  Bruno     û = [0.7071 0.7071]   ||û|| = 1.000000
  Camila    û = [0.9701 0.2425]   ||û|| = 1.000000
  Diego     û = [0.2425 0.9701]   ||û|| = 1.000000
  Elena     û = [0.6877 0.726 ]   ||û|| = 1.000000
  Fabián    û = [0.6402 0.7682]   ||û|| = 1.000000

¿Ana y Bruno comparten dirección?  ||û_Ana − û_Bruno|| = 0.0
¿Ana y Camila comparten dirección? ||û_Ana − û_Camila|| = 0.533867163791623

Cauchy–Schwarz: |a·b|  ≤  ||a|| ||b||
  Ana–Bruno:  64.0000  ≤  64.0000   holgura = 0.0000
  Ana–Camila:  40.0000  ≤  46.6476   holgura = 6.6476
  Camila–Diego:  32.0000  ≤  68.0000   holgura = 36.0000</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> Ana y Bruno tienen holgura <img src="https://latex.codecogs.com/png.latex?0">: son el caso de igualdad, <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Cmathbf%7Ba%7D%7D=%5Chat%7B%5Cmathbf%7Bb%7D%7D">. Camila–Diego dejan holgura positiva: no son múltiplos. El unitario es la versión académica de “quitar la norma”; el coseno es el producto punto de dos unitarios:</p>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Ccos%5Ctheta%20=%20%5Chat%7B%5Cmathbf%7Ba%7D%7D%5Ccdot%5Chat%7B%5Cmathbf%7Bb%7D%7D%20"></p>
</section>
<section id="etapa-6-distancia-euclidiana" class="level3">
<h3 class="anchored" data-anchor-id="etapa-6-distancia-euclidiana">Etapa 6: Distancia euclidiana</h3>
<p><img src="https://latex.codecogs.com/png.latex?%20d(%5Cmathbf%7Ba%7D,%5Cmathbf%7Bb%7D)%20=%20%5Csqrt%7B%5Csum_%7Bj=1%7D%5E%7Bp%7D(a_j-b_j)%5E2%7D%20=%20%5C%7C%5Cmathbf%7Ba%7D-%5Cmathbf%7Bb%7D%5C%7C_2%20"></p>
<p>Mide el <strong>segmento que une dos puntos</strong>, no el ángulo entre flechas.</p>
<p><strong>Pregunta guía (antes de los números):</strong> ¿quién debería quedar más cerca de Ana — Bruno (misma dirección, el doble de horas) o Elena (casi el mismo punto)?</p>
<div id="c029" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.576856Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.576704Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.580773Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.580353Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> distancia_euclidiana(a, b):</span>
<span id="cb16-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.linalg.norm(np.asarray(a) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> np.asarray(b)))</span>
<span id="cb16-3"></span>
<span id="cb16-4"></span>
<span id="cb16-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Distancia a Ana"</span>)</span>
<span id="cb16-6">d_ana <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb16-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, vec <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(nombres, X):</span>
<span id="cb16-8">    d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> distancia_euclidiana(ana, vec)</span>
<span id="cb16-9">    d_ana.append(d)</span>
<span id="cb16-10">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  d = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>d<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb16-11"></span>
<span id="cb16-12">orden <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argsort(d_ana)</span>
<span id="cb16-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb16-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ranking (más cercana → más lejana):"</span>)</span>
<span id="cb16-15"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k, idx <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(orden, start<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>):</span>
<span id="cb16-16">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> nombres[idx] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana"</span>:</span>
<span id="cb16-17">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">continue</span></span>
<span id="cb16-18">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">. </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombres[idx]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  d = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>d_ana[idx]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Distancia a Ana
  Ana       d = 0.000
  Bruno     d = 5.657
  Camila    d = 4.472
  Diego     d = 4.472
  Elena     d = 0.447
  Fabián    d = 4.104

Ranking (más cercana → más lejana):
  1. Elena     d = 0.447
  2. Fabián    d = 4.104
  3. Camila    d = 4.472
  4. Diego     d = 4.472
  5. Bruno     d = 5.657</code></pre>
</div>
</div>
<p><strong>Interpretación.</strong> Elena gana de lejos: está a décimas de Ana. Bruno, pese a ser “el mismo perfil”, queda <strong>el más lejano de todos</strong> (5.66), más que Camila, Diego y Fabián, porque el doble de horas lo desplaza por el plano. La euclidiana <strong>penaliza la diferencia de intensidad</strong>.</p>
<p><strong>Conexión con ML:</strong> un 1-NN euclidiano diría que el vecino de Ana es Elena, no Bruno. Eso puede ser correcto si “parecido” significa <em>mismas horas</em>, e incorrecto si significa <em>misma receta de hábitos</em>.</p>
</section>
<section id="etapa-7-similitud-coseno-y-el-contraste-que-importa" class="level3">
<h3 class="anchored" data-anchor-id="etapa-7-similitud-coseno-y-el-contraste-que-importa">Etapa 7: Similitud coseno — y el contraste que importa</h3>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Ccos%5Ctheta%20=%20%5Cfrac%7B%5Cmathbf%7Ba%7D%5Ccdot%5Cmathbf%7Bb%7D%7D%7B%5C%7C%5Cmathbf%7Ba%7D%5C%7C%5C,%5C%7C%5Cmathbf%7Bb%7D%5C%7C%7D%20"></p>
<p><strong>Idea central (el contraste de esta sesión).</strong> Ana y Bruno tienen <img src="https://latex.codecogs.com/png.latex?%5Ccos%5Ctheta%20=%201"> y, al mismo tiempo, una distancia euclidiana <strong>grande</strong>. Misma historia, dos métricas.</p>
<p><strong>Pregunta guía (antes de ejecutar):</strong> si ordenas a los compañeros de Ana por coseno, ¿Bruno sube al primer lugar? ¿Fabián, tan corto, queda alto o bajo?</p>
<div id="c032" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.582276Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.582120Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.590011Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.589607Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> similitud_coseno(a, b):</span>
<span id="cb18-2">    a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(a, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb18-3">    b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(b, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb18-4">    denom <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.norm(a) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.linalg.norm(b)</span>
<span id="cb18-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> denom <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb18-6">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.nan</span>
<span id="cb18-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.dot(a, b) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> denom)</span>
<span id="cb18-8"></span>
<span id="cb18-9"></span>
<span id="cb18-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Coseno con Ana"</span>)</span>
<span id="cb18-11">c_ana <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb18-12"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, vec <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(nombres, X):</span>
<span id="cb18-13">    c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> similitud_coseno(ana, vec)</span>
<span id="cb18-14">    c_ana.append(c)</span>
<span id="cb18-15">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  cos = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>c<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb18-16"></span>
<span id="cb18-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb18-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Verificación Ana–Bruno (deben ser 1):"</span>, similitud_coseno(ana, bruno))</span>
<span id="cb18-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ángulo Ana–Bruno (grados):"</span>, np.degrees(np.arccos(np.clip(similitud_coseno(ana, bruno), <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))))</span>
<span id="cb18-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ángulo Ana–Camila (grados):"</span>, np.degrees(np.arccos(np.clip(similitud_coseno(ana, camila), <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))))</span>
<span id="cb18-21"></span>
<span id="cb18-22">tabla <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb18-23">    {</span>
<span id="cb18-24">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"distancia_a_Ana"</span>: d_ana,</span>
<span id="cb18-25">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"coseno_con_Ana"</span>: c_ana,</span>
<span id="cb18-26">    },</span>
<span id="cb18-27">    index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres,</span>
<span id="cb18-28">)</span>
<span id="cb18-29"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb18-30">display(tabla.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Coseno con Ana
  Ana       cos = 1.0000
  Bruno     cos = 1.0000
  Camila    cos = 0.8575
  Diego     cos = 0.8575
  Elena     cos = 0.9996
  Fabián    cos = 0.9959

Verificación Ana–Bruno (deben ser 1): 0.9999999999999998
Ángulo Ana–Bruno (grados): 1.2074182697257333e-06
Ángulo Ana–Camila (grados): 30.963756532073536
</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">distancia_a_Ana</th>
<th data-quarto-table-cell-role="th">coseno_con_Ana</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">Ana</th>
<td>0.000</td>
<td>1.000</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Bruno</th>
<td>5.657</td>
<td>1.000</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">Camila</th>
<td>4.472</td>
<td>0.857</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Diego</th>
<td>4.472</td>
<td>0.857</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">Elena</th>
<td>0.447</td>
<td>1.000</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Fabián</th>
<td>4.104</td>
<td>0.996</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p><strong>Después de la tabla.</strong> Bruno empataría el primer lugar en coseno (con Ana misma) y queda lejos en distancia. Fabián, de norma chica, <strong>sí se parece en dirección</strong> a Ana: el coseno lo reconoce; la euclidiana lo aleja. Camila y Diego se separan de Ana en ángulo: el coseno baja aunque “sumen muchas horas”.</p>
<p>Ese es el análogo geométrico de “misma media, distinta dispersión” (Sesiones 2–4): <strong>el mismo par de personas, dos conclusiones</strong>.</p>
</section>
<section id="reto-técnico-1" class="level3">
<h3 class="anchored" data-anchor-id="reto-técnico-1">Reto técnico</h3>
<p>Calcula a mano el coseno entre Camila <img src="https://latex.codecogs.com/png.latex?(8,2)"> y Diego <img src="https://latex.codecogs.com/png.latex?(2,8)">. Interpreta el resultado en una frase: ¿comparten intensidad, dirección, ambas o ninguna?</p>
</section>
<section id="etapa-8-ortogonalidad-y-proyección" class="level3">
<h3 class="anchored" data-anchor-id="etapa-8-ortogonalidad-y-proyección">Etapa 8: Ortogonalidad y proyección</h3>
<p>Un par es ortogonal si su producto punto es cero. En el plano, <img src="https://latex.codecogs.com/png.latex?(1,0)"> y <img src="https://latex.codecogs.com/png.latex?(0,1)"> son el ejemplo canónico. Camila <img src="https://latex.codecogs.com/png.latex?(8,2)"> no es ortogonal a Diego <img src="https://latex.codecogs.com/png.latex?(2,8)">: <img src="https://latex.codecogs.com/png.latex?16+16=32%5Cneq%200">. Sí se puede construir un perfil <strong>ortogonal a Ana</strong> <img src="https://latex.codecogs.com/png.latex?(4,4)">: por ejemplo <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bv%7D=(4,-4)">, porque <img src="https://latex.codecogs.com/png.latex?16-16=0">.</p>
<p>La proyección de Camila sobre la recta de Ana responde: <em>si el único eje permitido fuera “equilibrio lectura–práctica”, ¿qué parte del perfil de Camila quedaría?</em></p>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Cmathrm%7Bproj%7D_%7B%5Cmathbf%7Ba%7D%7D(%5Cmathbf%7Bc%7D)%20=%20%5Cfrac%7B%5Cmathbf%7Bc%7D%5Ccdot%5Cmathbf%7Ba%7D%7D%7B%5C%7C%5Cmathbf%7Ba%7D%5C%7C%5E2%7D%5C,%5Cmathbf%7Ba%7D%20"></p>
<p><strong>Antes del gráfico:</strong> el residual debe ser perpendicular a Ana (producto punto <img src="https://latex.codecogs.com/png.latex?%5Capprox%200">).</p>
<div id="c035" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.591568Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.591411Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.709857Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.709271Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">ana, camila <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]</span>
<span id="cb20-2">ortogonal_a_ana <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>])</span>
<span id="cb20-3"></span>
<span id="cb20-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana · (4, −4) ="</span>, np.dot(ana, ortogonal_a_ana), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (ortogonal si es 0)"</span>)</span>
<span id="cb20-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Camila · Diego ="</span>, np.dot(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>]), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (no son ortogonales)"</span>)</span>
<span id="cb20-6"></span>
<span id="cb20-7">proj, residual <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> graficar_proyeccion(</span>
<span id="cb20-8">    camila, ana, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Camila"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana"</span>,</span>
<span id="cb20-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Proyección de Camila sobre la recta de Ana"</span>,</span>
<span id="cb20-10">)</span>
<span id="cb20-11"></span>
<span id="cb20-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"proj_Ana(Camila) ="</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(proj, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb20-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"residual         ="</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(residual, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb20-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana · residual   ="</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.dot(ana, residual), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (debe ser ~0)"</span>)</span>
<span id="cb20-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Teorema de Pitágoras: ||Camila||² = ||proj||² + ||residual||²"</span>)</span>
<span id="cb20-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  "</span>, np.dot(camila, camila), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"="</span>, np.dot(proj, proj) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.dot(residual, residual))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Ana · (4, −4) = 0.0   (ortogonal si es 0)
Camila · Diego = 32.0   (no son ortogonales)</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/06-representacion-vectorial-datos/index_files/figure-html/cell-11-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>proj_Ana(Camila) = [5. 5.]
residual         = [ 3. -3.]
Ana · residual   = 0.0   (debe ser ~0)
Teorema de Pitágoras: ||Camila||² = ||proj||² + ||residual||²
   68.0 = 68.0</code></pre>
</div>
</div>
<p><strong>Después del gráfico.</strong> La flecha punteada es lo que Ana “explica” de Camila: la componente alineada con el perfil equilibrado. El residual (puntos) es el exceso de lectura frente a práctica. Como <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Ba%7D%5Ccdot%5Cmathrm%7Bresidual%7D=0">, esa parte <strong>no</strong> se ve desde la recta de Ana.</p>
<p>En un modelo lineal, el residual es el error; en PCA, con los datos <strong>centrados</strong> (restando la media de cada columna), se elige el eje que <strong>maximiza</strong> la norma de las proyecciones, es decir, la varianza proyectada.</p>
</section>
<section id="etapa-9-interpretación-geométrica-conjunta" class="level3">
<h3 class="anchored" data-anchor-id="etapa-9-interpretación-geométrica-conjunta">Etapa 9: Interpretación geométrica conjunta</h3>
<p>Se dibujan de nuevo las flechas y se resume el diccionario visual: <strong>longitud = norma</strong>, <strong>apertura = ángulo</strong>, <strong>segmento entre puntas = distancia</strong>.</p>
<div id="c038" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.711801Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.711615Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.839885Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.839419Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1">graficar_vectores_2d(</span>
<span id="cb23-2">    nombres,</span>
<span id="cb23-3">    X,</span>
<span id="cb23-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Geometría: misma recta (Ana–Bruno), casi la misma (Elena, Fabián) frente a otras direcciones"</span>,</span>
<span id="cb23-5">)</span>
<span id="cb23-6"></span>
<span id="cb23-7">resumen <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb23-8">    {</span>
<span id="cb23-9">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"par"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana–Bruno"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana–Elena"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana–Fabián"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ana–Camila"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Camila–Diego"</span>],</span>
<span id="cb23-10">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"euclidiana"</span>: [</span>
<span id="cb23-11">            distancia_euclidiana(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]),</span>
<span id="cb23-12">            distancia_euclidiana(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>]),</span>
<span id="cb23-13">            distancia_euclidiana(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]),</span>
<span id="cb23-14">            distancia_euclidiana(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]),</span>
<span id="cb23-15">            distancia_euclidiana(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>]),</span>
<span id="cb23-16">        ],</span>
<span id="cb23-17">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"coseno"</span>: [</span>
<span id="cb23-18">            similitud_coseno(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]),</span>
<span id="cb23-19">            similitud_coseno(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>]),</span>
<span id="cb23-20">            similitud_coseno(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]),</span>
<span id="cb23-21">            similitud_coseno(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]),</span>
<span id="cb23-22">            similitud_coseno(X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], X[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>]),</span>
<span id="cb23-23">        ],</span>
<span id="cb23-24">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lectura"</span>: [</span>
<span id="cb23-25">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Misma dirección; distinta intensidad"</span>,</span>
<span id="cb23-26">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cercanos en el plano"</span>,</span>
<span id="cb23-27">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Casi la misma dirección; Fabián es corto"</span>,</span>
<span id="cb23-28">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ángulo abierto; Camila es lectora"</span>,</span>
<span id="cb23-29">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Trade-off opuesto lectura/práctica"</span>,</span>
<span id="cb23-30">        ],</span>
<span id="cb23-31">    }</span>
<span id="cb23-32">)</span>
<span id="cb23-33">display(resumen.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/06-representacion-vectorial-datos/index_files/figure-html/cell-12-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">par</th>
<th data-quarto-table-cell-role="th">euclidiana</th>
<th data-quarto-table-cell-role="th">coseno</th>
<th data-quarto-table-cell-role="th">lectura</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>Ana–Bruno</td>
<td>5.657</td>
<td>1.000</td>
<td>Misma dirección; distinta intensidad</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>Ana–Elena</td>
<td>0.447</td>
<td>1.000</td>
<td>Cercanos en el plano</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>Ana–Fabián</td>
<td>4.104</td>
<td>0.996</td>
<td>Casi la misma dirección; Fabián es corto</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>Ana–Camila</td>
<td>4.472</td>
<td>0.857</td>
<td>Ángulo abierto; Camila es lectora</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>Camila–Diego</td>
<td>8.485</td>
<td>0.471</td>
<td>Trade-off opuesto lectura/práctica</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p><strong>Cómo leer la tabla.</strong> Si la pregunta es “¿quién estudia <em>como</em> Ana, aunque sea más o menos horas?”, mira el <strong>coseno</strong>. Si la pregunta es “¿quién tiene una carga horaria <em>parecida</em> a la de Ana?”, mira la <strong>euclidiana</strong>. No hay métrica universalmente mejor: hay pregunta.</p>
<p><strong>Conexión con ML:</strong> en búsqueda de documentos, dos textos del mismo tema y distinta longitud suelen recuperarse mejor por coseno. En un sensor industrial, dos lecturas “parecidas en valor absoluto” suelen pedirse en distancia (tras escalar).</p>
</section>
<section id="etapa-10-la-escala-de-las-features-cambia-el-espacio" class="level3">
<h3 class="anchored" data-anchor-id="etapa-10-la-escala-de-las-features-cambia-el-espacio">Etapa 10: La escala de las <em>features</em> cambia el espacio</h3>
<p>Se añade una columna en <strong>otra unidad</strong>: minutos de pantalla al día. Los hábitos de Ana y Elena siguen cerca en horas; Fabián, que apenas se mueve en el plano original, ahora tiene <img src="https://latex.codecogs.com/png.latex?240"> minutos. Sin escalar, esa columna <strong>domina</strong> la distancia.</p>
<p><strong>Pregunta guía:</strong> ¿sigue Elena siendo la más cercana a Ana cuando entra <code>minutos_pantalla</code> sin estandarizar?</p>
<div id="c041" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.841822Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.841544Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:41.851199Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:41.850603Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1">minutos_pantalla <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">90.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">95.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">80.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">85.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">88.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">240.0</span>])</span>
<span id="cb24-2">X_crudo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([X, minutos_pantalla])</span>
<span id="cb24-3"></span>
<span id="cb24-4">df_crudo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb24-5">    X_crudo,</span>
<span id="cb24-6">    columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"horas_lectura"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"horas_practica"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"minutos_pantalla"</span>],</span>
<span id="cb24-7">    index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres,</span>
<span id="cb24-8">)</span>
<span id="cb24-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"X sin escalar (unidades mezcladas):"</span>)</span>
<span id="cb24-10">display(df_crudo)</span>
<span id="cb24-11"></span>
<span id="cb24-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Distancia euclidiana a Ana en R^3 sin escalar"</span>)</span>
<span id="cb24-13">d_crudo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [distancia_euclidiana(X_crudo[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], fila) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> fila <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> X_crudo]</span>
<span id="cb24-14"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, d <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(nombres, d_crudo):</span>
<span id="cb24-15">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  d = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>d<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb24-16"></span>
<span id="cb24-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Estandarización: (x - media) / desv. de cada columna (estadísticos del conjunto)</span></span>
<span id="cb24-18">medias <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_crudo.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb24-19">desv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_crudo.std(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb24-20">X_std <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (X_crudo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> medias) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> desv</span>
<span id="cb24-21"></span>
<span id="cb24-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb24-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Distancia euclidiana a Ana después de estandarizar columnas"</span>)</span>
<span id="cb24-24">d_std <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [distancia_euclidiana(X_std[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], fila) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> fila <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> X_std]</span>
<span id="cb24-25"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, d <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(nombres, d_std):</span>
<span id="cb24-26">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  d = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>d<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>X sin escalar (unidades mezcladas):</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">horas_lectura</th>
<th data-quarto-table-cell-role="th">horas_practica</th>
<th data-quarto-table-cell-role="th">minutos_pantalla</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">Ana</th>
<td>4.0</td>
<td>4.0</td>
<td>90.0</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Bruno</th>
<td>8.0</td>
<td>8.0</td>
<td>95.0</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">Camila</th>
<td>8.0</td>
<td>2.0</td>
<td>80.0</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Diego</th>
<td>2.0</td>
<td>8.0</td>
<td>85.0</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">Elena</th>
<td>3.6</td>
<td>3.8</td>
<td>88.0</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">Fabián</th>
<td>1.0</td>
<td>1.2</td>
<td>240.0</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Distancia euclidiana a Ana en R^3 sin escalar
  Ana       d = 0.000
  Bruno     d = 7.550
  Camila    d = 10.954
  Diego     d = 6.708
  Elena     d = 2.049
  Fabián    d = 150.056

Distancia euclidiana a Ana después de estandarizar columnas
  Ana       d = 0.000
  Bruno     d = 1.926
  Camila    d = 1.521
  Diego     d = 1.532
  Elena     d = 0.155
  Fabián    d = 2.779</code></pre>
</div>
</div>
<p><strong>Interpretación.</strong> Sin escalar, Fabián se vuelve un extremo: <img src="https://latex.codecogs.com/png.latex?240"> minutos pesan más que las horas de estudio. Tras estandarizar, cada <em>feature</em> aporta en unidades de desviación estándar y el vecindario de Ana <strong>deja de estar secuestrado</strong> por una sola columna.</p>
<p>El coseno <strong>tampoco salva</strong> este problema por sí solo: es invariante si multiplicas el <em>vector entero</em> por una constante, no si una coordenada vive en otra escala.</p>
<p><strong>Conexión con ML:</strong> escalar no es cosmética. Es decidir que “1 hora de lectura” y “1 minuto de pantalla” no merecen el mismo voto en la distancia.</p>
</section>
<section id="etapa-11-ejemplo-final-el-vecino-de-una-consulta" class="level3">
<h3 class="anchored" data-anchor-id="etapa-11-ejemplo-final-el-vecino-de-una-consulta">Etapa 11: Ejemplo final — el vecino de una consulta</h3>
<p>Llega un estudiante nuevo, la <strong>consulta</strong> <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bq%7D=(6.5,%5C,6.5)">: misma dirección que Ana y Bruno, magnitud más cercana a Bruno. Se elige el vecino más cercano <strong>sin incluir a la consulta en <img src="https://latex.codecogs.com/png.latex?X"></strong>, una vez por euclidiana y una vez por coseno.</p>
<p><strong>Antes de ejecutar:</strong> ¿quién gana por distancia? ¿quién gana por ángulo? ¿pueden ser personas distintas?</p>
<div id="c044" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:41.852946Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:41.852790Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:42.298037Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:42.297587Z&quot;}}" data-execution_count="13">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb27-1">consulta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.5</span>])</span>
<span id="cb27-2"></span>
<span id="cb27-3">d_q <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([distancia_euclidiana(consulta, fila) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> fila <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> X])</span>
<span id="cb27-4">c_q <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([similitud_coseno(consulta, fila) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> fila <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> X])</span>
<span id="cb27-5"></span>
<span id="cb27-6">idx_euc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmin(d_q))</span>
<span id="cb27-7">idx_cos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmax(c_q))</span>
<span id="cb27-8"></span>
<span id="cb27-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Consulta q ="</span>, consulta)</span>
<span id="cb27-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb27-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ranking euclidiano (menor distancia):"</span>)</span>
<span id="cb27-12"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> idx <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> np.argsort(d_q):</span>
<span id="cb27-13">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombres[idx]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  d = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>d_q[idx]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb27-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Vecino 1-NN euclidiano:"</span>, nombres[idx_euc])</span>
<span id="cb27-15"></span>
<span id="cb27-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb27-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ranking coseno (mayor similitud):"</span>)</span>
<span id="cb27-18"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> idx <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> np.argsort(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>c_q):</span>
<span id="cb27-19">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombres[idx]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:8s}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  cos = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>c_q[idx]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb27-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Vecino 1-NN coseno:"</span>, nombres[idx_cos])</span>
<span id="cb27-21"></span>
<span id="cb27-22">graficar_barras_metricas(</span>
<span id="cb27-23">    nombres, d_q, c_q,</span>
<span id="cb27-24">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La misma consulta, dos órdenes distintos"</span>,</span>
<span id="cb27-25">)</span>
<span id="cb27-26">graficar_puntos_y_consulta(</span>
<span id="cb27-27">    nombres, X, consulta,</span>
<span id="cb27-28">    [(idx_euc, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-"</span>, <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"1-NN euclidiano: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombres[idx_euc]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>),</span>
<span id="cb27-29">     (idx_cos, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"1-NN coseno: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nombres[idx_cos]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)],</span>
<span id="cb27-30">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Segmento continuo: 1-NN euclidiano · Segmento punteado: 1-NN coseno"</span>,</span>
<span id="cb27-31">)</span>
<span id="cb27-32">graficar_vectores_2d(</span>
<span id="cb27-33">    nombres, X,</span>
<span id="cb27-34">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La consulta (flecha negra) está en la recta de Ana–Bruno"</span>,</span>
<span id="cb27-35">    query<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>consulta,</span>
<span id="cb27-36">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Consulta q = [6.5 6.5]

Ranking euclidiano (menor distancia):
  Bruno     d = 2.121
  Ana       d = 3.536
  Elena     d = 3.962
  Camila    d = 4.743
  Diego     d = 4.743
  Fabián    d = 7.638
Vecino 1-NN euclidiano: Bruno

Ranking coseno (mayor similitud):
  Ana       cos = 1.0000
  Bruno     cos = 1.0000
  Elena     cos = 0.9996
  Fabián    cos = 0.9959
  Camila    cos = 0.8575
  Diego     cos = 0.8575
Vecino 1-NN coseno: Ana</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/06-representacion-vectorial-datos/index_files/figure-html/cell-14-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/06-representacion-vectorial-datos/index_files/figure-html/cell-14-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/06-representacion-vectorial-datos/index_files/figure-html/cell-14-output-4.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Después de los gráficos.</strong> La consulta está sobre la recta de Ana–Bruno, así que <strong>Ana y Bruno empatan en coseno</strong> (<img src="https://latex.codecogs.com/png.latex?1">). <code>argmax</code> devuelve el primero: Ana. En distancia, <img src="https://latex.codecogs.com/png.latex?(6.5,6.5)"> está más cerca de Bruno <img src="https://latex.codecogs.com/png.latex?(8,8)"> que de Ana <img src="https://latex.codecogs.com/png.latex?(4,4)">. Las dos métricas <strong>eligen personas distintas</strong>.</p>
<p>Si este fuera un sistema de recomendación o un KNN, <strong>la métrica es el modelo</strong>: cambia el vecino, cambia la predicción.</p>
</section>
<section id="reto-técnico-2" class="level3">
<h3 class="anchored" data-anchor-id="reto-técnico-2">Reto técnico</h3>
<p>Cambia la consulta a <img src="https://latex.codecogs.com/png.latex?(7.5,%5C,2.2)"> (perfil lector). Vuelve a calcular ambos rankings. ¿El 1-NN euclidiano y el 1-NN coseno coinciden? Escribe en dos líneas qué política de “parecido” estarías usando en cada caso.</p>
</section>
<section id="errores-que-conviene-nombrar" class="level3">
<h3 class="anchored" data-anchor-id="errores-que-conviene-nombrar">Errores que conviene nombrar</h3>
<ol type="1">
<li><strong>Meter el objetivo <img src="https://latex.codecogs.com/png.latex?y"> dentro de <img src="https://latex.codecogs.com/png.latex?X">.</strong> Cambia la geometría y filtra la respuesta hacia las <em>features</em>.</li>
<li><strong>Leer el producto punto como similitud.</strong> Mezcla tamaño y ángulo: un vector largo “se parece” a todos.</li>
<li><strong>Usar distancia euclidiana cuando la pregunta es la dirección</strong> (o coseno cuando importa la magnitud).</li>
<li><strong>Medir distancias con columnas en unidades distintas.</strong> La columna de mayor rango decide quién es vecino.</li>
<li><strong>Creer que el coseno corrige la escala.</strong> Es invariante a escalar el vector entero, no una sola coordenada.</li>
<li><strong>Calcular el coseno con un vector nulo.</strong> No tiene dirección; el cociente no está definido.</li>
<li><strong>Olvidar el empate.</strong> Con dos vecinos a igual similitud, <code>argmax</code> elige el primero: el resultado depende del orden de las filas.</li>
</ol>
</section>
<section id="idea-clave" class="level3">
<h3 class="anchored" data-anchor-id="idea-clave">Idea clave</h3>
<p><strong>La lección no es memorizar cuatro fórmulas.</strong> Es reconocer que, al vectorizar, se elige un espacio —y en ese espacio “cerca” no es un hecho, es una definición. Reportar solo <img src="https://latex.codecogs.com/png.latex?d"> o solo <img src="https://latex.codecogs.com/png.latex?%5Ccos%5Ctheta"> sin decir <em>qué pregunta</em> se responde deja la geometría a medias.</p>
<p>En producción, esa definición tiene consecuencias: un buscador por coseno agrupa temas; un detector de anomalías por distancia (bien escalada) agrupa magnitudes; un pipeline sin escalar deja que la columna más ancha decida.</p>
</section>
<section id="síntesis-de-la-sesión" class="level3">
<h3 class="anchored" data-anchor-id="síntesis-de-la-sesión">Síntesis de la sesión</h3>
<p>Se pasó de la tabla a <img src="https://latex.codecogs.com/png.latex?X%5Cin%5Cmathbb%7BR%7D%5E%7Bn%5Ctimes%20p%7D">, de la fila al vector, y de un número suelto a dos geometrías distintas: <strong>longitud</strong> (norma, distancia) y <strong>orientación</strong> (producto punto, coseno). El contraste Ana–Bruno concentra la idea; el 1-NN muestra por qué la métrica importa antes de entrenar.</p>
<ul>
<li><strong>PCA:</strong> nuevas direcciones en el mismo espacio.</li>
<li><strong>KNN y clustering:</strong> vecindarios que heredan la métrica elegida.</li>
<li><strong>Regularización y embeddings:</strong> normas y ángulos como piezas de modelo, no solo de EDA.</li>
</ul>
<p>Quedó también el andamiaje algebraico: Cauchy–Schwarz acota el coseno, el unitario separa dirección de magnitud, y la proyección parte un vector en una componente explicada y un residual ortogonal.</p>
</section>
</section>
<section id="guía-rápida-qué-medida-usar" class="level2">
<h2 class="anchored" data-anchor-id="guía-rápida-qué-medida-usar">6. Guía rápida: ¿qué medida usar?</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Situación</th>
<th>Medida principal</th>
<th>Justificación</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Guardar el dataset para un modelo</td>
<td>Matriz <img src="https://latex.codecogs.com/png.latex?X">, vector <img src="https://latex.codecogs.com/png.latex?y"></td>
<td>Es el contrato de entrada de casi cualquier <code>fit</code></td>
</tr>
<tr class="even">
<td>¿Qué tan intenso es un perfil?</td>
<td>Norma</td>
<td>Longitud; no informa dirección</td>
</tr>
<tr class="odd">
<td>¿Dos perfiles apuntan igual?</td>
<td>Coseno</td>
<td>Invariante a escalar el vector completo</td>
</tr>
<tr class="even">
<td>¿Dos observaciones están cerca en valor?</td>
<td>Distancia euclidiana</td>
<td>Penaliza magnitud y dirección</td>
</tr>
<tr class="odd">
<td><em>Features</em> en unidades distintas</td>
<td>Estandarizar, <em>luego</em> distancia</td>
<td>Si no, gana la columna de mayor rango</td>
</tr>
<tr class="even">
<td>Texto, <em>embeddings</em>, tema compartido</td>
<td>Coseno</td>
<td>La longitud del documento no debería decidir</td>
</tr>
<tr class="odd">
<td>Proyección, capa lineal, “alineación”</td>
<td>Producto punto</td>
<td>Mezcla norma y ángulo; hay que leerlo con cuidado</td>
</tr>
<tr class="even">
<td>¿Un vector es múltiplo de otro?</td>
<td>Cauchy–Schwarz (holgura <img src="https://latex.codecogs.com/png.latex?0">)</td>
<td>Igualdad <img src="https://latex.codecogs.com/png.latex?%5CLeftrightarrow"> dependencia lineal</td>
</tr>
<tr class="odd">
<td>Quitar la intensidad, dejar la dirección</td>
<td>Vector unitario</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Chat%7Bx%7D=x/%5C%7Cx%5C%7C">; el coseno es <img src="https://latex.codecogs.com/png.latex?%5Chat%7Ba%7D%5Ccdot%5Chat%7Bb%7D"></td>
</tr>
<tr class="even">
<td>¿Qué parte de A vive en la recta de B?</td>
<td>Proyección ortogonal</td>
<td>Residual <img src="https://latex.codecogs.com/png.latex?%5Cperp"> a la dirección de referencia</td>
</tr>
</tbody>
</table>
<p><strong>Regla de comunicación:</strong> indicar las variables que entran a <img src="https://latex.codecogs.com/png.latex?X">, la métrica y si hubo escalamiento.</p>
</section>
<section id="guía-práctica-para-reportar-la-geometría" class="level2">
<h2 class="anchored" data-anchor-id="guía-práctica-para-reportar-la-geometría">7. Guía práctica para reportar la geometría</h2>
<section id="paso-1-identificar-el-espacio" class="level3">
<h3 class="anchored" data-anchor-id="paso-1-identificar-el-espacio">Paso 1: identificar el espacio</h3>
<p>Nombra las <em>features</em>, <img src="https://latex.codecogs.com/png.latex?n">, <img src="https://latex.codecogs.com/png.latex?p"> y las unidades. Separa <img src="https://latex.codecogs.com/png.latex?y"> si existe.</p>
</section>
<section id="paso-2-calcular-las-medidas" class="level3">
<h3 class="anchored" data-anchor-id="paso-2-calcular-las-medidas">Paso 2: calcular las medidas</h3>
<p>Normas de los casos que importan; distancia y coseno del par (o del vecindario) que responde la pregunta.</p>
</section>
<section id="paso-3-comparar-e-interpretar" class="level3">
<h3 class="anchored" data-anchor-id="paso-3-comparar-e-interpretar">Paso 3: comparar e interpretar</h3>
<p>Si distancia y coseno <strong>ordenan distinto</strong>, dilo. Esa discrepancia <em>es</em> el hallazgo.</p>
</section>
<section id="paso-4-revisar-escala" class="level3">
<h3 class="anchored" data-anchor-id="paso-4-revisar-escala">Paso 4: revisar escala</h3>
<p>Si una columna tiene otro rango, reporta también la versión estandarizada.</p>
</section>
<section id="paso-5-redactar-el-reporte" class="level3">
<h3 class="anchored" data-anchor-id="paso-5-redactar-el-reporte">Paso 5: redactar el reporte</h3>
<blockquote class="blockquote">
<p>“En el espacio <code>[features]</code>, <code>[caso A]</code> y <code>[caso B]</code> tienen distancia <code>___</code> y coseno <code>___</code>. Se reporta <code>[métrica]</code> porque <code>[pregunta]</code>. Implicación para el modelo: <code>[KNN/embeddings/escalar]</code>.”</p>
</blockquote>
<p><strong>Ejemplo aplicado:</strong> <em>“En el espacio (horas de lectura, horas de práctica), Ana y Bruno tienen distancia 5.66 y coseno 1.00. Se reporta el <strong>coseno</strong> porque la pregunta es quién estudia con la misma proporción de lectura y práctica, no quién dedica las mismas horas. Implicación para el modelo: un recomendador de rutinas debería usar coseno; un KNN que prediga la puntuación debería usar distancia, porque la cantidad de horas sí cambia el resultado.”</em></p>
</section>
</section>
<section id="puente-hacia-las-siguientes-sesiones" class="level2">
<h2 class="anchored" data-anchor-id="puente-hacia-las-siguientes-sesiones">8. Puente hacia las siguientes sesiones</h2>
<p>El espacio <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BR%7D%5Ep"> ya está nombrado: cada fila es un vector, con norma y dirección.</p>
<p>Lo que sigue es comprimir ese espacio: <strong>PCA</strong> busca ejes nuevos que conserven la mayor varianza posible. Sin norma, dirección y escala, PCA se reduce a una caja negra de <code>sklearn</code>.</p>
</section>
<section id="cierre" class="level2">
<h2 class="anchored" data-anchor-id="cierre">9. Cierre</h2>
<p>Este notebook deja una base aplicada sobre representación vectorial:</p>
<ul>
<li>el dataset como matriz <img src="https://latex.codecogs.com/png.latex?X"> y el objetivo como <img src="https://latex.codecogs.com/png.latex?y">,</li>
<li>la fila como vector, con norma y dirección,</li>
<li>producto punto, matriz de Gram, normas <img src="https://latex.codecogs.com/png.latex?L_1"> y <img src="https://latex.codecogs.com/png.latex?L_2">,</li>
<li>vector unitario, Cauchy–Schwarz, ortogonalidad y proyección,</li>
<li>distancia euclidiana y similitud coseno,</li>
<li>el contraste “misma dirección, distinta magnitud”,</li>
<li>el efecto de mezclar escalas,</li>
<li>un 1-NN que cambia de vecino al cambiar de métrica.</li>
</ul>
<p><strong>Resultado esperado:</strong> el estudiante puede escribir <img src="https://latex.codecogs.com/png.latex?X">, dibujar dos perfiles y justificar si “parecido” debe medirse en distancia o en ángulo —antes de entrenar.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>algebra-lineal</category>
  <category>vectores</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/basico/06-representacion-vectorial-datos/</guid>
  <pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Estadística para IA — 7. Reducción de dimensionalidad (PCA)</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/</link>
  <description><![CDATA[ 




<section id="sesión-7-reducción-de-dimensionalidad-pca" class="level1">
<h1>Sesión 7 — Reducción de Dimensionalidad (PCA)</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado es Científico de Datos, Arquitecto de IA, Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), consultor y docente universitario, trabaja en la intersección entre Data Science, Inteligencia Artificial, Big Data e IoT, transformando problemas reales en soluciones aplicadas.</p>
<p>De la teoría a la práctica, un problema a la vez.</p>
</section>
<section id="reducción-de-dimensionalidad-con-pca" class="level2">
<h2 class="anchored" data-anchor-id="reducción-de-dimensionalidad-con-pca">Reducción de Dimensionalidad con PCA</h2>
<p>Diez columnas no son diez historias. A menudo dos o tres <strong>direcciones</strong> bastan para describir la nube; el resto es ruido, redundancia o una escala mal elegida. PCA (análisis de componentes principales) busca esos ejes: los de <strong>máxima varianza</strong>, ortogonales entre sí y ordenados de mayor a menor.</p>
<p>Este notebook construye PCA desde la geometría. No parte de <code>sklearn.decomposition.PCA</code> sin mostrar el cálculo. Primero se ve por qué, con muchas variables, los puntos quedan <strong>aislados y con mucho vacío entre ellos</strong>; después, por qué hay que <strong>centrar</strong>; cómo la <strong>covarianza</strong> describe la forma de la nube; cómo un <strong>autovector</strong> se convierte en componente; cuánta varianza se conserva; cómo <strong>proyectar</strong> y <strong>reconstruir</strong>; y, al final, cuándo maximizar varianza es la pregunta <strong>equivocada</strong>.</p>
<p>Los datos son sintéticos y <strong>diseñados</strong>: una elipse, un plano en 3D, hábitos con dos factores latentes, una columna que, si no se escala, se queda con el primer componente, y un caso en el que la clase vive en la dirección <em>delgada</em>.</p>
<p>Electiva I — Estadística Aplicada a la Inteligencia Artificial · Módulo 2 · Sesión 7</p>
</section>
<section id="objetivos" class="level2">
<h2 class="anchored" data-anchor-id="objetivos">Objetivos</h2>
<ul>
<li>Explicar el <strong>problema de la alta dimensionalidad</strong> (mucho vacío entre puntos; “el más cercano” deja de ser informativo).</li>
<li>Justificar el <strong>centrado</strong> y leer la <strong>matriz de covarianza</strong> como forma de la nube.</li>
<li>Formular PCA como un problema de <strong>máxima varianza</strong> con restricción <img src="https://latex.codecogs.com/png.latex?%5C%7C%5Cmathbf%7Bw%7D%5C%7C=1">.</li>
<li>Obtener <strong>componentes principales</strong> por descomposición espectral y por <strong>SVD</strong>.</li>
<li>Calcular e interpretar <strong>varianza explicada</strong>, <em>scree</em> y varianza acumulada.</li>
<li><strong>Proyectar</strong> observaciones, <strong>reconstruir</strong> y medir el error en función de <img src="https://latex.codecogs.com/png.latex?k">.</li>
<li>Reproducir el mismo resultado con <strong>scikit-learn</strong> (incluido el signo arbitrario del eje).</li>
<li>Decidir cuándo <strong>estandarizar</strong> y cómo leer <strong>cargas</strong> (<em>loadings</em>).</li>
<li>Distinguir <strong>varianza</strong> de <strong>utilidad predictiva</strong>: cuándo PCA no es el método.</li>
</ul>
<blockquote class="blockquote">
<p>Nota: se recomienda ejecutar las celdas en orden. Las fórmulas usan LaTeX; si no se ven renderizadas, abre el notebook en Jupyter o Colab.</p>
</blockquote>
</section>
<section id="el-problema-y-la-solución-en-el-lenguaje-del-álgebra" class="level2">
<h2 class="anchored" data-anchor-id="el-problema-y-la-solución-en-el-lenguaje-del-álgebra">1. El problema y la solución, en el lenguaje del álgebra</h2>
<section id="alta-dimensionalidad" class="level3">
<h3 class="anchored" data-anchor-id="alta-dimensionalidad">1.1 Alta dimensionalidad</h3>
<p>Sea <img src="https://latex.codecogs.com/png.latex?X%5Cin%5Cmathbb%7BR%7D%5E%7Bn%5Ctimes%20p%7D"> la matriz de datos: <img src="https://latex.codecogs.com/png.latex?n"> observaciones, <img src="https://latex.codecogs.com/png.latex?p"> variables. Cada fila es un punto en <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BR%7D%5Ep">. Cuando <img src="https://latex.codecogs.com/png.latex?p"> crece y <img src="https://latex.codecogs.com/png.latex?n"> no crece al mismo ritmo ocurren tres fenómenos prácticos:</p>
<ol type="1">
<li><strong>Volumen:</strong> si fijas un radio, casi no cabe nadie: el espacio “se agranda” más rápido que el número de observaciones. Los puntos se alejan.</li>
<li><strong>Distancias:</strong> las distancias entre pares se parecen entre sí; el contraste entre “cerca” y “lejos” se comprime. KNN y el clustering por distancia dejan de distinguir bien quién está cerca.</li>
<li><strong>Redundancia:</strong> muchas columnas miden, con ruido, las mismas pocas causas. El rango efectivo de <img src="https://latex.codecogs.com/png.latex?X"> es mucho menor que <img src="https://latex.codecogs.com/png.latex?p">.</li>
</ol>
<p>En dimensión alta las observaciones quedan <strong>aisladas, con mucho vacío entre ellas</strong>: hay tantas direcciones posibles que <img src="https://latex.codecogs.com/png.latex?n"> puntos no alcanzan a llenarlas.</p>
<p>Reducir dimensión no es “borrar columnas al azar”. Es <strong>cambiar de base</strong>: pasar a un sistema de ejes donde las primeras coordenadas describen la forma de la nube y las últimas solo recogen una variación pequeña, casi ruido.</p>
</section>
<section id="qué-pregunta-responde-pca" class="level3">
<h3 class="anchored" data-anchor-id="qué-pregunta-responde-pca">1.2 Qué pregunta responde PCA</h3>
<p>PCA busca una dirección <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D%5Cin%5Cmathbb%7BR%7D%5Ep">, de norma <img src="https://latex.codecogs.com/png.latex?1">, tal que la proyección de los datos centrados tenga <strong>varianza máxima</strong>:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmax_%7B%5Cmathbf%7Bw%7D%7D%5C;%20%5Cmathbf%7Bw%7D%5E%7B%5Ctop%7D%5CSigma%5Cmathbf%7Bw%7D%0A%5Cquad%5Ctext%7Bsujeto%20a%7D%5Cquad%0A%5Cmathbf%7Bw%7D%5E%7B%5Ctop%7D%5Cmathbf%7Bw%7D=1.%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%5CSigma"> es la matriz de covarianzas muestral de las columnas:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CSigma%20=%20%5Cfrac%7B1%7D%7Bn-1%7D%20X_c%5E%7B%5Ctop%7D%20X_c,%0A%5Cqquad%0AX_c%20=%20X%20-%20%5Cmathbf%7B1%7D%5Cbar%7B%5Cmathbf%7Bx%7D%7D%5E%7B%5Ctop%7D.%0A"></p>
<p>El centrado <img src="https://latex.codecogs.com/png.latex?X_c"> no es un detalle de implementación: PCA describe la <strong>nube alrededor de su centro de masa</strong>. Sin restar <img src="https://latex.codecogs.com/png.latex?%5Cbar%7B%5Cmathbf%7Bx%7D%7D">, el primer eje apuntaría hacia el origen del sistema de coordenadas, no hacia la dirección ancha de los datos.</p>
</section>
<section id="la-solución-es-un-autovector" class="level3">
<h3 class="anchored" data-anchor-id="la-solución-es-un-autovector">1.3 La solución es un autovector</h3>
<p>El lagrangiano de ese problema conduce a la ecuación espectral</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CSigma%5Cmathbf%7Bw%7D%20=%20%5Clambda%5Cmathbf%7Bw%7D.%0A"></p>
<p>Los autovectores de <img src="https://latex.codecogs.com/png.latex?%5CSigma"> (ortonormales, porque <img src="https://latex.codecogs.com/png.latex?%5CSigma"> es simétrica y semidefinida positiva) son las <strong>componentes principales</strong>. El autovalor <img src="https://latex.codecogs.com/png.latex?%5Clambda"> es la <strong>varianza</strong> de los datos proyectados sobre ese eje.</p>
<p>Se ordenan <img src="https://latex.codecogs.com/png.latex?%5Clambda_1%5Cge%5Clambda_2%5Cge%5Ccdots%5Cge%5Clambda_p%5Cge%200">. El primer componente <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D_1"> es la dirección más ancha; <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D_2"> es la más ancha <em>entre las ortogonales a</em> <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D_1">; y así sucesivamente.</p>
</section>
<section id="varianza-explicada" class="level3">
<h3 class="anchored" data-anchor-id="varianza-explicada">1.4 Varianza explicada</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cpi_k%20=%20%5Cfrac%7B%5Clambda_k%7D%7B%5Csum_%7Bj=1%7D%5E%7Bp%7D%5Clambda_j%7D,%0A%5Cqquad%0A%5CPi_k%20=%20%5Csum_%7Bi=1%7D%5E%7Bk%7D%5Cpi_i.%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cpi_k"> es la fracción de la varianza total que vive en el eje <img src="https://latex.codecogs.com/png.latex?k">. <img src="https://latex.codecogs.com/png.latex?%5CPi_k"> es lo que se conserva al quedarse con los primeros <img src="https://latex.codecogs.com/png.latex?k"> componentes. Un <em>scree plot</em> (autovalores frente a <img src="https://latex.codecogs.com/png.latex?k">) y la curva <img src="https://latex.codecogs.com/png.latex?%5CPi_k"> son las dos lecturas estándar para elegir <img src="https://latex.codecogs.com/png.latex?k">. No hay umbral universal: <img src="https://latex.codecogs.com/png.latex?80%5C%25"> o <img src="https://latex.codecogs.com/png.latex?90%5C%25"> son convenciones; la pregunta de dominio manda.</p>
</section>
<section id="puntuaciones-cargas-y-reconstrucción" class="level3">
<h3 class="anchored" data-anchor-id="puntuaciones-cargas-y-reconstrucción">1.5 Puntuaciones, cargas y reconstrucción</h3>
<p>Sea <img src="https://latex.codecogs.com/png.latex?W=(%5Cmathbf%7Bw%7D_1%7C%5Ccdots%7C%5Cmathbf%7Bw%7D_p)%5Cin%5Cmathbb%7BR%7D%5E%7Bp%5Ctimes%20p%7D"> la matriz de autovectores. Las <strong>puntuaciones</strong> (<em>scores</em>) son las coordenadas en la nueva base:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AZ%20=%20X_c%20W.%0A"></p>
<p>Las <strong>cargas</strong> (<em>loadings</em>) son las entradas de <img src="https://latex.codecogs.com/png.latex?W"> (o de <img src="https://latex.codecogs.com/png.latex?W_k%5Csqrt%7B%5Clambda%7D">, según la convención): dicen cuánto aporta cada variable original a cada componente.</p>
<p>Si se retienen <img src="https://latex.codecogs.com/png.latex?k%3Cp"> ejes, <img src="https://latex.codecogs.com/png.latex?W_k"> son las primeras <img src="https://latex.codecogs.com/png.latex?k"> columnas y <img src="https://latex.codecogs.com/png.latex?Z_k=X_c%20W_k">. La <strong>reconstrucción</strong> en el espacio original es</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7BX%7D%5E%7B(k)%7D%20=%20Z_k%20W_k%5E%7B%5Ctop%7D%20+%20%5Cmathbf%7B1%7D%5Cbar%7B%5Cmathbf%7Bx%7D%7D%5E%7B%5Ctop%7D.%0A"></p>
<p>El error <img src="https://latex.codecogs.com/png.latex?%5C%7CX-%5Chat%7BX%7D%5E%7B(k)%7D%5C%7C_F%5E2"> es exactamente la suma de los autovalores <strong>no usados</strong> (salvo el factor <img src="https://latex.codecogs.com/png.latex?n-1">). <strong>Descartar un eje es descartar la varianza que había en esa dirección.</strong> Se hace a propósito: se sabe cuánto se pierde, porque ese monto es <img src="https://latex.codecogs.com/png.latex?%5Clambda_%7Bk+1%7D+%5Ccdots+%5Clambda_p">.</p>
</section>
<section id="svd-la-misma-geometría-otra-factorización" class="level3">
<h3 class="anchored" data-anchor-id="svd-la-misma-geometría-otra-factorización">1.6 SVD: la misma geometría, otra factorización</h3>
<p>Si <img src="https://latex.codecogs.com/png.latex?X_c=USV%5E%7B%5Ctop%7D"> es la descomposición en valores singulares,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AW=V,%0A%5Cqquad%0A%5Clambda_j%20=%20%5Cfrac%7Bs_j%5E2%7D%7Bn-1%7D.%0A"></p>
<p>Eigendecomposición de <img src="https://latex.codecogs.com/png.latex?%5CSigma"> y SVD de <img src="https://latex.codecogs.com/png.latex?X_c"> son dos caminos al mismo sistema de ejes. scikit-learn usa SVD internamente.</p>
</section>
<section id="geometría-en-una-frase" class="level3">
<h3 class="anchored" data-anchor-id="geometría-en-una-frase">1.7 Geometría en una frase</h3>
<p>PCA <strong>rota</strong> la nube para alinear los ejes coordenados con los ejes de la elipse de covarianza, <strong>ordena</strong> esos ejes por ancho y <strong>corta</strong> los más estrechos. No inventa variables mágicas: cambia de base y descarta coordenadas.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 50%">
<col style="width: 50%">
</colgroup>
<thead>
<tr class="header">
<th>Pregunta</th>
<th>Respuesta de PCA</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>¿Hacia dónde es ancha la nube?</td>
<td>Primeros autovectores de <img src="https://latex.codecogs.com/png.latex?%5CSigma"></td>
</tr>
<tr class="even">
<td>¿Cuánto se conserva al bajar a <img src="https://latex.codecogs.com/png.latex?k"> ejes?</td>
<td><img src="https://latex.codecogs.com/png.latex?%5CPi_k"></td>
</tr>
<tr class="odd">
<td>¿Dónde está cada observación en esa base?</td>
<td>Filas de <img src="https://latex.codecogs.com/png.latex?Z_k"></td>
</tr>
<tr class="even">
<td>¿Qué variables originales empujan cada eje?</td>
<td>Cargas (filas de <img src="https://latex.codecogs.com/png.latex?W_k">)</td>
</tr>
<tr class="odd">
<td>¿Qué se perdió?</td>
<td>Autovalores <img src="https://latex.codecogs.com/png.latex?%5Clambda_%7Bk+1%7D+%5Ccdots+%5Clambda_p"></td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="por-qué-importa-en-ia-y-machine-learning" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-importa-en-ia-y-machine-learning">2. Por qué importa en IA y Machine Learning</h2>
<p>Un modelo lineal, un KNN o una red no “entienden” nombres de columnas: operan en un espacio. Si ese espacio tiene <img src="https://latex.codecogs.com/png.latex?p"> grande, correlaciones fuertes y escalas distintas, el aprendizaje se encarece y se vuelve inestable.</p>
<ul>
<li><strong>Visualización.</strong> Proyectar a <img src="https://latex.codecogs.com/png.latex?2"> o <img src="https://latex.codecogs.com/png.latex?3"> componentes permite ver la nube que no cabe en un scatter de <img src="https://latex.codecogs.com/png.latex?p"> ejes.</li>
<li><strong>Compresión y ruido.</strong> Si las últimas componentes solo recogen variación mínima, <strong>descartarlas</strong> quita ruido.</li>
<li><strong>Multicolinealidad.</strong> Predictores alineados hacen inestables los coeficientes; los PCs son ortogonales por construcción.</li>
<li><strong>Preprocesamiento.</strong> Muchos flujos de modelado usan PCA como paso previo (con el riesgo de <strong>descartar</strong> la dirección que <em>sí</em> predice).</li>
</ul>
<p><strong>Idea central:</strong> PCA maximiza <strong>varianza</strong>, no relevancia para <img src="https://latex.codecogs.com/png.latex?y">. Un eje de <strong>poca</strong> varianza puede separar dos clases; un eje de <strong>mucha</strong> varianza puede ser solo un efecto de las unidades. El método es poderoso cuando la pregunta es la forma de <img src="https://latex.codecogs.com/png.latex?X">. Es peligroso cuando se usa como sustituto automático de la variable objetivo.</p>
</section>
<section id="flujo-recomendado-de-trabajo" class="level2">
<h2 class="anchored" data-anchor-id="flujo-recomendado-de-trabajo">3. Flujo recomendado de trabajo</h2>
<ol type="1">
<li><p><strong>Formular la pregunta.</strong> ¿Se quiere visualizar, comprimir, quitar ruido o preparar un modelo? PCA no responde “qué predice <img src="https://latex.codecogs.com/png.latex?y">” por sí solo.</p></li>
<li><p><strong>Inspeccionar unidades.</strong> Si las columnas no comparten escala, estandarizar <em>antes</em>. Si ya están en la misma unidad y la magnitud importa, no estandarizar por reflejo.</p></li>
<li><p><strong>Centrar siempre.</strong> Restar la media de cada columna. PCA sin centrar resuelve otro problema.</p></li>
<li><p><strong>Descomponer.</strong> Autovectores de <img src="https://latex.codecogs.com/png.latex?%5CSigma"> o SVD de <img src="https://latex.codecogs.com/png.latex?X_c">. Ordenar por <img src="https://latex.codecogs.com/png.latex?%5Clambda"> decreciente.</p></li>
<li><p><strong>Leer <img src="https://latex.codecogs.com/png.latex?%5Cpi_k"> y <img src="https://latex.codecogs.com/png.latex?%5CPi_k">.</strong> <em>Scree</em> y curva acumulada. Elegir <img src="https://latex.codecogs.com/png.latex?k"> con un criterio explícito.</p></li>
<li><p><strong>Proyectar e interpretar cargas.</strong> <img src="https://latex.codecogs.com/png.latex?Z_k"> son las nuevas coordenadas; <img src="https://latex.codecogs.com/png.latex?W_k"> dice de qué están hechas.</p></li>
<li><p><strong>Reconstruir.</strong> Verificar qué patrón se perdió con <img src="https://latex.codecogs.com/png.latex?k"> pequeño.</p></li>
<li><p><strong>Contrastar con el objetivo, si existe.</strong> Si hay <img src="https://latex.codecogs.com/png.latex?y">, comprobar que la dirección útil no quedó en un PC descartado.</p></li>
</ol>
<p><strong>Criterio general:</strong> <img src="https://latex.codecogs.com/png.latex?k"> es una decisión de modelado, no un número que el software “adivina”.</p>
</section>
<section id="preparar-el-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparar-el-entorno">4. Preparar el entorno</h2>
<div id="c009" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:45.316610Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:45.316123Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:47.365532Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:47.365079Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb1-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Python:"</span>, sys.version.split()[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> mpl_toolkits.mplot3d <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Axes3D  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># noqa: F401</span></span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.decomposition <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PCA</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> StandardScaler</span>
<span id="cb1-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pairwise_distances</span>
<span id="cb1-11"></span>
<span id="cb1-12">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-13">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-14"></span>
<span id="cb1-15">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"figure.figsize"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-16">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"axes.grid"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb1-17">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grid.alpha"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span></span>
<span id="cb1-18"></span>
<span id="cb1-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Entorno listo: numpy, pandas, matplotlib, scikit-learn."</span>)</span>
<span id="cb1-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pandas:"</span>, pd.__version__, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"| numpy:"</span>, np.__version__)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Python: 3.13.9
Entorno listo: numpy, pandas, matplotlib, scikit-learn.
pandas: 2.3.3 | numpy: 2.3.5</code></pre>
</div>
</div>
<section id="funciones-de-visualización-definidas-una-sola-vez" class="level3">
<h3 class="anchored" data-anchor-id="funciones-de-visualización-definidas-una-sola-vez">Funciones de visualización (definidas una sola vez)</h3>
<p>Las figuras se definen aquí. Cada etapa solo <strong>llama</strong> a la función correspondiente.</p>
<div id="c011" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:47.367364Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:47.367127Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:47.382542Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:47.382071Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_curse(ps, medias, contrastes):</span>
<span id="cb3-2">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>), constrained_layout<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-3">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(ps, medias, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>)</span>
<span id="cb3-4">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Dimensión p"</span>)</span>
<span id="cb3-5">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Distancia media entre pares"</span>)</span>
<span id="cb3-6">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Las distancias crecen con p"</span>)</span>
<span id="cb3-7">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(ps, contrastes, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>)</span>
<span id="cb3-8">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Dimensión p"</span>)</span>
<span id="cb3-9">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"(máx − mín) / media"</span>)</span>
<span id="cb3-10">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"El contraste cerca/lejos se aplana"</span>)</span>
<span id="cb3-11">    fig.suptitle(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Alta dimensionalidad: n fijo, p creciente"</span>)</span>
<span id="cb3-12">    plt.show()</span>
<span id="cb3-13"></span>
<span id="cb3-14"></span>
<span id="cb3-15"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_nube_2d(X, titulo, centro<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>, clases<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>, ejes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x₁"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x₂"</span>)):</span>
<span id="cb3-16">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.2</span>))</span>
<span id="cb3-17">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> clases <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>:</span>
<span id="cb3-18">        ax.scatter(X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.65</span>)</span>
<span id="cb3-19">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb3-20">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> lab <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> np.unique(clases):</span>
<span id="cb3-21">            m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> clases <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> lab</span>
<span id="cb3-22">            ax.scatter(X[m, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[m, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Clase </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>lab<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-23">        ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-24">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> centro <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>:</span>
<span id="cb3-25">        ax.scatter(centro[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], centro[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"centro"</span>)</span>
<span id="cb3-26">    ax.set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"equal"</span>, adjustable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box"</span>)</span>
<span id="cb3-27">    ax.set_xlabel(ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb3-28">    ax.set_ylabel(ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb3-29">    ax.set_title(titulo)</span>
<span id="cb3-30">    plt.tight_layout()</span>
<span id="cb3-31">    plt.show()</span>
<span id="cb3-32"></span>
<span id="cb3-33"></span>
<span id="cb3-34"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_nube_con_pcs(Xc, W, lambdas, titulo, nombres_ejes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x₁ centrada"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x₂ centrada"</span>)):</span>
<span id="cb3-35">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.4</span>))</span>
<span id="cb3-36">    ax.scatter(Xc[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], Xc[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>)</span>
<span id="cb3-37">    escala <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.4</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.sqrt(lambdas)</span>
<span id="cb3-38">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j, color <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C2"</span>]):</span>
<span id="cb3-39">        v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> W[:, j] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> escala[j]</span>
<span id="cb3-40">        ax.arrow(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, v[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], v[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], head_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span>, head_length<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span>,</span>
<span id="cb3-41">                 length_includes_head<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb3-42">                 label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  (λ=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>lambdas[j]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)"</span>)</span>
<span id="cb3-43">        ax.arrow(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>v[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>v[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], head_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.08</span>, head_length<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.08</span>,</span>
<span id="cb3-44">                 length_includes_head<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb3-45">    ax.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb3-46">    ax.axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb3-47">    ax.set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"equal"</span>, adjustable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box"</span>)</span>
<span id="cb3-48">    ax.set_xlabel(nombres_ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb3-49">    ax.set_ylabel(nombres_ejes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb3-50">    ax.set_title(titulo)</span>
<span id="cb3-51">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-52">    plt.tight_layout()</span>
<span id="cb3-53">    plt.show()</span>
<span id="cb3-54"></span>
<span id="cb3-55"></span>
<span id="cb3-56"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_scree(lambdas, titulo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Varianza por componente"</span>):</span>
<span id="cb3-57">    p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(lambdas)</span>
<span id="cb3-58">    ks <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb3-59">    pi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lambdas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> lambdas.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()</span>
<span id="cb3-60">    acum <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cumsum(pi)</span>
<span id="cb3-61">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>), constrained_layout<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-62">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].bar(ks, lambdas)</span>
<span id="cb3-63">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(ks, lambdas, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>)</span>
<span id="cb3-64">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_xticks(ks)</span>
<span id="cb3-65">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Componente k"</span>)</span>
<span id="cb3-66">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Autovalor λ_k"</span>)</span>
<span id="cb3-67">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Scree"</span>)</span>
<span id="cb3-68">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].bar(ks, pi, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"π_k"</span>)</span>
<span id="cb3-69">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(ks, acum, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Π_k acumulada"</span>)</span>
<span id="cb3-70">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].axhline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.4"</span>)</span>
<span id="cb3-71">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xticks(ks)</span>
<span id="cb3-72">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Componente k"</span>)</span>
<span id="cb3-73">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Fracción de varianza"</span>)</span>
<span id="cb3-74">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Varianza explicada"</span>)</span>
<span id="cb3-75">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-76">    fig.suptitle(titulo)</span>
<span id="cb3-77">    plt.show()</span>
<span id="cb3-78">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> pi, acum</span>
<span id="cb3-79"></span>
<span id="cb3-80"></span>
<span id="cb3-81"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_scores_1d(Z, titulo):</span>
<span id="cb3-82">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.6</span>), constrained_layout<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-83">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j, ax <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(axes):</span>
<span id="cb3-84">        ax.scatter(Z[:, j], np.zeros_like(Z[:, j]), s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>)</span>
<span id="cb3-85">        ax.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>)</span>
<span id="cb3-86">        ax.set_xlabel(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-87">        ax.set_yticks([])</span>
<span id="cb3-88">        ax.set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Proyección sobre PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   var = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>Z[:, j]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>var(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-89">    fig.suptitle(titulo)</span>
<span id="cb3-90">    plt.show()</span>
<span id="cb3-91"></span>
<span id="cb3-92"></span>
<span id="cb3-93"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_3d(X, titulo, vistas):</span>
<span id="cb3-94">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Nube 3D vista desde varias direcciones; cada vista es (dirección de la cámara, subtítulo)."""</span></span>
<span id="cb3-95">    fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.0</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(vistas), <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.4</span>))</span>
<span id="cb3-96">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, (direccion, subtitulo) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(vistas, start<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>):</span>
<span id="cb3-97">        d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(direccion, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.linalg.norm(direccion)</span>
<span id="cb3-98">        ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fig.add_subplot(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(vistas), i, projection<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"3d"</span>)</span>
<span id="cb3-99">        ax.scatter(X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)</span>
<span id="cb3-100">        ax.view_init(elev<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>np.degrees(np.arcsin(d[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])), azim<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>np.degrees(np.arctan2(d[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], d[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])))</span>
<span id="cb3-101">        ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>)</span>
<span id="cb3-102">        ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>)</span>
<span id="cb3-103">        ax.set_zlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"z"</span>)</span>
<span id="cb3-104">        ax.set_title(subtitulo, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb3-105">    fig.suptitle(titulo)</span>
<span id="cb3-106">    plt.tight_layout()</span>
<span id="cb3-107">    plt.show()</span>
<span id="cb3-108"></span>
<span id="cb3-109"></span>
<span id="cb3-110"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_reconstruccion(X, Xhat, titulo):</span>
<span id="cb3-111">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.8</span>), constrained_layout<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-112">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].scatter(X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>)</span>
<span id="cb3-113">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Original"</span>)</span>
<span id="cb3-114">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].scatter(Xhat[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], Xhat[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>)</span>
<span id="cb3-115">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Reconstrucción"</span>)</span>
<span id="cb3-116">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> axes:</span>
<span id="cb3-117">        ax.set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"equal"</span>, adjustable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box"</span>)</span>
<span id="cb3-118">        ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x₁"</span>)</span>
<span id="cb3-119">        ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x₂"</span>)</span>
<span id="cb3-120">    fig.suptitle(titulo)</span>
<span id="cb3-121">    plt.show()</span>
<span id="cb3-122"></span>
<span id="cb3-123"></span>
<span id="cb3-124"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_mse_k(ks, mses, titulo):</span>
<span id="cb3-125">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>))</span>
<span id="cb3-126">    ax.plot(ks, mses, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>)</span>
<span id="cb3-127">    ax.set_xticks(ks)</span>
<span id="cb3-128">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"k componentes retenidos"</span>)</span>
<span id="cb3-129">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Error cuadrático medio de reconstrucción"</span>)</span>
<span id="cb3-130">    ax.set_title(titulo)</span>
<span id="cb3-131">    plt.tight_layout()</span>
<span id="cb3-132">    plt.show()</span>
<span id="cb3-133"></span>
<span id="cb3-134"></span>
<span id="cb3-135"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_cargas(W, nombres, titulo, k<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>):</span>
<span id="cb3-136">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, k, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> k, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>), constrained_layout<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-137">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:</span>
<span id="cb3-138">        axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [axes]</span>
<span id="cb3-139">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j, ax <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(axes):</span>
<span id="cb3-140">        ax.barh(nombres, W[:, j])</span>
<span id="cb3-141">        ax.axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.4"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb3-142">        ax.set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Cargas PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-143">        ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"peso en el componente"</span>)</span>
<span id="cb3-144">    fig.suptitle(titulo)</span>
<span id="cb3-145">    plt.show()</span>
<span id="cb3-146"></span>
<span id="cb3-147"></span>
<span id="cb3-148"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_escala_lado_a_lado(X_a, X_b, titulo_a, titulo_b):</span>
<span id="cb3-149">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.8</span>), constrained_layout<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-150">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].scatter(X_a[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X_a[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>)</span>
<span id="cb3-151">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(titulo_a)</span>
<span id="cb3-152">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].scatter(X_b[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X_b[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>)</span>
<span id="cb3-153">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(titulo_b)</span>
<span id="cb3-154">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> axes:</span>
<span id="cb3-155">        ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC1"</span>)</span>
<span id="cb3-156">        ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC2"</span>)</span>
<span id="cb3-157">    fig.suptitle(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La misma nube, dos decisiones de escala"</span>)</span>
<span id="cb3-158">    plt.show()</span></code></pre></div></div>
</div>
<div id="c012" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:47.384392Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:47.384227Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:47.387730Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:47.387341Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> pca_manual(X, ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>):</span>
<span id="cb4-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""PCA por eigendecomposición de la covarianza muestral.</span></span>
<span id="cb4-3"></span>
<span id="cb4-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    Devuelve media, datos centrados, autovalores (desc), W (columnas = PCs),</span></span>
<span id="cb4-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    puntuaciones Z y Σ.</span></span>
<span id="cb4-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    """</span></span>
<span id="cb4-7">    X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(X, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb4-8">    media <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb4-9">    Xc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> media</span>
<span id="cb4-10">    Sigma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cov(Xc, rowvar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ddof)</span>
<span id="cb4-11">    lambdas, W <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.eigh(Sigma)</span>
<span id="cb4-12">    orden <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argsort(lambdas)[::<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb4-13">    lambdas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lambdas[orden]</span>
<span id="cb4-14">    W <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> W[:, orden]</span>
<span id="cb4-15">    Z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Xc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> W</span>
<span id="cb4-16">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb4-17">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"media"</span>: media,</span>
<span id="cb4-18">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Xc"</span>: Xc,</span>
<span id="cb4-19">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sigma"</span>: Sigma,</span>
<span id="cb4-20">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>: lambdas,</span>
<span id="cb4-21">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>: W,</span>
<span id="cb4-22">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>: Z,</span>
<span id="cb4-23">    }</span>
<span id="cb4-24"></span>
<span id="cb4-25"></span>
<span id="cb4-26"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> reconstruir(pca_dict, k):</span>
<span id="cb4-27">    Wk <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_dict[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, :k]</span>
<span id="cb4-28">    Zk <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_dict[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>][:, :k]</span>
<span id="cb4-29">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Zk <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> Wk.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> pca_dict[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"media"</span>]</span></code></pre></div></div>
</div>
</section>
</section>
<section id="desarrollo-por-etapas" class="level2">
<h2 class="anchored" data-anchor-id="desarrollo-por-etapas">5. Desarrollo por etapas</h2>
<p>El argumento es único: del problema (muchas variables, nube difícil de leer) al objeto algebraico (<img src="https://latex.codecogs.com/png.latex?%5CSigma">, autovectores), a la lectura (<img src="https://latex.codecogs.com/png.latex?%5Cpi_k">, cargas), a la verificación (sklearn, SVD) y al límite (cuando la varianza no es la señal).</p>
<section id="etapa-1-el-problema-el-espacio-se-vacía" class="level3">
<h3 class="anchored" data-anchor-id="etapa-1-el-problema-el-espacio-se-vacía">Etapa 1: El problema — el espacio se vacía</h3>
<p>Se generan <img src="https://latex.codecogs.com/png.latex?n=80"> puntos gaussianos independientes y se mide la distancia euclidiana entre todos los pares, para <img src="https://latex.codecogs.com/png.latex?p%5Cin%5C%7B2,5,10,25,50,100%5C%7D">.</p>
<p><strong>Antes de ejecutar:</strong> si el contraste <img src="https://latex.codecogs.com/png.latex?(d_%7B%5Cmax%7D-d_%7B%5Cmin%7D)/%5Cbar%7Bd%7D"> baja cuando <img src="https://latex.codecogs.com/png.latex?p"> sube, “el vecino más cercano” deja de ser un concepto nítido. Eso es el corazón práctico de la <em>curse of dimensionality</em>.</p>
<div id="c015" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:47.389306Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:47.389116Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:47.598683Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:47.598129Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span></span>
<span id="cb5-2">ps <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>]</span>
<span id="cb5-3">medias, contrastes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [], []</span>
<span id="cb5-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> p <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> ps:</span>
<span id="cb5-5">    Xp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(n, p))</span>
<span id="cb5-6">    D <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pairwise_distances(Xp)</span>
<span id="cb5-7">    d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> D[np.triu_indices(n, k<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)]</span>
<span id="cb5-8">    medias.append(d.mean())</span>
<span id="cb5-9">    contrastes.append((d.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> d.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> d.mean())</span>
<span id="cb5-10"></span>
<span id="cb5-11">tabla_curse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb5-12">    {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p"</span>: ps, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"distancia_media"</span>: medias, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"contraste_relativo"</span>: contrastes}</span>
<span id="cb5-13">)</span>
<span id="cb5-14">display(tabla_curse.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb5-15">graficar_curse(ps, medias, contrastes)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">p</th>
<th data-quarto-table-cell-role="th">distancia_media</th>
<th data-quarto-table-cell-role="th">contraste_relativo</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>2</td>
<td>1.528</td>
<td>3.745</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>5</td>
<td>3.042</td>
<td>2.023</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>10</td>
<td>4.416</td>
<td>1.587</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>25</td>
<td>7.055</td>
<td>0.871</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>50</td>
<td>10.007</td>
<td>0.650</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">5</th>
<td>100</td>
<td>14.183</td>
<td>0.509</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-5-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Después del gráfico.</strong> La distancia media crece: en dimensión alta casi todo el mundo está lejos. El contraste se aplana: la diferencia entre el par más cercano y el más lejano se vuelve pequeña <em>respecto</em> a la escala típica. Un KNN en <img src="https://latex.codecogs.com/png.latex?p=100"> con <img src="https://latex.codecogs.com/png.latex?n=80"> distingue mucho peor quién está cerca: el par más cercano y el más lejano difieren en la mitad de la distancia típica, frente a casi cuatro veces en <img src="https://latex.codecogs.com/png.latex?p=2">.</p>
<p>Reducir <img src="https://latex.codecogs.com/png.latex?p"> no es solo para dibujar. Es recuperar un espacio donde “cerca” otra vez significa algo.</p>
</section>
<section id="etapa-2-una-nube-que-se-puede-leer-a-ojo" class="level3">
<h3 class="anchored" data-anchor-id="etapa-2-una-nube-que-se-puede-leer-a-ojo">Etapa 2: Una nube que se puede leer a ojo</h3>
<p>Antes de <img src="https://latex.codecogs.com/png.latex?p"> grande, una elipse en el plano. <img src="https://latex.codecogs.com/png.latex?n=400"> puntos con correlación fuerte: la dirección ancha es la diagonal <img src="https://latex.codecogs.com/png.latex?x_1%5Capprox%20x_2">; la dirección delgada es la anti-diagonal.</p>
<p><strong>Pregunta guía:</strong> si hubiera que resumir cada punto con <em>un solo número</em>, ¿sobre qué recta lo proyectaría?</p>
<div id="c018" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:47.600459Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:47.600294Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:47.701792Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:47.701073Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span></span>
<span id="cb6-2">z1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.8</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb6-3">z2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb6-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Rotación 45°: el eje ancho queda sobre la diagonal</span></span>
<span id="cb6-5">c, s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cos(np.pi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), np.sin(np.pi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb6-6">R <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([[c, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>s], [s, c]])</span>
<span id="cb6-7">X2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([z1, z2]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> R.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>])</span>
<span id="cb6-8"></span>
<span id="cb6-9">df2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(X2, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x2"</span>])</span>
<span id="cb6-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(df2.describe().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb6-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Correlación x1, x2:"</span>, np.corrcoef(X2.T)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb6-12">graficar_nube_2d(X2, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Nube 2D diseñada: ancha en la diagonal"</span>, centro<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>X2.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>            x1       x2
count  400.000  400.000
mean     3.048    2.029
std      1.247    1.234
min     -0.065   -0.754
25%      2.153    1.092
50%      2.933    2.001
75%      3.972    2.920
max      6.529    5.284
Correlación x1, x2: 0.916</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-6-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> El centro no está en el origen. La nube es una elipse inclinada. Cualquier resumen univariado por columna (media de <img src="https://latex.codecogs.com/png.latex?x_1">, media de <img src="https://latex.codecogs.com/png.latex?x_2">) <strong>rompe</strong> esa diagonal: trata como independientes dos coordenadas que se mueven juntas. El eje útil no es <img src="https://latex.codecogs.com/png.latex?x_1"> ni <img src="https://latex.codecogs.com/png.latex?x_2">; es una <strong>combinación lineal</strong>.</p>
</section>
<section id="etapa-3-centrar-el-origen-tiene-que-ser-el-centro-de-la-nube" class="level3">
<h3 class="anchored" data-anchor-id="etapa-3-centrar-el-origen-tiene-que-ser-el-centro-de-la-nube">Etapa 3: Centrar — el origen tiene que ser el centro de la nube</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0AX_c%20=%20X%20-%20%5Cmathbf%7B1%7D%5Cbar%7B%5Cmathbf%7Bx%7D%7D%5E%7B%5Ctop%7D%0A"></p>
<p><strong>Antes de comparar los dos gráficos:</strong> el primero tiene el centro en <img src="https://latex.codecogs.com/png.latex?(3,2)">; el segundo, en <img src="https://latex.codecogs.com/png.latex?(0,0)">. PCA necesita el segundo. Si no, el “eje de máxima varianza” se confunde con el vector que apunta al centro de masa desde el origen.</p>
<div id="c021" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:47.703532Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:47.703361Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:47.910347Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:47.909843Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">media2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X2.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb8-2">Xc2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> media2</span>
<span id="cb8-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Media original:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(media2, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb8-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Media centrada (debe ser ~0):"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(Xc2.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>))</span>
<span id="cb8-5"></span>
<span id="cb8-6">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.8</span>), constrained_layout<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb8-7">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].scatter(X2[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X2[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>)</span>
<span id="cb8-8">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].scatter(media2[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], media2[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb8-9">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb8-10">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb8-11">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Original (centro ≠ origen)"</span>)</span>
<span id="cb8-12">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"equal"</span>, adjustable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box"</span>)</span>
<span id="cb8-13">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].scatter(Xc2[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], Xc2[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>)</span>
<span id="cb8-14">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].scatter(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb8-15">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb8-16">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb8-17">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Centrada (centro = origen)"</span>)</span>
<span id="cb8-18">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"equal"</span>, adjustable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box"</span>)</span>
<span id="cb8-19"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> axes:</span>
<span id="cb8-20">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x₁"</span>)</span>
<span id="cb8-21">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x₂"</span>)</span>
<span id="cb8-22">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Media original: [3.0478 2.0294]
Media centrada (debe ser ~0): [0. 0.]</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-7-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Después.</strong> Centrar <strong>traslada</strong>; no rota ni cambia la forma. La covarianza, los ángulos y las distancias <em>entre puntos</em> se conservan. Solo se elige un origen honesto: el <strong>centro de la muestra</strong> (la media de cada columna).</p>
</section>
<section id="etapa-4-la-covarianza-es-la-forma-de-la-nube" class="level3">
<h3 class="anchored" data-anchor-id="etapa-4-la-covarianza-es-la-forma-de-la-nube">Etapa 4: La covarianza es la forma de la nube</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CSigma%20=%20%5Cfrac%7B1%7D%7Bn-1%7D%20X_c%5E%7B%5Ctop%7D%20X_c%0A%5Cin%5Cmathbb%7BR%7D%5E%7Bp%5Ctimes%20p%7D%0A"></p>
<p>En la diagonal, varianzas. Fuera, covarianzas. Una <img src="https://latex.codecogs.com/png.latex?%5CSigma"> con fuera-diagonal grande (respecto a las varianzas) es una elipse inclinada. Una <img src="https://latex.codecogs.com/png.latex?%5CSigma"> diagonal es una elipse alineada con los ejes —o un círculo, si las varianzas coinciden.</p>
<p><strong>Conexión algebraica:</strong> <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D%5E%7B%5Ctop%7D%5CSigma%5Cmathbf%7Bw%7D"> es exactamente la varianza muestral de la proyección <img src="https://latex.codecogs.com/png.latex?X_c%5Cmathbf%7Bw%7D">.</p>
<div id="c024" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:47.912019Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:47.911838Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:47.995080Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:47.994677Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">Sigma2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cov(Xc2, rowvar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb10-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Σ (covarianza muestral):"</span>)</span>
<span id="cb10-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(Sigma2, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb10-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb10-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Varianza total (traza):"</span>, np.trace(Sigma2).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb10-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"w = (1,1)/√2  →  wᵀΣw ="</span>, (np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> Sigma2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> (np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb10-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"w = (1,-1)/√2 →  wᵀΣw ="</span>, (np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> Sigma2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> (np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb10-8"></span>
<span id="cb10-9">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>))</span>
<span id="cb10-10">im <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ax.imshow(Sigma2, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Blues"</span>)</span>
<span id="cb10-11">ax.set_xticks([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x2"</span>])</span>
<span id="cb10-12">ax.set_yticks([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x2"</span>])</span>
<span id="cb10-13"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>):</span>
<span id="cb10-14">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>):</span>
<span id="cb10-15">        ax.text(j, i, <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>Sigma2[i, j]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, ha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>, va<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>)</span>
<span id="cb10-16">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mapa de Σ"</span>)</span>
<span id="cb10-17">fig.colorbar(im, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ax, fraction<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.046</span>)</span>
<span id="cb10-18">plt.tight_layout()</span>
<span id="cb10-19">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Σ (covarianza muestral):
[[1.556 1.41 ]
 [1.41  1.524]]

Varianza total (traza): 3.079
w = (1,1)/√2  →  wᵀΣw = 2.95
w = (1,-1)/√2 →  wᵀΣw = 0.13</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-8-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> La proyección sobre la diagonal <img src="https://latex.codecogs.com/png.latex?(1,1)"> tiene mucha más varianza que sobre la anti-diagonal <img src="https://latex.codecogs.com/png.latex?(1,-1)">. Eso <em>es</em> PCA, todavía sin nombrar autovectores: se probó a mano las dos direcciones naturales de esta elipse. El álgebra siguiente elige esas direcciones de forma sistemática, en cualquier <img src="https://latex.codecogs.com/png.latex?p">.</p>
</section>
<section id="etapa-5-autovectores-los-ejes-de-la-elipse" class="level3">
<h3 class="anchored" data-anchor-id="etapa-5-autovectores-los-ejes-de-la-elipse">Etapa 5: Autovectores — los ejes de la elipse</h3>
<p>Se resuelve <img src="https://latex.codecogs.com/png.latex?%5CSigma%5Cmathbf%7Bw%7D=%5Clambda%5Cmathbf%7Bw%7D"> con <code>np.linalg.eigh</code> (estable para matrices simétricas) y se ordenan los pares <img src="https://latex.codecogs.com/png.latex?(%5Clambda,%5Cmathbf%7Bw%7D)"> de mayor a menor autovalor.</p>
<p>Propiedades que hay que verificar, no creer:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?%5C%7C%5Cmathbf%7Bw%7D_j%5C%7C=1">,</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D_1%5Ccdot%5Cmathbf%7Bw%7D_2=0">,</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Clambda_1+%5Clambda_2=%5Cmathrm%7Btr%7D(%5CSigma)"> (la traza se conserva al cambiar de base ortonormal).</li>
</ul>
<div id="c027" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:47.996682Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:47.996497Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:48.111238Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:48.110768Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">pca2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_manual(X2)</span>
<span id="cb12-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Autovalores λ:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb12-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Autovectores (columnas = PC1, PC2):"</span>)</span>
<span id="cb12-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb12-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb12-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"||w1|| ="</span>, np.linalg.norm(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb12-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"||w2|| ="</span>, np.linalg.norm(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb12-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"w1 · w2 ="</span>, np.dot(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>))</span>
<span id="cb12-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"λ1 + λ2 ="</span>, pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  tr(Σ) ="</span>, np.trace(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sigma"</span>]).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb12-10"></span>
<span id="cb12-11">graficar_nube_con_pcs(</span>
<span id="cb12-12">    pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Xc"</span>], pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>], pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>],</span>
<span id="cb12-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Componentes principales = ejes de la elipse"</span>,</span>
<span id="cb12-14">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Autovalores λ: [2.9496 0.1297]
Autovectores (columnas = PC1, PC2):
[[-0.7111  0.7031]
 [-0.7031 -0.7111]]

||w1|| = 1.0
||w2|| = 1.0
w1 · w2 = 0.0
λ1 + λ2 = 3.0794   tr(Σ) = 3.0794</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-9-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Después del gráfico.</strong> PC1 recorre el eje largo; PC2, el corto. El signo de <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D_1"> (flecha hacia un sentido u otro de la <em>misma</em> recta) es convencional: <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D"> y <img src="https://latex.codecogs.com/png.latex?-%5Cmathbf%7Bw%7D"> definen el mismo componente. Eso reaparece al comparar con sklearn.</p>
<p>Formalmente se acaba de resolver el problema de la sección 1.2. No hay heurística: el primer eje es el maximizador de <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D%5E%7B%5Ctop%7D%5CSigma%5Cmathbf%7Bw%7D"> en la esfera unitaria.</p>
</section>
<section id="etapa-6-proyectar-coordenadas-en-la-base-principal" class="level3">
<h3 class="anchored" data-anchor-id="etapa-6-proyectar-coordenadas-en-la-base-principal">Etapa 6: Proyectar — coordenadas en la base principal</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0AZ%20=%20X_c%20W%0A"></p>
<p>La columna <img src="https://latex.codecogs.com/png.latex?j"> de <img src="https://latex.codecogs.com/png.latex?Z"> es el score sobre <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BPC%7Dj">. Su varianza muestral debe coincidir con <img src="https://latex.codecogs.com/png.latex?%5Clambda_j">.</p>
<p><strong>Antes de los gráficos de proyección:</strong> el de PC1 debe verse <em>mucho más extendido</em> que el de PC2. Si no, el diseño de la elipse falló.</p>
<div id="c030" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:48.113052Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:48.112869Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:48.283666Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:48.283228Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">Z2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>]</span>
<span id="cb14-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Var(PC1) ="</span>, Z2[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].var(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  λ1 ="</span>, pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>][<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb14-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Var(PC2) ="</span>, Z2[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].var(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  λ2 ="</span>, pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>][<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb14-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cov(PC1, PC2) ="</span>, np.cov(Z2, rowvar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (ortogonalidad ⇒ 0)"</span>)</span>
<span id="cb14-5"></span>
<span id="cb14-6">graficar_scores_1d(Z2, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La misma nube, descompuesta en dos ejes ortogonales"</span>)</span>
<span id="cb14-7">graficar_nube_2d(Z2, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Puntuaciones: la elipse, rotada y centrada"</span>, ejes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC2"</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Var(PC1) = 2.9496   λ1 = 2.9496
Var(PC2) = 0.1297   λ2 = 0.1297
Cov(PC1, PC2) = 0.0   (ortogonalidad ⇒ 0)</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-10-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-10-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> En el espacio de puntuaciones (las nuevas coordenadas) la elipse queda <strong>alineada con los ejes</strong>. Eso no añade información: es un cambio de coordenadas. El valor está en poder <strong>dejar de usar PC2</strong> y quedarse con un número por observación (PC1) que conserva casi todo el ancho de la nube.</p>
</section>
<section id="etapa-7-varianza-explicada-cuánto-se-guarda-al-cortar" class="level3">
<h3 class="anchored" data-anchor-id="etapa-7-varianza-explicada-cuánto-se-guarda-al-cortar">Etapa 7: Varianza explicada — cuánto se guarda al cortar</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cpi_k=%5Cfrac%7B%5Clambda_k%7D%7B%5Csum_j%5Clambda_j%7D,%5Cqquad%20%5CPi_k=%5Csum_%7Bi=1%7D%5E%7Bk%7D%5Cpi_i%0A"></p>
<p>En esta elipse, <img src="https://latex.codecogs.com/png.latex?%5CPi_1"> debe ser alto: un solo eje basta. El <em>scree</em> (gráfico de <img src="https://latex.codecogs.com/png.latex?%5Clambda_k"> frente a <img src="https://latex.codecogs.com/png.latex?k">) muestra un <strong>quiebre</strong> evidente: <img src="https://latex.codecogs.com/png.latex?%5Clambda"> cae y después se aplana.</p>
<div id="c033" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:48.285363Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:48.285198Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:48.441190Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:48.440730Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">pi2, acum2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> graficar_scree(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Elipse 2D: un componente concentra la forma"</span>)</span>
<span id="cb16-2">resumen2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb16-3">    {</span>
<span id="cb16-4">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"k"</span>: [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>],</span>
<span id="cb16-5">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambda"</span>: pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>],</span>
<span id="cb16-6">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pi"</span>: pi2,</span>
<span id="cb16-7">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Pi_acumulada"</span>: acum2,</span>
<span id="cb16-8">    }</span>
<span id="cb16-9">)</span>
<span id="cb16-10">display(resumen2.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb16-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Con k=1 se conserva el </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>acum2[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">% de la varianza."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-11-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">k</th>
<th data-quarto-table-cell-role="th">lambda</th>
<th data-quarto-table-cell-role="th">pi</th>
<th data-quarto-table-cell-role="th">Pi_acumulada</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>1</td>
<td>2.9496</td>
<td>0.9579</td>
<td>0.9579</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>2</td>
<td>0.1297</td>
<td>0.0421</td>
<td>1.0000</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Con k=1 se conserva el 95.8% de la varianza.</code></pre>
</div>
</div>
<p><strong>Cómo elegir <img src="https://latex.codecogs.com/png.latex?k"> en general.</strong> El quiebre del <em>scree</em> es una pista visual, no un teorema. <img src="https://latex.codecogs.com/png.latex?%5CPi_k%5Cge%200.9"> es una convención de ingeniería. En un problema real se cruza con: ¿se puede interpretar el PC<img src="https://latex.codecogs.com/png.latex?k">? ¿baja el error de reconstrucción de forma material? ¿un modelo posterior mejora? El número <img src="https://latex.codecogs.com/png.latex?k"> se <strong>argumenta</strong>, no se extrae de un umbral fijo.</p>
</section>
<section id="etapa-8-el-mismo-cálculo-en-scikit-learn" class="level3">
<h3 class="anchored" data-anchor-id="etapa-8-el-mismo-cálculo-en-scikit-learn">Etapa 8: El mismo cálculo en scikit-learn</h3>
<p><code>PCA</code> siempre centra los datos (guarda la media en <code>mean_</code>) y usa SVD. Las ratios deben coincidir. Los vectores pueden salir <strong>multiplicados por <img src="https://latex.codecogs.com/png.latex?-1"></strong>: es la misma recta.</p>
<p><strong>Antes de comparar:</strong> si <code>components_</code> es el opuesto de <img src="https://latex.codecogs.com/png.latex?W%5E%7B%5Ctop%7D">, el resultado no está mal. Un componente es una dirección, no una flecha orientada.</p>
<div id="c036" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:48.442894Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:48.442731Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:48.448804Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:48.448368Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">sk <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, svd_solver<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"full"</span>)</span>
<span id="cb18-2">Z_sk <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sk.fit_transform(X2)</span>
<span id="cb18-3"></span>
<span id="cb18-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sklearn explained_variance_     :"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(sk.explained_variance_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb18-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"manual λ                        :"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb18-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sklearn explained_variance_ratio_:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(sk.explained_variance_ratio_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb18-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb18-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sklearn components_ (filas = PCs):"</span>)</span>
<span id="cb18-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(sk.components_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb18-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"manual W.T:"</span>)</span>
<span id="cb18-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>].T, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb18-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb18-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Producto fila a fila (1 o −1 si son el mismo eje):"</span>)</span>
<span id="cb18-14"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>):</span>
<span id="cb18-15">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.dot(sk.components_[j], pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, j]), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb18-16"></span>
<span id="cb18-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb18-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Medias usadas por sklearn (mean_):"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(sk.mean_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>sklearn explained_variance_     : [2.9496 0.1297]
manual λ                        : [2.9496 0.1297]
sklearn explained_variance_ratio_: [0.9579 0.0421]

sklearn components_ (filas = PCs):
[[ 0.7111  0.7031]
 [-0.7031  0.7111]]
manual W.T:
[[-0.7111 -0.7031]
 [ 0.7031 -0.7111]]

Producto fila a fila (1 o −1 si son el mismo eje):
  PC1: -1.0
  PC2: -1.0

Medias usadas por sklearn (mean_): [3.0478 2.0294]</code></pre>
</div>
</div>
<p><strong>Después.</strong> Autovalores y ratios coinciden. El producto <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D_%7B%5Cmathrm%7Bsklearn%7D%7D%5Ccdot%5Cmathbf%7Bw%7D_%7B%5Cmathrm%7Bmanual%7D%7D"> vale <img src="https://latex.codecogs.com/png.latex?%5Cpm%201">. Quien implemente un test numérico debe comparar ejes <em>salvo signo</em>, o fijar una convención (por ejemplo, que la carga de mayor valor absoluto sea positiva).</p>
</section>
<section id="etapa-9-de-3d-a-2d-un-plano-con-un-poco-de-ruido-perpendicular" class="level3">
<h3 class="anchored" data-anchor-id="etapa-9-de-3d-a-2d-un-plano-con-un-poco-de-ruido-perpendicular">Etapa 9: De 3D a 2D — un plano con un poco de ruido perpendicular</h3>
<p>Se fabrica un plano en <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BR%7D%5E3"> (dos factores latentes) y se añade ruido pequeño en la dirección normal. PCA debe reportar <strong>dos</strong> componentes grandes y un tercero casi nulo.</p>
<p><strong>Pregunta guía (antes del 3D):</strong> si la nube es <strong>ancha en dos direcciones y muy delgada en la tercera</strong> (como una lámina), ¿cuántos números hacen falta para ubicar un punto “casi” bien?</p>
<div id="c039" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:48.450456Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:48.450303Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:48.908215Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:48.907797Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">n3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span></span>
<span id="cb20-2">u <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.6</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n3)</span>
<span id="cb20-3">v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n3)</span>
<span id="cb20-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plano: x = u+v, y = u-0.3v, z = 0.4u+0.8v, más ruido normal</span></span>
<span id="cb20-5">plano <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([</span>
<span id="cb20-6">    u <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> v,</span>
<span id="cb20-7">    u <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> v,</span>
<span id="cb20-8">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> u <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> v,</span>
<span id="cb20-9">])</span>
<span id="cb20-10">ruido <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.08</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>plano.shape)</span>
<span id="cb20-11">X3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plano <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> ruido</span>
<span id="cb20-12"></span>
<span id="cb20-13">pca3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_manual(X3)</span>
<span id="cb20-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Autovalores 3D:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca3[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb20-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"π:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca3[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> pca3[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb20-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Π acumulada:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.cumsum(pca3[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> pca3[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb20-17"></span>
<span id="cb20-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Cámara perpendicular a la lámina (dirección del PC3) y en el plano de la lámina (PC1)</span></span>
<span id="cb20-19">graficar_3d(X3, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Antes: nube en R³ (una lámina, no una bola)"</span>,</span>
<span id="cb20-20">            vistas<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[(pca3[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"De frente: dos direcciones anchas"</span>),</span>
<span id="cb20-21">                    (pca3[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"De canto: casi sin espesor"</span>)])</span>
<span id="cb20-22">graficar_nube_2d(pca3[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>][:, :<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Después: proyección a PC1–PC2"</span>, ejes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC2"</span>))</span>
<span id="cb20-23">graficar_scree(pca3[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Tres autovalores: dos de señal, uno de ruido"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Autovalores 3D: [6.1439e+00 1.4099e+00 6.0000e-03]
π: [8.127e-01 1.865e-01 8.000e-04]
Π acumulada: [0.8127 0.9992 1.    ]</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-13-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-13-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-13-output-4.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display" data-execution_count="12">
<pre><code>(array([8.12698400e-01, 1.86502493e-01, 7.99106421e-04]),
 array([0.8126984 , 0.99920089, 1.        ]))</code></pre>
</div>
</div>
<p><strong>Antes / después.</strong> El gráfico 3D muestra una lámina: de frente ocupa dos direcciones; de canto casi no tiene espesor. El 2D de puntuaciones recupera las dos direcciones del plano. El tercer autovalor es el ruido perpendicular a esa lámina: <strong>descartarlo quita ruido</strong>, no estructura. Esa es la comparación del temario: la misma nube, compactada, con la forma intacta.</p>
</section>
<section id="etapa-10-la-escala-se-queda-con-el-primer-componente" class="level3">
<h3 class="anchored" data-anchor-id="etapa-10-la-escala-se-queda-con-el-primer-componente">Etapa 10: La escala se queda con el primer componente</h3>
<p>Se toma la elipse 2D y se añade una tercera columna en <strong>otra unidad</strong> y sin relación con la elipse: un “conteo” del orden de cientos. Sin estandarizar, <img src="https://latex.codecogs.com/png.latex?%5Clambda_1"> se va con esa columna. Con <code>StandardScaler</code>, cada variable pesa lo mismo: se mide en desviaciones estándar.</p>
<p><strong>Antes de los dos <em>scree</em>:</strong> el primero debe tener un PC1 casi igual a la columna de mayor rango; el segundo debe devolver PC1 a la diagonal <img src="https://latex.codecogs.com/png.latex?x_1">–<img src="https://latex.codecogs.com/png.latex?x_2"> de la elipse y dejar al conteo en un eje propio.</p>
<div id="c042" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:48.909842Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:48.909664Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:49.427728Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:49.426965Z&quot;}}" data-execution_count="13">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1">conteo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># otra unidad, sin relación con x1 ni x2</span></span>
<span id="cb23-2">X_mix <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([X2, conteo])</span>
<span id="cb23-3"></span>
<span id="cb23-4">pca_crudo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_manual(X_mix)</span>
<span id="cb23-5">X_std <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler().fit_transform(X_mix)</span>
<span id="cb23-6">pca_std <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_manual(X_std)</span>
<span id="cb23-7"></span>
<span id="cb23-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sin escalar — cargas PC1 (x1, x2, conteo):"</span>)</span>
<span id="cb23-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_crudo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  π1 ="</span>, (pca_crudo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>][<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> pca_crudo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb23-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Estandarizado — cargas PC1:"</span>)</span>
<span id="cb23-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_std[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  π1 ="</span>, (pca_std[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>][<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> pca_std[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb23-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Estandarizado — cargas PC2:"</span>)</span>
<span id="cb23-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_std[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  π2 ="</span>, (pca_std[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>][<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> pca_std[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb23-14"></span>
<span id="cb23-15">graficar_scree(pca_crudo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sin escalar: el conteo se come λ₁"</span>)</span>
<span id="cb23-16">graficar_scree(pca_std[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Estandarizado: la forma vuelve a las dos primeras variables"</span>)</span>
<span id="cb23-17">graficar_escala_lado_a_lado(</span>
<span id="cb23-18">    pca_crudo[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>][:, :<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], pca_std[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>][:, :<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>],</span>
<span id="cb23-19">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Scores sin escalar"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Scores estandarizados"</span>,</span>
<span id="cb23-20">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Sin escalar — cargas PC1 (x1, x2, conteo):
[-0.0016 -0.0023  1.    ]   π1 = 0.998
Estandarizado — cargas PC1:
[-0.7032 -0.7045  0.0956]   π1 = 0.641
Estandarizado — cargas PC2:
[0.0812 0.054  0.9952]   π2 = 0.331</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-14-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-14-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-14-output-4.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Interpretación.</strong> Sin escalar, PC1 es el conteo (carga 1.00) y concentra el 99.8% de la varianza: la elipse queda relegada a los ejes menores. Estandarizado, PC1 vuelve a la diagonal <img src="https://latex.codecogs.com/png.latex?x_1">–<img src="https://latex.codecogs.com/png.latex?x_2"> (cargas −0.70 y −0.70, <img src="https://latex.codecogs.com/png.latex?%5Cpi_1=64%5C%25">) y el conteo pasa a PC2 (carga 0.995, <img src="https://latex.codecogs.com/png.latex?%5Cpi_2=33%5C%25">). PCA no es invariante a cambios de unidad. Multiplicar una columna por <img src="https://latex.codecogs.com/png.latex?1000"> reescribe <img src="https://latex.codecogs.com/png.latex?%5CSigma"> y, con ella, los ejes. Estandarizar es declarar: <em>todas las variables pesan igual a priori</em>. No estandarizar es declarar: <em>la variable de mayor rango merece el primer eje</em>. Las dos decisiones son legítimas; la ilegítima es no saber cuál se tomó.</p>
</section>
<section id="etapa-11-dos-factores-latentes-y-las-cargas" class="level3">
<h3 class="anchored" data-anchor-id="etapa-11-dos-factores-latentes-y-las-cargas">Etapa 11: Dos factores latentes y las cargas</h3>
<p>Se simula un cuestionario de <img src="https://latex.codecogs.com/png.latex?p=6"> hábitos con <strong>dos causas</strong>: un factor <em>estudio</em> (lectura, práctica, ejercicios) y un factor <em>agotamiento</em> (pantalla, distracción, cafeína). PCA, bien escalado, debe recuperar dos componentes interpretables.</p>
<p>Las <strong>cargas</strong> son las coordenadas de cada variable original sobre los PCs: una barra larga en PC1 significa que esa columna <em>define</em> ese eje.</p>
<div id="c045" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:49.429480Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:49.429310Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:49.754155Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:49.753650Z&quot;}}" data-execution_count="14">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb25" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb25-1">n6 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">600</span></span>
<span id="cb25-2">estudio <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n6)</span>
<span id="cb25-3">agotamiento <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n6)</span>
<span id="cb25-4">nombres6 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lectura"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"practica"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ejercicios"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pantalla"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"distraccion"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cafeina"</span>]</span>
<span id="cb25-5">X6 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([</span>
<span id="cb25-6">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> estudio <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, n6),</span>
<span id="cb25-7">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> estudio <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, n6),</span>
<span id="cb25-8">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> estudio <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span>, n6),</span>
<span id="cb25-9">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> agotamiento <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, n6),</span>
<span id="cb25-10">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> agotamiento <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span>, n6),</span>
<span id="cb25-11">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> agotamiento <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span>, n6),</span>
<span id="cb25-12">])</span>
<span id="cb25-13">X6s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler().fit_transform(X6)</span>
<span id="cb25-14">pca6 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_manual(X6s)</span>
<span id="cb25-15"></span>
<span id="cb25-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"π:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca6[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> pca6[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb25-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Π:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.cumsum(pca6[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> pca6[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb25-18"></span>
<span id="cb25-19">cargas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb25-20">    pca6[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, :<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres6, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC2"</span>]</span>
<span id="cb25-21">)</span>
<span id="cb25-22">display(cargas.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb25-23">graficar_scree(pca6[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Seis variables, dos factores: quiebre en k=2"</span>)</span>
<span id="cb25-24">graficar_cargas(pca6[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>], nombres6, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cargas: qué variable empuja cada eje"</span>, k<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>π: [0.497 0.458 0.019 0.012 0.008 0.006]
Π: [0.497 0.954 0.974 0.986 0.994 1.   ]</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">PC1</th>
<th data-quarto-table-cell-role="th">PC2</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">lectura</th>
<td>-0.456</td>
<td>0.358</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">practica</th>
<td>-0.457</td>
<td>0.355</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">ejercicios</th>
<td>-0.451</td>
<td>0.354</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">pantalla</th>
<td>-0.354</td>
<td>-0.463</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">distraccion</th>
<td>-0.360</td>
<td>-0.453</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">cafeina</th>
<td>-0.353</td>
<td>-0.448</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-15-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-15-output-4.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Cómo leer las cargas.</strong> Un componente no “es” una variable: es una <strong>combinación</strong>. Si PC1 agrupa lectura–práctica–ejercicios con el mismo signo, ese eje es el factor estudio. Si PC2 agrupa pantalla–distracción–cafeína, es el factor agotamiento. Los signos se interpretan juntos: invertir el PC entero (todas las cargas <img src="https://latex.codecogs.com/png.latex?%5Ctimes%20-1">) no cambia el eje.</p>
<p>Regla práctica: no ponerle nombre a un PC solo por la variable de mayor carga si las demás del mismo signo son comparables. El nombre describe el <strong>bloque</strong>, no la columna ganadora.</p>
</section>
<section id="etapa-12-reconstruir-y-medir-lo-que-se-tiró" class="level3">
<h3 class="anchored" data-anchor-id="etapa-12-reconstruir-y-medir-lo-que-se-tiró">Etapa 12: Reconstruir y medir lo que se tiró</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7BX%7D%5E%7B(k)%7D%20=%20Z_k%20W_k%5E%7B%5Ctop%7D%20+%20%5Cmathbf%7B1%7D%5Cbar%7B%5Cmathbf%7Bx%7D%7D%5E%7B%5Ctop%7D%0A"></p>
<p>Para la elipse 2D, <img src="https://latex.codecogs.com/png.latex?k=1"> aplasta la nube sobre la diagonal; <img src="https://latex.codecogs.com/png.latex?k=2"> recupera todo (salvo error numérico). El MSE de reconstrucción debe caer a <img src="https://latex.codecogs.com/png.latex?%5Capprox%200"> cuando <img src="https://latex.codecogs.com/png.latex?k=p">.</p>
<div id="c048" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:49.756140Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:49.755967Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:50.075890Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:50.075459Z&quot;}}" data-execution_count="15">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb27-1">ks <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]</span>
<span id="cb27-2">mses <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb27-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> ks:</span>
<span id="cb27-4">    Xhat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> reconstruir(pca2, k)</span>
<span id="cb27-5">    mse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean((X2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> Xhat) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb27-6">    mses.append(mse)</span>
<span id="cb27-7">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"k=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: MSE = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mse<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.6f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb27-8"></span>
<span id="cb27-9">Xhat1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> reconstruir(pca2, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb27-10">graficar_reconstruccion(X2, Xhat1, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"k=1: la elipse se aplasta sobre PC1"</span>)</span>
<span id="cb27-11">graficar_mse_k(ks, mses, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Error de reconstrucción en la elipse 2D"</span>)</span>
<span id="cb27-12"></span>
<span id="cb27-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb27-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"3D — MSE según k:"</span>)</span>
<span id="cb27-15">mses3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb27-16"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>):</span>
<span id="cb27-17">    Xhat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> reconstruir(pca3, k)</span>
<span id="cb27-18">    mse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean((X3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> Xhat) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb27-19">    mses3.append(mse)</span>
<span id="cb27-20">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  k=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: MSE = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mse<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.5f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb27-21">graficar_mse_k([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>], mses3, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Error de reconstrucción de la lámina 3D"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>k=1: MSE = 0.064707
k=2: MSE = 0.000000</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-16-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-16-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>
3D — MSE según k:
  k=1: MSE = 0.47105
  k=2: MSE = 0.00201
  k=3: MSE = 0.00000</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-16-output-5.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> En 2D, <img src="https://latex.codecogs.com/png.latex?k=1"> pierde la variación de PC2 (el eje estrecho): la reconstrucción es un segmento grueso sobre la diagonal. En 3D, el salto grande de error está entre <img src="https://latex.codecogs.com/png.latex?k=1"> y <img src="https://latex.codecogs.com/png.latex?k=2">; de <img src="https://latex.codecogs.com/png.latex?k=2"> a <img src="https://latex.codecogs.com/png.latex?k=3"> se recupera solo el ruido. Elegir <img src="https://latex.codecogs.com/png.latex?k=2"> ahí no es una moda: es el punto en el que el MSE deja de bajar de forma material.</p>
<p>Identidad útil: la varianza no capturada por los primeros <img src="https://latex.codecogs.com/png.latex?k"> ejes es <img src="https://latex.codecogs.com/png.latex?%5Csum_%7Bj%3Ek%7D%5Clambda_j">. El gráfico de MSE y el de <img src="https://latex.codecogs.com/png.latex?%5CPi_k"> cuentan la misma pérdida, en dos unidades.</p>
</section>
<section id="etapa-13-svd-el-segundo-camino-al-mismo-sitio" class="level3">
<h3 class="anchored" data-anchor-id="etapa-13-svd-el-segundo-camino-al-mismo-sitio">Etapa 13: SVD — el segundo camino al mismo sitio</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0AX_c%20=%20U%20S%20V%5E%7B%5Ctop%7D,%0A%5Cqquad%0AW%20=%20V,%0A%5Cqquad%0A%5Clambda_j%20=%20%5Cfrac%7Bs_j%5E2%7D%7Bn-1%7D.%0A"></p>
<p><code>U</code> son direcciones en el espacio de las <img src="https://latex.codecogs.com/png.latex?n"> observaciones; <code>V</code>, en el de las <img src="https://latex.codecogs.com/png.latex?p"> variables. PCA vive en <img src="https://latex.codecogs.com/png.latex?V">.</p>
<div id="c051" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:50.077497Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:50.077325Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:50.082814Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:50.082470Z&quot;}}" data-execution_count="16">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb30" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb30-1">U, s, Vt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.svd(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Xc"</span>], full_matrices<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb30-2">lambdas_svd <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (Xc2.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb30-3"></span>
<span id="cb30-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"λ por SVD:     "</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(lambdas_svd, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb30-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"λ por eigh(Σ): "</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb30-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb30-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"V (filas de Vt) frente a W.T:"</span>)</span>
<span id="cb30-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Vt:"</span>)</span>
<span id="cb30-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(Vt, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb30-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W.T:"</span>)</span>
<span id="cb30-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>].T, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb30-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb30-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Producto de ejes (otra vez ±1):"</span>)</span>
<span id="cb30-14"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>):</span>
<span id="cb30-15">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  eje </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.dot(Vt[j], pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, j]), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb30-16"></span>
<span id="cb30-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Puntuaciones vía SVD: U * s</span></span>
<span id="cb30-18">Z_svd <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> U <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> s</span>
<span id="cb30-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb30-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max |Z_svd − Z_eigh| (salvo posible signo por columna):"</span>)</span>
<span id="cb30-21"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>):</span>
<span id="cb30-22">    d1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(Z_svd[:, j] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>][:, j]))</span>
<span id="cb30-23">    d2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(Z_svd[:, j] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>][:, j]))</span>
<span id="cb30-24">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(d1, d2)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2e}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>λ por SVD:      [2.9496 0.1297]
λ por eigh(Σ):  [2.9496 0.1297]

V (filas de Vt) frente a W.T:
Vt:
[[-0.7111 -0.7031]
 [-0.7031  0.7111]]
W.T:
[[-0.7111 -0.7031]
 [ 0.7031 -0.7111]]

Producto de ejes (otra vez ±1):
  eje 1: 1.0
  eje 2: -1.0

max |Z_svd − Z_eigh| (salvo posible signo por columna):
  PC1: 1.13e-14
  PC2: 8.16e-15</code></pre>
</div>
</div>
<p><strong>Por qué importan los dos caminos.</strong> <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7Beigh%7D(%5CSigma)"> es el lenguaje de la covarianza: claro para demostrar <img src="https://latex.codecogs.com/png.latex?%5CSigma%5Cmathbf%7Bw%7D=%5Clambda%5Cmathbf%7Bw%7D">. SVD es el lenguaje numérico: no forma <img src="https://latex.codecogs.com/png.latex?%5CSigma"> explícita (útil si <img src="https://latex.codecogs.com/png.latex?p"> es enorme) y es lo que usa sklearn. Quien entiende ambos no debate “cuál es el PCA verdadero”: son la misma rotación.</p>
</section>
<section id="etapa-14-el-contrapunto-la-clase-vive-en-el-eje-delgado" class="level3">
<h3 class="anchored" data-anchor-id="etapa-14-el-contrapunto-la-clase-vive-en-el-eje-delgado">Etapa 14: El contrapunto — la clase vive en el eje delgado</h3>
<p>Se construye una nube <strong>muy alargada</strong> en <img src="https://latex.codecogs.com/png.latex?x_1"> (mucha varianza, ninguna clase) y <strong>estrecha</strong> en <img src="https://latex.codecogs.com/png.latex?x_2">, donde sí se separan dos grupos. PCA pondrá PC1 sobre <img src="https://latex.codecogs.com/png.latex?x_1"> y, si alguien se queda solo con <img src="https://latex.codecogs.com/png.latex?k=1">, <strong>descartará la dirección que clasifica</strong>.</p>
<p>Este es el experimento que impide tratar PCA como paso automático antes de un modelo supervisado.</p>
<div id="c054" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:50.084286Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:50.084129Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:50.413453Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:50.413015Z&quot;}}" data-execution_count="17">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb32" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb32-1">n_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">280</span></span>
<span id="cb32-2">mitad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> n_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb32-3">x1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.2</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_c)          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ancho, inútil para la clase</span></span>
<span id="cb32-4">x2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.r_[rng.normal(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>, mitad),  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># delgado, sí separa</span></span>
<span id="cb32-5">           rng.normal(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>, n_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> mitad)]</span>
<span id="cb32-6">clases <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.r_[np.zeros(mitad, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>), np.ones(n_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> mitad, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)]</span>
<span id="cb32-7">Xcls <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([x1, x2])</span>
<span id="cb32-8"></span>
<span id="cb32-9">pca_cls <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_manual(Xcls)</span>
<span id="cb32-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"λ:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_cls[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  π:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_cls[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> pca_cls[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb32-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC1 (cargas x1, x2):"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_cls[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb32-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC2 (cargas x1, x2):"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_cls[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb32-13"></span>
<span id="cb32-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Umbral ingenuo sobre PC1 vs sobre x2</span></span>
<span id="cb32-15"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> acierto_umbral(v, y):</span>
<span id="cb32-16">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># umbral en el punto medio de las medias de clase</span></span>
<span id="cb32-17">    m0, m1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> v[y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].mean(), v[y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].mean()</span>
<span id="cb32-18">    t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (m0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> m1)</span>
<span id="cb32-19">    pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> t).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)</span>
<span id="cb32-20">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> pred.mean() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> y.mean() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>:</span>
<span id="cb32-21">        pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> pred</span>
<span id="cb32-22">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># probar ambas orientaciones</span></span>
<span id="cb32-23">    acc_a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> y).mean()</span>
<span id="cb32-24">    acc_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ((<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> pred) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> y).mean()</span>
<span id="cb32-25">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(acc_a, acc_b)</span>
<span id="cb32-26"></span>
<span id="cb32-27">acc_pc1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> acierto_umbral(pca_cls[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], clases)</span>
<span id="cb32-28">acc_pc2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> acierto_umbral(pca_cls[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>][:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], clases)</span>
<span id="cb32-29">acc_x2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> acierto_umbral(Xcls[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], clases)</span>
<span id="cb32-30"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb32-31"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Acierto umbral en PC1 (eje de más varianza): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acc_pc1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb32-32"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Acierto umbral en PC2 (eje de menos varianza): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acc_pc2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb32-33"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Acierto umbral en x2 original:     </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>acc_x2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb32-34"></span>
<span id="cb32-35">graficar_nube_2d(Xcls, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La clase se separa en el eje de MENOS varianza"</span>, clases<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>clases)</span>
<span id="cb32-36">graficar_nube_con_pcs(</span>
<span id="cb32-37">    pca_cls[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Xc"</span>], pca_cls[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>], pca_cls[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>],</span>
<span id="cb32-38">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC1 sigue el eje de más varianza e ignora la separación"</span>,</span>
<span id="cb32-39">)</span>
<span id="cb32-40">graficar_nube_2d(pca_cls[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Puntuaciones: en PC1 las clases se mezclan; en PC2 se apartan"</span>, clases<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>clases, ejes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC2"</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>λ: [10.774  0.535]   π: [0.953 0.047]
PC1 (cargas x1, x2): [-1.     0.003]
PC2 (cargas x1, x2): [-0.003 -1.   ]

Acierto umbral en PC1 (eje de más varianza): 0.507
Acierto umbral en PC2 (eje de menos varianza): 1.000
Acierto umbral en x2 original:     1.000</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-18-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-18-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-18-output-4.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>La lección que no se puede saltar.</strong> <img src="https://latex.codecogs.com/png.latex?%5Cpi_1"> será alto y tentador. Un flujo que haga <code>PCA(n_components=1)</code> + clasificador <strong>descartará la señal</strong>. PCA no está “mal calculado”: respondió la pregunta que se le hizo (¿dónde hay varianza?) y no la que el modelo supervisado necesita (¿dónde hay clase?).</p>
<p>Cuando existe <img src="https://latex.codecogs.com/png.latex?y">, la familia correcta de métodos se llama <em>supervisada</em> (LDA, PLS, selección por información mutua, regularización). PCA puede ser un paso exploratorio de <img src="https://latex.codecogs.com/png.latex?X">; no es un sustituto de la función objetivo.</p>
</section>
<section id="etapa-15-límites-y-buenas-prácticas-sin-folklore" class="level3">
<h3 class="anchored" data-anchor-id="etapa-15-límites-y-buenas-prácticas-sin-folklore">Etapa 15: Límites y buenas prácticas (sin folklore)</h3>
<p>PCA asume que las direcciones útiles son <strong>lineales</strong> y que “útil” <img src="https://latex.codecogs.com/png.latex?%5Capprox"> “ancha”. Falla, o se malinterpreta, en al menos estos casos:</p>
<ol type="1">
<li><strong>Forma curva (no un plano).</strong> Si los datos se doblan en el espacio —como una U o un espiral—, su “dimensión verdadera” es baja, pero no caben en un plano. PCA los aplasta sobre una recta o un plano y pierde esa curva. Hay otros métodos para ese caso (isomap, t-SNE, UMAP, autoencoders); responden otra pregunta.</li>
<li><strong>Valores atípicos.</strong> Un extremo desplaza <img src="https://latex.codecogs.com/png.latex?%5CSigma"> y puede crear un componente que solo existe por ese punto. Conviene inspeccionar la nube y, si hace falta, una versión robusta.</li>
<li><strong>Variables categóricas sin preparar.</strong> Convertir una categoría con muchos niveles a columnas 0/1 (indicadoras) infla <img src="https://latex.codecogs.com/png.latex?%5CSigma">. PCA clásico es para <img src="https://latex.codecogs.com/png.latex?X"> numérica, ya preparada.</li>
<li><strong><img src="https://latex.codecogs.com/png.latex?k"> como hiperparámetro oculto.</strong> Si hay <img src="https://latex.codecogs.com/png.latex?y">, <img src="https://latex.codecogs.com/png.latex?k"> es un hiperparámetro del modelo: se elige con validación <strong>dentro</strong> del entrenamiento. Elegirlo mirando el desempeño en el conjunto de prueba es fuga de información (Sesión 13).</li>
<li><strong>Interpretación causal.</strong> Un PC es una rotación, no un mecanismo. Bautizarlo (“el factor socioeconómico”) es una hipótesis, no un teorema.</li>
</ol>
<p>La práctica sólida: centrar siempre; decidir la escala; mostrar <em>scree</em> y cargas; reconstruir; y, si hay objetivo, contrastar contra él.</p>
</section>
<section id="cálculo-dirigido-una-matriz-5times-2-a-mano" class="level3">
<h3 class="anchored" data-anchor-id="cálculo-dirigido-una-matriz-5times-2-a-mano">Cálculo dirigido: una matriz <img src="https://latex.codecogs.com/png.latex?5%5Ctimes%202"> a mano</h3>
<p>Antes de <img src="https://latex.codecogs.com/png.latex?n=400">, cinco filas. Se puede seguir cada entrada de <img src="https://latex.codecogs.com/png.latex?%5Cbar%7B%5Cmathbf%7Bx%7D%7D">, <img src="https://latex.codecogs.com/png.latex?X_c">, <img src="https://latex.codecogs.com/png.latex?%5CSigma">, el polinomio característico (o <code>eigh</code>) y la proyección. El objetivo no es el número: es ver que <strong>no hay un paso oculto</strong> entre la tabla y el primer componente.</p>
<div id="c058" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:50.415336Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:50.415172Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:50.420861Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:50.420402Z&quot;}}" data-execution_count="18">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb34" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb34-1">X_mini <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(</span>
<span id="cb34-2">    [</span>
<span id="cb34-3">        [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>],</span>
<span id="cb34-4">        [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>],</span>
<span id="cb34-5">        [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>],</span>
<span id="cb34-6">        [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.5</span>],</span>
<span id="cb34-7">        [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>],</span>
<span id="cb34-8">    ]</span>
<span id="cb34-9">)</span>
<span id="cb34-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"X"</span>)</span>
<span id="cb34-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(X_mini)</span>
<span id="cb34-12">media_m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_mini.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb34-13">Xc_m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_mini <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> media_m</span>
<span id="cb34-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"media ="</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(media_m, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb34-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"X_c ="</span>)</span>
<span id="cb34-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(Xc_m, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb34-17">Sigma_m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cov(Xc_m, rowvar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb34-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Σ ="</span>)</span>
<span id="cb34-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(Sigma_m, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb34-20">pca_m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_manual(X_mini)</span>
<span id="cb34-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"λ ="</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_m[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb34-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W ="</span>)</span>
<span id="cb34-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_m[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb34-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z = X_c W ="</span>)</span>
<span id="cb34-25"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_m[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb34-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Comprobación Z.T Z / (n-1) (debe ser diag(λ)):"</span>)</span>
<span id="cb34-27"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_m[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>].T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> pca_m[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(X_mini) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>X
[[2.  1. ]
 [3.  2. ]
 [4.  2.5]
 [5.  3.5]
 [6.  4. ]]
media = [4.  2.6]
X_c =
[[-2.  -1.6]
 [-1.  -0.6]
 [ 0.  -0.1]
 [ 1.   0.9]
 [ 2.   1.4]]
Σ =
[[2.5   1.875]
 [1.875 1.425]]
λ = [3.913 0.012]
W =
[[-0.7986  0.6018]
 [-0.6018 -0.7986]]
Z = X_c W =
[[ 2.5602  0.0741]
 [ 1.1597 -0.1227]
 [ 0.0602  0.0799]
 [-1.3403 -0.1169]
 [-2.4398  0.0856]]
Comprobación Z.T Z / (n-1) (debe ser diag(λ)):
[[ 3.913 -0.   ]
 [-0.     0.012]]</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> <img src="https://latex.codecogs.com/png.latex?Z%5E%7B%5Ctop%7DZ/(n-1)=%5Cmathrm%7Bdiag%7D(%5Clambda)"> es la identidad que cierra el círculo: las puntuaciones son incorreladas y sus varianzas son los autovalores. Si esta igualdad no se cumple, hay un error de orden, de centrado o de <code>ddof</code>.</p>
</section>
<section id="etapa-extra-pc1-gana-a-direcciones-al-azar" class="level3">
<h3 class="anchored" data-anchor-id="etapa-extra-pc1-gana-a-direcciones-al-azar">Etapa extra: PC1 gana a direcciones al azar</h3>
<p>Se sortean <img src="https://latex.codecogs.com/png.latex?200"> vectores unitarios en <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BR%7D%5E2"> y se calcula <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D%5E%7B%5Ctop%7D%5CSigma%5Cmathbf%7Bw%7D">. Ninguno puede superar <img src="https://latex.codecogs.com/png.latex?%5Clambda_1">. El histograma debe cortarse en <img src="https://latex.codecogs.com/png.latex?%5Clambda_1"> y <img src="https://latex.codecogs.com/png.latex?%5Clambda_2"> marca el otro extremo entre las direcciones del círculo (el mínimo es <img src="https://latex.codecogs.com/png.latex?%5Clambda_2"> en 2D).</p>
<div id="c061" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:50.422332Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:50.422172Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:50.627272Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:50.626786Z&quot;}}" data-execution_count="19">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb36" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb36-1">n_dir <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span></span>
<span id="cb36-2">angs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.pi, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_dir)</span>
<span id="cb36-3">Wrand <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([np.cos(angs), np.sin(angs)])</span>
<span id="cb36-4">vars_rand <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.einsum(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ij,jk,ik-&gt;i"</span>, Wrand, pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sigma"</span>], Wrand)</span>
<span id="cb36-5"></span>
<span id="cb36-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max varianza aleatoria :"</span>, vars_rand.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb36-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"λ1 (teórico máximo)    :"</span>, pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>][<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb36-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"min varianza aleatoria :"</span>, vars_rand.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb36-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"λ2 (teórico mínimo 2D) :"</span>, pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>][<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb36-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"¿Alguna dirección supera λ1?"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">any</span>(vars_rand <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>][<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-10</span>))</span>
<span id="cb36-11"></span>
<span id="cb36-12">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>))</span>
<span id="cb36-13">ax.hist(vars_rand, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.85</span>)</span>
<span id="cb36-14">ax.axvline(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>][<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"λ1 = máximo"</span>)</span>
<span id="cb36-15">ax.axvline(pca2[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>][<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C2"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"λ2 = mínimo"</span>)</span>
<span id="cb36-16">ax.set_xlabel(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$\m</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">athbf{w}</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">^</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\t</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">op </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">\S</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">igma </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">\m</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">athbf{w}</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb36-17">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"direcciones"</span>)</span>
<span id="cb36-18">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"200 direcciones unitarias frente a los autovalores"</span>)</span>
<span id="cb36-19">ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb36-20">plt.tight_layout()</span>
<span id="cb36-21">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>max varianza aleatoria : 2.9494
λ1 (teórico máximo)    : 2.9496
min varianza aleatoria : 0.1299
λ2 (teórico mínimo 2D) : 0.1297
¿Alguna dirección supera λ1? False</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-20-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Esto es la definición, no una analogía.</strong> El primer componente no es “una dirección que suele ir bien”: es el maximizador de esa forma cuadrática en la esfera. El experimento solo hace visible un teorema.</p>
</section>
<section id="pca-sobre-la-matriz-de-correlaciones" class="level3">
<h3 class="anchored" data-anchor-id="pca-sobre-la-matriz-de-correlaciones">PCA sobre la matriz de correlaciones</h3>
<p>Estandarizar columnas y hacer PCA es equivalente a descomponer la <strong>matriz de correlaciones</strong> <img src="https://latex.codecogs.com/png.latex?R"> en lugar de <img src="https://latex.codecogs.com/png.latex?%5CSigma">. Útil cuando se quiere que cada variable tenga varianza <img src="https://latex.codecogs.com/png.latex?1"> <em>antes</em> de buscar ejes. Se compara <img src="https://latex.codecogs.com/png.latex?R"> con <img src="https://latex.codecogs.com/png.latex?%5CSigma"> sobre el cuestionario de hábitos.</p>
<div id="c064" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:50.629056Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:50.628888Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:50.639227Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:50.638827Z&quot;}}" data-execution_count="20">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb38" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb38-1">R <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.corrcoef(X6, rowvar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb38-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Matriz de correlaciones R:"</span>)</span>
<span id="cb38-3">display(pd.DataFrame(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(R, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres6, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres6))</span>
<span id="cb38-4"></span>
<span id="cb38-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># PCA de R: equivalentes a pca_manual(X6s)</span></span>
<span id="cb38-6">evals_R, evecs_R <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.eigh(R)</span>
<span id="cb38-7">orden <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argsort(evals_R)[::<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb38-8">evals_R, evecs_R <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> evals_R[orden], evecs_R[:, orden]</span>
<span id="cb38-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb38-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"λ de R:           "</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(evals_R, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb38-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"λ de X estandarizada:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca6[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb38-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"π de R:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(evals_R <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> evals_R.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb38-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb38-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Criterio de Kaiser (λ &gt; 1) sobre R: k ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>((evals_R <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()))</span>
<span id="cb38-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ese k coincide con el quiebre del gráfico si los factores son dos y el resto es ruido."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Matriz de correlaciones R:</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">lectura</th>
<th data-quarto-table-cell-role="th">practica</th>
<th data-quarto-table-cell-role="th">ejercicios</th>
<th data-quarto-table-cell-role="th">pantalla</th>
<th data-quarto-table-cell-role="th">distraccion</th>
<th data-quarto-table-cell-role="th">cafeina</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">lectura</th>
<td>1.00</td>
<td>0.96</td>
<td>0.94</td>
<td>0.03</td>
<td>0.04</td>
<td>0.04</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">practica</th>
<td>0.96</td>
<td>1.00</td>
<td>0.93</td>
<td>0.03</td>
<td>0.05</td>
<td>0.04</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">ejercicios</th>
<td>0.94</td>
<td>0.93</td>
<td>1.00</td>
<td>0.03</td>
<td>0.04</td>
<td>0.04</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">pantalla</th>
<td>0.03</td>
<td>0.03</td>
<td>0.03</td>
<td>1.00</td>
<td>0.95</td>
<td>0.91</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">distraccion</th>
<td>0.04</td>
<td>0.05</td>
<td>0.04</td>
<td>0.95</td>
<td>1.00</td>
<td>0.89</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">cafeina</th>
<td>0.04</td>
<td>0.04</td>
<td>0.04</td>
<td>0.91</td>
<td>0.89</td>
<td>1.00</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>
λ de R:            [2.979 2.746 0.116 0.073 0.049 0.036]
λ de X estandarizada: [2.984 2.751 0.117 0.073 0.049 0.036]
π de R: [0.497 0.458 0.019 0.012 0.008 0.006]

Criterio de Kaiser (λ &gt; 1) sobre R: k = 2
Ese k coincide con el quiebre del gráfico si los factores son dos y el resto es ruido.</code></pre>
</div>
</div>
<p><strong>Kaiser</strong> (<img src="https://latex.codecogs.com/png.latex?%5Clambda%3E1"> en la matriz de correlaciones) dice: un componente debe explicar más que una variable original estandarizada. Es una regla, no una demostración. Aquí debería sugerir <img src="https://latex.codecogs.com/png.latex?k=2">, alineado con el diseño. En datos sucios el criterio se queda corto o se pasa; por eso se cruza con el <em>scree</em> y con la reconstrucción.</p>
</section>
<section id="biplot-puntuaciones-y-cargas-en-el-mismo-plano" class="level3">
<h3 class="anchored" data-anchor-id="biplot-puntuaciones-y-cargas-en-el-mismo-plano">Biplot: puntuaciones y cargas en el mismo plano</h3>
<p>Un <em>biplot</em> superpone las observaciones (puntuaciones en PC1–PC2) y las variables (flechas = cargas). Una flecha larga y alineada con un grupo de puntos indica qué variable tira de ese grupo. Las flechas casi paralelas son variables redundantes; las ortogonales, bloques distintos.</p>
<div id="c067" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:50.640977Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:50.640819Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:50.746143Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:50.745634Z&quot;}}" data-execution_count="21">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb41" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb41-1">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.4</span>))</span>
<span id="cb41-2">Z6 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca6[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>][:, :<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]</span>
<span id="cb41-3">ax.scatter(Z6[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], Z6[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span>)</span>
<span id="cb41-4">escala <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.2</span></span>
<span id="cb41-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j, nom <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(nombres6):</span>
<span id="cb41-6">    vx, vy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> escala <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> pca6[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][j, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], escala <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> pca6[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][j, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb41-7">    ax.arrow(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, vx, vy, head_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.08</span>, head_length<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.08</span>,</span>
<span id="cb41-8">             length_includes_head<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.6</span>)</span>
<span id="cb41-9">    desfase <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sign(vy) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.32</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (j <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># separa las etiquetas del mismo bloque</span></span>
<span id="cb41-10">    ax.text(vx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.12</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, vy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.12</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> desfase, nom, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>,</span>
<span id="cb41-11">            bbox<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(boxstyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"round,pad=0.15"</span>, fc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, ec<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"none"</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>))</span>
<span id="cb41-12">ax.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>)</span>
<span id="cb41-13">ax.axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.6"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>)</span>
<span id="cb41-14">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC1"</span>)</span>
<span id="cb41-15">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC2"</span>)</span>
<span id="cb41-16">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Biplot: puntos = estudiantes, flechas = variables"</span>)</span>
<span id="cb41-17">ax.set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"equal"</span>, adjustable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box"</span>)</span>
<span id="cb41-18">plt.tight_layout()</span>
<span id="cb41-19">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-22-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura del biplot.</strong> Las tres flechas de estudio deben apuntar juntas; las de agotamiento, en otra dirección (casi ortogonal si los factores se simularon independientes). Esa figura es la versión geométrica de la tabla de cargas: misma información, más rápida de comprobar.</p>
</section>
<section id="ajuste-solo-en-entrenamiento-no-filtrar-con-toda-la-muestra" class="level3">
<h3 class="anchored" data-anchor-id="ajuste-solo-en-entrenamiento-no-filtrar-con-toda-la-muestra">Ajuste solo en entrenamiento — no filtrar con toda la muestra</h3>
<p>Si <img src="https://latex.codecogs.com/png.latex?Z"> se calcula con la media y los ejes de <strong>todas</strong> las filas, y después se parte train/test, el conjunto de prueba ya intervino en <img src="https://latex.codecogs.com/png.latex?%5Cbar%7B%5Cmathbf%7Bx%7D%7D"> y en <img src="https://latex.codecogs.com/png.latex?W">. Eso es fuga. El protocolo correcto: <code>fit</code> en train, <code>transform</code> en test —y vale también para el escalado, no solo para PCA. (La partición entrenamiento/prueba se estudia a fondo en la <strong>Sesión 13</strong>.)</p>
<div id="c070" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:50.747785Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:50.747617Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:50.759285Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:50.758766Z&quot;}}" data-execution_count="22">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb42" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb42-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split</span>
<span id="cb42-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.pipeline <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_pipeline</span>
<span id="cb42-3"></span>
<span id="cb42-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Se parte X6 SIN escalar: el escalado también forma parte de lo que se ajusta</span></span>
<span id="cb42-5">Xtr, Xte <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X6, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb42-6">pipe_tr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_pipeline(StandardScaler(), PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)).fit(Xtr)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># correcto</span></span>
<span id="cb42-7">pipe_all <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_pipeline(StandardScaler(), PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)).fit(X6)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fuga: vio el test</span></span>
<span id="cb42-8"></span>
<span id="cb42-9">Zte_ok <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_tr.transform(Xte)</span>
<span id="cb42-10">Zte_leak <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_all.transform(Xte)</span>
<span id="cb42-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Un eje y su opuesto son el mismo componente: se alinean los signos antes de comparar</span></span>
<span id="cb42-12">signos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sign(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(pipe_tr[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].components_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> pipe_all[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].components_, axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb42-13">Zte_leak <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Zte_leak <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> signos</span>
<span id="cb42-14"></span>
<span id="cb42-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"media del escalador (train):"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pipe_tr[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].mean_[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..."</span>)</span>
<span id="cb42-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"media del escalador (todos):"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pipe_all[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].mean_[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..."</span>)</span>
<span id="cb42-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"π train:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pipe_tr[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].explained_variance_ratio_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb42-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"π todos:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pipe_all[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].explained_variance_ratio_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb42-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb42-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMS diferencia de puntuaciones en test (fit-train vs fit-todos):"</span>,</span>
<span id="cb42-21">      np.sqrt(np.mean((Zte_ok <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> Zte_leak) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb42-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La diferencia no es un bug: son dos espacios distintos."</span>)</span>
<span id="cb42-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"En un pipeline, solo el primero es válido."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>media del escalador (train): [0.022  0.0343 0.0431] ...
media del escalador (todos): [0.0511 0.0543 0.0511] ...
π train: [0.499 0.454]
π todos: [0.497 0.458]

RMS diferencia de puntuaciones en test (fit-train vs fit-todos): 0.0334
La diferencia no es un bug: son dos espacios distintos.
En un pipeline, solo el primero es válido.</code></pre>
</div>
</div>
<p><strong>Protocolo.</strong> <code>StandardScaler</code> y <code>PCA</code> se envuelven en un <code>Pipeline</code> de scikit-learn y se ajustan <em>dentro</em> de cada fold de validación. Tratar el escalado y PCA como un preprocesado “offline” sobre <img src="https://latex.codecogs.com/png.latex?X"> completa, y validar después, deja que el conjunto de prueba influya en el modelo y vuelve optimistas las métricas de validación. Aquí la diferencia es pequeña (RMS ≈ 0.03) porque hay 600 filas y la estructura es fuerte; con pocos datos o muchas variables crece. En cualquier caso, un número calculado con un modelo que ya vio la prueba deja de ser una estimación honesta.</p>
</section>
<section id="derivación-breve-de-la-varianza-máxima-al-autovector" class="level3">
<h3 class="anchored" data-anchor-id="derivación-breve-de-la-varianza-máxima-al-autovector">Derivación breve: de la varianza máxima al autovector</h3>
<p>Se quiere <img src="https://latex.codecogs.com/png.latex?%5Cmax_%7B%5Cmathbf%7Bw%7D%7D%20f(%5Cmathbf%7Bw%7D)=%5Cmathbf%7Bw%7D%5E%7B%5Ctop%7D%5CSigma%5Cmathbf%7Bw%7D"> con <img src="https://latex.codecogs.com/png.latex?g(%5Cmathbf%7Bw%7D)=%5Cmathbf%7Bw%7D%5E%7B%5Ctop%7D%5Cmathbf%7Bw%7D-1=0">. El lagrangiano es</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathcal%7BL%7D(%5Cmathbf%7Bw%7D,%5Clambda)=%5Cmathbf%7Bw%7D%5E%7B%5Ctop%7D%5CSigma%5Cmathbf%7Bw%7D-%5Clambda(%5Cmathbf%7Bw%7D%5E%7B%5Ctop%7D%5Cmathbf%7Bw%7D-1).%0A"></p>
<p>La condición <img src="https://latex.codecogs.com/png.latex?%5Cnabla_%7B%5Cmathbf%7Bw%7D%7D%5Cmathcal%7BL%7D=0"> da <img src="https://latex.codecogs.com/png.latex?2%5CSigma%5Cmathbf%7Bw%7D-2%5Clambda%5Cmathbf%7Bw%7D=%5Cmathbf%7B0%7D">, es decir <img src="https://latex.codecogs.com/png.latex?%5CSigma%5Cmathbf%7Bw%7D=%5Clambda%5Cmathbf%7Bw%7D">. Como <img src="https://latex.codecogs.com/png.latex?%5CSigma"> es simétrica, existe una base ortonormal de autovectores. El mayor <img src="https://latex.codecogs.com/png.latex?%5Clambda"> es el máximo de <img src="https://latex.codecogs.com/png.latex?f"> en la esfera; el segundo, el máximo en el subespacio ortogonal al primero (se añade <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D%5E%7B%5Ctop%7D%5Cmathbf%7Bw%7D_1=0">).</p>
<p>Eso es todo el “misterio” de los componentes: no hay un algoritmo distinto de la teoría espectral de matrices simétricas.</p>
</section>
<section id="errores-que-conviene-nombrar" class="level3">
<h3 class="anchored" data-anchor-id="errores-que-conviene-nombrar">Errores que conviene nombrar</h3>
<ol type="1">
<li><strong>No centrar.</strong> Sin restar la media, el primer eje apunta hacia el centro de la nube, no a su dirección ancha.</li>
<li><strong>Mezclar unidades sin decidir la escala.</strong> La columna de mayor rango se queda con PC1 (Etapa 10).</li>
<li><strong>Elegir <img src="https://latex.codecogs.com/png.latex?k"> con un umbral fijo</strong> (80%, 90%) sin argumentarlo con el <em>scree</em>, la reconstrucción o el dominio.</li>
<li><strong>Usar PCA como sustituto de <img src="https://latex.codecogs.com/png.latex?y">.</strong> La señal puede vivir en el eje de menos varianza (Etapa 14).</li>
<li><strong>Comparar componentes sin tolerar el signo.</strong> <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bw%7D"> y <img src="https://latex.codecogs.com/png.latex?-%5Cmathbf%7Bw%7D"> son el mismo eje.</li>
<li><strong>Ajustar el escalado o PCA con todos los datos</strong> y validar después: es fuga de información.</li>
<li><strong>Nombrar un componente por su variable de mayor carga</strong> cuando otras del mismo bloque pesan parecido.</li>
<li><strong>Leer un componente como una causa.</strong> Es una rotación de los datos, no un mecanismo.</li>
</ol>
</section>
<section id="idea-clave" class="level3">
<h3 class="anchored" data-anchor-id="idea-clave">Idea clave</h3>
<p><strong>PCA no reduce columnas: reduce direcciones.</strong> Cambia a la base de la elipse de covarianza, ordena por ancho y corta. Eso es geometría, no un truco de librería.</p>
<p>Dos números deciden si el recorte fue honesto: <img src="https://latex.codecogs.com/png.latex?%5CPi_k"> (cuánta forma se guardó) y, cuando existe, el desempeño sobre <img src="https://latex.codecogs.com/png.latex?y"> (cuánta <em>señal</em> se guardó). Si solo se reporta el primero, se ha contado la mitad de la historia.</p>
</section>
<section id="síntesis" class="level3">
<h3 class="anchored" data-anchor-id="síntesis">Síntesis</h3>
<p>Se partió de un espacio que se vacía (<img src="https://latex.codecogs.com/png.latex?p"> grande, distancias planas) y se llegó a un procedimiento completo: centrar, formar <img src="https://latex.codecogs.com/png.latex?%5CSigma">, extraer <img src="https://latex.codecogs.com/png.latex?(%5Clambda_j,%5Cmathbf%7Bw%7D_j)">, leer <img src="https://latex.codecogs.com/png.latex?%5Cpi_k">, proyectar, reconstruir, repetir con sklearn y SVD, estandarizar cuando la unidad lo exige, interpretar cargas, y <strong>negar</strong> el uso automático cuando la clase vive en un eje delgado.</p>
<p>El objeto central no es <code>PCA.fit</code>. Es la elipse. Quien ve la elipse puede comprobar cualquier implementación.</p>
</section>
</section>
<section id="guía-rápida-qué-hacer-en-cada-situación" class="level2">
<h2 class="anchored" data-anchor-id="guía-rápida-qué-hacer-en-cada-situación">6. Guía rápida: ¿qué hacer en cada situación?</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Situación</th>
<th>Qué usar</th>
<th>Por qué</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Visualizar <img src="https://latex.codecogs.com/png.latex?p%3E3"></td>
<td>Primeros 2–3 PCs + <em>scree</em></td>
<td>Son las coordenadas de máximo ancho</td>
</tr>
<tr class="even">
<td>Muchas columnas correlacionadas</td>
<td>PCA sobre <img src="https://latex.codecogs.com/png.latex?X"> estandarizada</td>
<td>Ortogonaliza y comprime redundancia</td>
</tr>
<tr class="odd">
<td>Unidades distintas</td>
<td><code>StandardScaler</code> y <em>luego</em> PCA</td>
<td>Si no, gana la columna de mayor rango</td>
</tr>
<tr class="even">
<td>¿Cuántos ejes retener?</td>
<td>Codo, <img src="https://latex.codecogs.com/png.latex?%5CPi_k">, reconstrucción, dominio</td>
<td>No hay umbral universal</td>
</tr>
<tr class="odd">
<td>¿De qué está hecho un PC?</td>
<td>Cargas <img src="https://latex.codecogs.com/png.latex?W_%7B%5Ccdot%20k%7D"></td>
<td>El nombre es el bloque, no una sola variable</td>
</tr>
<tr class="even">
<td>Comprobar la implementación</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Clambda"> y <img src="https://latex.codecogs.com/png.latex?%5Cpi"> vs sklearn; ejes salvo signo</td>
<td>SVD y <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7Beigh%7D(%5CSigma)"> coinciden</td>
</tr>
<tr class="odd">
<td>Hay <img src="https://latex.codecogs.com/png.latex?y"> y se quiere predecir</td>
<td>No elegir <img src="https://latex.codecogs.com/png.latex?k"> solo con varianza</td>
<td>La señal puede vivir en un eje delgado</td>
</tr>
<tr class="even">
<td>Forma no lineal</td>
<td>PCA no basta</td>
<td>El subespacio lineal no es la variedad</td>
</tr>
</tbody>
</table>
<p><strong>Regla de comunicación:</strong> indicar si se estandarizó, el <img src="https://latex.codecogs.com/png.latex?k">, <img src="https://latex.codecogs.com/png.latex?%5CPi_k">, y si se contrastó contra un objetivo.</p>
</section>
<section id="guía-práctica-para-reportar-un-pca" class="level2">
<h2 class="anchored" data-anchor-id="guía-práctica-para-reportar-un-pca">7. Guía práctica para reportar un PCA</h2>
<section id="paso-1-espacio" class="level3">
<h3 class="anchored" data-anchor-id="paso-1-espacio">Paso 1: espacio</h3>
<p><img src="https://latex.codecogs.com/png.latex?n">, <img src="https://latex.codecogs.com/png.latex?p">, unidades, si se centró (sí) y si se estandarizó (decisión).</p>
</section>
<section id="paso-2-espectro" class="level3">
<h3 class="anchored" data-anchor-id="paso-2-espectro">Paso 2: espectro</h3>
<p>Tabla <img src="https://latex.codecogs.com/png.latex?%5Clambda_k">, <img src="https://latex.codecogs.com/png.latex?%5Cpi_k">, <img src="https://latex.codecogs.com/png.latex?%5CPi_k">. <em>Scree</em> y curva acumulada.</p>
</section>
<section id="paso-3-ejes" class="level3">
<h3 class="anchored" data-anchor-id="paso-3-ejes">Paso 3: ejes</h3>
<p>Cargas de los <img src="https://latex.codecogs.com/png.latex?k"> retenidos. Una frase por componente: qué bloque de variables lo define.</p>
</section>
<section id="paso-4-calidad" class="level3">
<h3 class="anchored" data-anchor-id="paso-4-calidad">Paso 4: calidad</h3>
<p>Error de reconstrucción o varianza no explicada <img src="https://latex.codecogs.com/png.latex?%5Csum_%7Bj%3Ek%7D%5Clambda_j">. Si hay <img src="https://latex.codecogs.com/png.latex?y">, una métrica simple sobre <img src="https://latex.codecogs.com/png.latex?Z_k"> frente a <img src="https://latex.codecogs.com/png.latex?X">.</p>
</section>
<section id="paso-5-redactar" class="level3">
<h3 class="anchored" data-anchor-id="paso-5-redactar">Paso 5: redactar</h3>
<blockquote class="blockquote">
<p>“Sobre <code>[variables]</code>, estandarizadas/no, los primeros <img src="https://latex.codecogs.com/png.latex?k=%5C_"> componentes conservan <code>[Π]%</code> de la varianza. PC1 agrupa <code>[bloque]</code>; PC2 agrupa <code>[bloque]</code>. Se retiene <img src="https://latex.codecogs.com/png.latex?k"> porque <code>[quiebre del gráfico / reconstrucción / dominio]</code>. Limitación: <code>[varianza ≠ objetivo / linealidad / escala]</code>.”</p>
</blockquote>
</section>
<section id="caso-real-178-vinos-italianos-uci-wine" class="level3">
<h3 class="anchored" data-anchor-id="caso-real-178-vinos-italianos-uci-wine">Caso real: 178 vinos italianos (UCI Wine)</h3>
<p>Se aplica la plantilla de arriba a un dataset <strong>real</strong>: 178 vinos de tres cepas de la misma región de Italia, con 13 medidas químicas (alcohol, ácidos, fenoles, color, prolina, etc.). Las unidades no son comparables: el alcohol va ~11–15 y la prolina, cientos o miles. Por eso se <strong>estandariza</strong> antes del PCA.</p>
<p>El cultivar (cepa) existe como etiqueta. Aquí no se usa para elegir los ejes —PCA no ve <img src="https://latex.codecogs.com/png.latex?y">—; solo se mira al final, para el paso 4.</p>
<div id="c079" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:12:50.760900Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:12:50.760732Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:12:51.368131Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:12:51.367642Z&quot;}}" data-execution_count="23">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb44" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb44-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.datasets <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> load_wine</span>
<span id="cb44-2"></span>
<span id="cb44-3">wine <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> load_wine()</span>
<span id="cb44-4">X_wine <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> wine.data</span>
<span id="cb44-5">y_wine <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> wine.target</span>
<span id="cb44-6">nombres_wine <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb44-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"alcohol"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"acido_malico"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cenizas"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"alcalinidad_cenizas"</span>,</span>
<span id="cb44-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"magnesio"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fenoles_totales"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"flavonoides"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fenoles_no_flavonoides"</span>,</span>
<span id="cb44-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"proantocianidinas"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"intensidad_color"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tono"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"od280_od315"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prolina"</span>,</span>
<span id="cb44-10">]</span>
<span id="cb44-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n ="</span>, X_wine.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  p ="</span>, X_wine.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb44-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Unidades distintas: alcohol ~"</span>, X_wine[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-"</span>, X_wine[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb44-13">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" | prolina ~"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(X_wine[:, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(X_wine[:, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()))</span>
<span id="cb44-14"></span>
<span id="cb44-15">X_wine_s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler().fit_transform(X_wine)</span>
<span id="cb44-16">pca_wine <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_manual(X_wine_s)</span>
<span id="cb44-17">pi_w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca_wine[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> pca_wine[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()</span>
<span id="cb44-18">acum_w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cumsum(pi_w)</span>
<span id="cb44-19"></span>
<span id="cb44-20">espectro <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb44-21">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"k"</span>: np.arange(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>),</span>
<span id="cb44-22">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambda"</span>: pca_wine[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>],</span>
<span id="cb44-23">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pi"</span>: pi_w,</span>
<span id="cb44-24">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Pi"</span>: acum_w,</span>
<span id="cb44-25">})</span>
<span id="cb44-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb44-27"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Paso 2 — espectro (primeros 6):"</span>)</span>
<span id="cb44-28">display(espectro.head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb44-29"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Π_2 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>acum_w[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%   Π_3 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>acum_w[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%   Π_5 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>acum_w[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span>
<span id="cb44-30"></span>
<span id="cb44-31">graficar_scree(pca_wine[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambdas"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Wine: varianza por componente (datos reales, estandarizados)"</span>)</span>
<span id="cb44-32"></span>
<span id="cb44-33">k_rep <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span></span>
<span id="cb44-34">cargas_w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb44-35">    pca_wine[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>][:, :k_rep],</span>
<span id="cb44-36">    index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombres_wine,</span>
<span id="cb44-37">    columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>j<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(k_rep)],</span>
<span id="cb44-38">)</span>
<span id="cb44-39"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Paso 3 — cargas de los 3 ejes retenidos:"</span>)</span>
<span id="cb44-40">display(cargas_w.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb44-41">graficar_cargas(pca_wine[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"W"</span>], nombres_wine, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cargas (Wine, k=2 para leer los bloques)"</span>, k<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb44-42"></span>
<span id="cb44-43">Xhat3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> reconstruir(pca_wine, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb44-44">mse3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean((X_wine_s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> Xhat3) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb44-45"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Paso 4 — MSE de reconstrucción con k=3: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mse3<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb44-46"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Varianza no usada (1-Π_3):"</span>, <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>acum_w[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span>
<span id="cb44-47"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Media de PC1 por cepa:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>([pca_wine[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>][y_wine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span>c, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].mean() <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> c <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb44-48"></span>
<span id="cb44-49">graficar_nube_2d(</span>
<span id="cb44-50">    pca_wine[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z"</span>][:, :<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>],</span>
<span id="cb44-51">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Wine: las tres cepas en PC1–PC2 (PCA no usó la etiqueta para elegir ejes)"</span>,</span>
<span id="cb44-52">    clases<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y_wine,</span>
<span id="cb44-53">    ejes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PC2"</span>),</span>
<span id="cb44-54">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>n = 178   p = 13
Unidades distintas: alcohol ~ 11.0 - 14.8  | prolina ~ 278 - 1680

Paso 2 — espectro (primeros 6):</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">k</th>
<th data-quarto-table-cell-role="th">lambda</th>
<th data-quarto-table-cell-role="th">pi</th>
<th data-quarto-table-cell-role="th">Pi</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">0</th>
<td>1</td>
<td>4.732</td>
<td>0.362</td>
<td>0.362</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">1</th>
<td>2</td>
<td>2.511</td>
<td>0.192</td>
<td>0.554</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">2</th>
<td>3</td>
<td>1.454</td>
<td>0.111</td>
<td>0.665</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">3</th>
<td>4</td>
<td>0.924</td>
<td>0.071</td>
<td>0.736</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">4</th>
<td>5</td>
<td>0.858</td>
<td>0.066</td>
<td>0.802</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">5</th>
<td>6</td>
<td>0.645</td>
<td>0.049</td>
<td>0.851</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Π_2 = 55.4%   Π_3 = 66.5%   Π_5 = 80.2%</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-24-output-4.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Paso 3 — cargas de los 3 ejes retenidos:</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">PC1</th>
<th data-quarto-table-cell-role="th">PC2</th>
<th data-quarto-table-cell-role="th">PC3</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th data-quarto-table-cell-role="th">alcohol</th>
<td>-0.14</td>
<td>0.48</td>
<td>0.21</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">acido_malico</th>
<td>0.25</td>
<td>0.22</td>
<td>-0.09</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">cenizas</th>
<td>0.00</td>
<td>0.32</td>
<td>-0.63</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">alcalinidad_cenizas</th>
<td>0.24</td>
<td>-0.01</td>
<td>-0.61</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">magnesio</th>
<td>-0.14</td>
<td>0.30</td>
<td>-0.13</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">fenoles_totales</th>
<td>-0.39</td>
<td>0.07</td>
<td>-0.15</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">flavonoides</th>
<td>-0.42</td>
<td>-0.00</td>
<td>-0.15</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">fenoles_no_flavonoides</th>
<td>0.30</td>
<td>0.03</td>
<td>-0.17</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">proantocianidinas</th>
<td>-0.31</td>
<td>0.04</td>
<td>-0.15</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">intensidad_color</th>
<td>0.09</td>
<td>0.53</td>
<td>0.14</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">tono</th>
<td>-0.30</td>
<td>-0.28</td>
<td>-0.09</td>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">od280_od315</th>
<td>-0.38</td>
<td>-0.16</td>
<td>-0.17</td>
</tr>
<tr class="odd">
<th data-quarto-table-cell-role="th">prolina</th>
<td>-0.29</td>
<td>0.36</td>
<td>0.13</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-24-output-7.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Paso 4 — MSE de reconstrucción con k=3: 0.335
Varianza no usada (1-Π_3): 33.5%
Media de PC1 por cepa: [-2.28  0.04  2.75]</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/index_files/figure-html/cell-24-output-9.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Los cinco pasos, aplicados</strong></p>
<ol type="1">
<li><strong>Espacio.</strong> <img src="https://latex.codecogs.com/png.latex?n=178">, <img src="https://latex.codecogs.com/png.latex?p=13"> medidas químicas de vinos (UCI Wine). Unidades distintas → se <strong>estandarizó</strong>. Se centró (siempre).</li>
<li><strong>Espectro.</strong> <img src="https://latex.codecogs.com/png.latex?%5Cpi_1=36.2%5C%25">, <img src="https://latex.codecogs.com/png.latex?%5Cpi_2=19.2%5C%25">, <img src="https://latex.codecogs.com/png.latex?%5Cpi_3=11.1%5C%25">. Acumulado: <img src="https://latex.codecogs.com/png.latex?%5CPi_2=55.4%5C%25">, <img src="https://latex.codecogs.com/png.latex?%5CPi_3=66.5%5C%25">, <img src="https://latex.codecogs.com/png.latex?%5CPi_5=80.2%5C%25">. El gráfico se aplana después de <img src="https://latex.codecogs.com/png.latex?k=3">.</li>
<li><strong>Ejes.</strong> PC1 es el bloque <strong>fenólico</strong> (flavonoides, fenoles totales, OD280, proantocianidinas, tono; en sentido opuesto, ácido málico y fenoles no flavonoides). PC2 es <strong>cuerpo y color</strong> (intensidad de color, alcohol, prolina, cenizas, magnesio).</li>
<li><strong>Calidad.</strong> Con <img src="https://latex.codecogs.com/png.latex?k=3"> queda fuera el <img src="https://latex.codecogs.com/png.latex?33.5%5C%25"> de la varianza. Las tres cepas se separan a ojo en PC1–PC2, aunque PCA <strong>no</strong> usó la etiqueta para construir los ejes.</li>
<li><strong>Reporte.</strong></li>
</ol>
<blockquote class="blockquote">
<p>Sobre las 13 medidas químicas de 178 vinos italianos (UCI Wine), estandarizadas, los primeros <img src="https://latex.codecogs.com/png.latex?k=3"> componentes conservan el <img src="https://latex.codecogs.com/png.latex?66.5%5C%25"> de la varianza. PC1 agrupa el bloque fenólico (flavonoides, fenoles, OD280, tono); PC2 agrupa cuerpo y color (intensidad de color, alcohol, prolina). Se retiene <img src="https://latex.codecogs.com/png.latex?k=3"> porque el gráfico de <img src="https://latex.codecogs.com/png.latex?%5Clambda_k"> se aplana después del tercer eje y <img src="https://latex.codecogs.com/png.latex?k=2"> ya basta para ver las cepas; harían falta <img src="https://latex.codecogs.com/png.latex?k=5"> si se exigiera la convención del <img src="https://latex.codecogs.com/png.latex?80%5C%25">. Limitación: el <img src="https://latex.codecogs.com/png.latex?33.5%5C%25"> no usado podría contener señal de cepa; PCA se usó para describir <img src="https://latex.codecogs.com/png.latex?X">, no para predecir el cultivar.</p>
</blockquote>
</section>
</section>
<section id="puente-hacia-las-siguientes-sesiones" class="level2">
<h2 class="anchored" data-anchor-id="puente-hacia-las-siguientes-sesiones">8. Puente hacia las siguientes sesiones</h2>
<p>El espacio <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BR%7D%5Ep"> ya no es un bloque rígido: se puede rotar, ordenar y cortar. La probabilidad y la inferencia que siguen trabajan <em>sobre</em> coordenadas —a veces las originales, a veces unas transformadas.</p>
<p>PCA no cierra el modelado. Deja un <img src="https://latex.codecogs.com/png.latex?Z_k"> con el que más adelante se ajusta una recta, se clasifica o se valida. La precaución de la etapa 14 viaja con ese <img src="https://latex.codecogs.com/png.latex?Z_k">: compactar <img src="https://latex.codecogs.com/png.latex?X"> no autoriza a olvidar <img src="https://latex.codecogs.com/png.latex?y">.</p>
</section>
<section id="cierre" class="level2">
<h2 class="anchored" data-anchor-id="cierre">9. Cierre</h2>
<p>Este notebook deja una construcción completa de PCA:</p>
<ul>
<li>el problema de la alta dimensionalidad como pérdida de contraste entre distancias,</li>
<li>el centrado y <img src="https://latex.codecogs.com/png.latex?%5CSigma"> como forma de la nube,</li>
<li>componentes = autovectores, varianza = autovalores,</li>
<li>proyección, varianza explicada, reconstrucción,</li>
<li>equivalencia SVD / <code>eigh</code> / scikit-learn (salvo signo),</li>
<li>el efecto de la escala y la lectura de cargas,</li>
<li>el contrapunto: maximizar varianza no es maximizar señal,</li>
<li>un caso real (vinos UCI) reportado con la plantilla de la sección 7.</li>
</ul>
<p><strong>Resultado esperado:</strong> el estudiante puede dibujar la elipse, escribir <img src="https://latex.codecogs.com/png.latex?%5CSigma%5Cmathbf%7Bw%7D=%5Clambda%5Cmathbf%7Bw%7D">, elegir <img src="https://latex.codecogs.com/png.latex?k"> con <img src="https://latex.codecogs.com/png.latex?%5CPi_k"> <em>y</em> con un argumento, reproducir el resultado en sklearn y explicar un caso en el que quedarse con PC1 sería un error.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>pca</category>
  <category>dimensionalidad</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/basico/07-reduccion-dimensionalidad-pca/</guid>
  <pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Estadística para IA — 8. Fundamentos de probabilidad</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/basico/08-fundamentos-probabilidad/</link>
  <description><![CDATA[ 




<section id="sesión-8-fundamentos-de-probabilidad" class="level1">
<h1>Sesión 8 — Fundamentos de Probabilidad</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado es Científico de Datos, Arquitecto de IA, Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), consultor y docente universitario, trabaja en la intersección entre Data Science, Inteligencia Artificial, Big Data e IoT, transformando problemas reales en soluciones aplicadas.</p>
<p>De la teoría a la práctica, un problema a la vez.</p>
</section>
<section id="probabilidad-aplicada-a-la-incertidumbre" class="level2">
<h2 class="anchored" data-anchor-id="probabilidad-aplicada-a-la-incertidumbre">Probabilidad Aplicada a la Incertidumbre</h2>
<p>Un modelo no “sabe” el futuro: asigna <strong>números entre 0 y 1</strong> a resultados posibles. Esa es la probabilidad. Sin ella no hay clasificación, no hay intervalos y no hay forma honesta de decir “estoy más seguro de A que de B”.</p>
<p>Este notebook construye el lenguaje mínimo: <strong>experimento aleatorio</strong>, <strong>espacio muestral</strong>, <strong>evento</strong>, <strong>probabilidad condicional</strong>, <strong>independencia</strong> y el <strong>teorema de Bayes</strong>. La práctica es simular: contar frecuencias y ver cómo se acercan a la fórmula. El contraste que importa es clásico y cruelmente útil: <em>una prueba muy sensible no implica que un positivo sea casi seguro</em> —si el caso es raro.</p>
<p>Contexto: monedas y dados para fijar las definiciones; después una <strong>prueba diagnóstica</strong> y un <strong>filtro de fraude</strong> (clasificación binaria).</p>
<p>Electiva I — Estadística Aplicada a la Inteligencia Artificial · Módulo 3 · Sesión 8</p>
</section>
<section id="objetivos" class="level2">
<h2 class="anchored" data-anchor-id="objetivos">Objetivos</h2>
<ul>
<li>Distinguir <strong>experimento</strong>, <strong>espacio muestral</strong> <img src="https://latex.codecogs.com/png.latex?%5COmega"> y <strong>evento</strong>.</li>
<li>Estimar una probabilidad por <strong>frecuencia relativa</strong> y compararla con la fórmula.</li>
<li>Calcular <strong>probabilidad condicional</strong> <img src="https://latex.codecogs.com/png.latex?P(A%5Cmid%20B)"> e interpretarla como un recorte del espacio.</li>
<li>Decidir si dos eventos son <strong>independientes</strong> (y no confundirlos con “no pueden ocurrir a la vez”).</li>
<li>Aplicar la <strong>probabilidad total</strong> y el <strong>teorema de Bayes</strong>.</li>
<li>Usar Bayes en un problema de <strong>clasificación binaria</strong> (prueba diagnóstica / alerta de fraude).</li>
<li>Redactar <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bclase%7D%5Cmid%20%5Ctext%7Bevidencia%7D)"> sin invertir el condicional.</li>
</ul>
<blockquote class="blockquote">
<p>Nota: se recomienda ejecutar las celdas en orden. Las fórmulas usan LaTeX; si no se ven renderizadas, abre el notebook en Jupyter o Colab.</p>
</blockquote>
</section>
<section id="el-lenguaje-de-lo-incierto" class="level2">
<h2 class="anchored" data-anchor-id="el-lenguaje-de-lo-incierto">1. El lenguaje de lo incierto</h2>
<section id="experimento-aleatorio" class="level3">
<h3 class="anchored" data-anchor-id="experimento-aleatorio">1.1 Experimento aleatorio</h3>
<p>Un <strong>experimento aleatorio</strong> es un procedimiento con más de un resultado posible, que se puede repetir en las mismas condiciones, y cuyo resultado individual no se conoce de antemano. Lanzar un dado, extraer un correo, medir si un cliente incumple: los tres caben.</p>
</section>
<section id="espacio-muestral" class="level3">
<h3 class="anchored" data-anchor-id="espacio-muestral">1.2 Espacio muestral</h3>
<p>El <strong>espacio muestral</strong> <img src="https://latex.codecogs.com/png.latex?%5COmega"> es el conjunto de todos los resultados simples que se consideran. Para un dado honesto, <img src="https://latex.codecogs.com/png.latex?%5COmega=%5C%7B1,2,3,4,5,6%5C%7D">. Cada elemento de <img src="https://latex.codecogs.com/png.latex?%5COmega"> se llama <strong>resultado</strong> (o punto muestral).</p>
<p>Definir <img src="https://latex.codecogs.com/png.latex?%5COmega"> es una decisión: si solo importa “par o impar”, se puede trabajar con <img src="https://latex.codecogs.com/png.latex?%5COmega=%5C%7B%5Ctext%7Bpar%7D,%5Ctext%7Bimpar%7D%5C%7D">. El espacio no es la realidad; es el mapa que se eligió.</p>
</section>
<section id="evento" class="level3">
<h3 class="anchored" data-anchor-id="evento">1.3 Evento</h3>
<p>Un <strong>evento</strong> <img src="https://latex.codecogs.com/png.latex?A"> es un subconjunto de <img src="https://latex.codecogs.com/png.latex?%5COmega">. “Sacar par” es <img src="https://latex.codecogs.com/png.latex?A=%5C%7B2,4,6%5C%7D">. El evento ocurre si el resultado cae en <img src="https://latex.codecogs.com/png.latex?A">.</p>
<p>Operaciones que se usan todo el tiempo:</p>
<ul>
<li><strong>Complemento</strong> <img src="https://latex.codecogs.com/png.latex?A%5Ec">: “no ocurrió <img src="https://latex.codecogs.com/png.latex?A">”. <img src="https://latex.codecogs.com/png.latex?P(A%5Ec)=1-P(A)">.</li>
<li><strong>Unión</strong> <img src="https://latex.codecogs.com/png.latex?A%5Ccup%20B">: ocurrió <img src="https://latex.codecogs.com/png.latex?A"> o <img src="https://latex.codecogs.com/png.latex?B"> o ambos.</li>
<li><strong>Intersección</strong> <img src="https://latex.codecogs.com/png.latex?A%5Ccap%20B">: ocurrieron los dos.</li>
</ul>
<p>Dos eventos son <strong>disjuntos</strong> (mutuamente excluyentes) si <img src="https://latex.codecogs.com/png.latex?A%5Ccap%20B=%5Cemptyset">: no pueden ocurrir a la vez. Eso <strong>no</strong> es lo mismo que ser independientes.</p>
</section>
<section id="probabilidad-reglas-de-kolmogorov" class="level3">
<h3 class="anchored" data-anchor-id="probabilidad-reglas-de-kolmogorov">1.4 Probabilidad (reglas de Kolmogorov)</h3>
<p>Una probabilidad <img src="https://latex.codecogs.com/png.latex?P"> asigna a cada evento un número que cumple:</p>
<ol type="1">
<li><img src="https://latex.codecogs.com/png.latex?P(A)%5Cge%200">,</li>
<li><img src="https://latex.codecogs.com/png.latex?P(%5COmega)=1">,</li>
<li>si <img src="https://latex.codecogs.com/png.latex?A"> y <img src="https://latex.codecogs.com/png.latex?B"> son disjuntos, <img src="https://latex.codecogs.com/png.latex?P(A%5Ccup%20B)=P(A)+P(B)">.</li>
</ol>
<p>De ahí salen las reglas de trabajo: <img src="https://latex.codecogs.com/png.latex?P(A%5Ec)=1-P(A)"> y, en general,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(A%5Ccup%20B)=P(A)+P(B)-P(A%5Ccap%20B).%0A"></p>
<p><strong>Lectura frecuentista (la que se simula aquí):</strong> si el experimento se repite <img src="https://latex.codecogs.com/png.latex?n"> veces en las mismas condiciones,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(A)%20%5Capprox%20%5Cfrac%7B%5Ctext%7Bveces%20que%20ocurre%20%7DA%7D%7Bn%7D.%0A"></p>
<p>Cuando <img src="https://latex.codecogs.com/png.latex?n"> crece, esa fracción se estabiliza. Eso no “demuestra” los axiomas; los hace visibles.</p>
</section>
<section id="probabilidad-condicional" class="level3">
<h3 class="anchored" data-anchor-id="probabilidad-condicional">1.5 Probabilidad condicional</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(A%5Cmid%20B)=%5Cfrac%7BP(A%5Ccap%20B)%7D%7BP(B)%7D%20%5Cqquad%20(P(B)%3E0).%0A"></p>
<p>Se lee: <em>entre las veces en que ya ocurrió <img src="https://latex.codecogs.com/png.latex?B">, qué fracción son también <img src="https://latex.codecogs.com/png.latex?A"></em>. El condicional <strong>recorta</strong> <img src="https://latex.codecogs.com/png.latex?%5COmega"> a <img src="https://latex.codecogs.com/png.latex?B"> y vuelve a normalizar. No es “la probabilidad de A y después B” en el tiempo; es un cambio de denominador.</p>
</section>
<section id="independencia" class="level3">
<h3 class="anchored" data-anchor-id="independencia">1.6 Independencia</h3>
<p><img src="https://latex.codecogs.com/png.latex?A"> y <img src="https://latex.codecogs.com/png.latex?B"> son <strong>independientes</strong> si saber uno no cambia la probabilidad del otro:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(A%5Cmid%20B)=P(A)%20%5Ciff%20P(A%5Ccap%20B)=P(A)%5C,P(B).%0A"></p>
<p>Disjuntos e independientes casi nunca coinciden: si son disjuntos y ambos tienen probabilidad positiva, saber que ocurrió <img src="https://latex.codecogs.com/png.latex?A"> <em>fuerza</em> <img src="https://latex.codecogs.com/png.latex?P(B%5Cmid%20A)=0%5Cneq%20P(B)">.</p>
</section>
<section id="probabilidad-total-y-bayes" class="level3">
<h3 class="anchored" data-anchor-id="probabilidad-total-y-bayes">1.7 Probabilidad total y Bayes</h3>
<p>Si <img src="https://latex.codecogs.com/png.latex?H"> y <img src="https://latex.codecogs.com/png.latex?H%5Ec"> parten <img src="https://latex.codecogs.com/png.latex?%5COmega">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(E)=P(E%5Cmid%20H)P(H)+P(E%5Cmid%20H%5Ec)P(H%5Ec).%0A"></p>
<p>El <strong>teorema de Bayes</strong> invierte el condicional:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(H%5Cmid%20E)=%5Cfrac%7BP(E%5Cmid%20H)%5C,P(H)%7D%7BP(E)%7D.%0A"></p>
<p>Nombres que usa la IA:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Símbolo</th>
<th>Nombre</th>
<th>Pregunta</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><img src="https://latex.codecogs.com/png.latex?P(H)"></td>
<td><strong>Prior</strong></td>
<td>¿Qué tan frecuente es la clase <em>antes</em> de ver el dato?</td>
</tr>
<tr class="even">
<td><img src="https://latex.codecogs.com/png.latex?P(E%5Cmid%20H)"></td>
<td><strong>Verosimilitud</strong></td>
<td>Si la clase es <img src="https://latex.codecogs.com/png.latex?H">, ¿qué tan creíble es el dato?</td>
</tr>
<tr class="odd">
<td><img src="https://latex.codecogs.com/png.latex?P(H%5Cmid%20E)"></td>
<td><strong>Posterior</strong></td>
<td>Ya visto el dato, ¿qué tan creíble es la clase?</td>
</tr>
</tbody>
</table>
<p>Un clasificador binario, en el fondo, compara <img src="https://latex.codecogs.com/png.latex?P(H=1%5Cmid%20x)"> con <img src="https://latex.codecogs.com/png.latex?P(H=0%5Cmid%20x)">. Bayes es esa comparación hecha explícita.</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Pregunta</th>
<th>Herramienta</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>¿Qué resultados admito?</td>
<td><img src="https://latex.codecogs.com/png.latex?%5COmega"></td>
</tr>
<tr class="even">
<td>¿Qué subconjunto me interesa?</td>
<td>Evento</td>
</tr>
<tr class="odd">
<td>¿Qué tan frecuente es, sin otra información?</td>
<td><img src="https://latex.codecogs.com/png.latex?P(A)"></td>
</tr>
<tr class="even">
<td>¿Y si ya sé que ocurrió <img src="https://latex.codecogs.com/png.latex?B">?</td>
<td><img src="https://latex.codecogs.com/png.latex?P(A%5Cmid%20B)"></td>
</tr>
<tr class="odd">
<td>¿Saber <img src="https://latex.codecogs.com/png.latex?B"> cambia <img src="https://latex.codecogs.com/png.latex?A">?</td>
<td>Independencia</td>
</tr>
<tr class="even">
<td>Tengo <img src="https://latex.codecogs.com/png.latex?P(E%5Cmid%20H)"> y quiero <img src="https://latex.codecogs.com/png.latex?P(H%5Cmid%20E)"></td>
<td>Bayes</td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="por-qué-importa-en-ia-y-machine-learning" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-importa-en-ia-y-machine-learning">2. Por qué importa en IA y Machine Learning</h2>
<p>El modelo no entrega una verdad: entrega una <strong>incertidumbre numérica</strong>.</p>
<ul>
<li>En <strong>clasificación</strong>, la salida útil es <img src="https://latex.codecogs.com/png.latex?P(y=1%5Cmid%20x)">, no solo una etiqueta.</li>
<li>Un <strong>falso positivo</strong> y un <strong>falso negativo</strong> no pesan igual si la clase positiva es rara (fraude, enfermedad, spam agresivo). Bayes obliga a poner la <strong>frecuencia base</strong> <img src="https://latex.codecogs.com/png.latex?P(y=1)"> sobre la mesa.</li>
<li><strong>Naive Bayes</strong> asume independencia entre <em>features</em> dado <img src="https://latex.codecogs.com/png.latex?y">. Esa hipótesis se entiende —y se critica— solo si se entiende independencia.</li>
<li>En <strong>calibración</strong>, “el modelo dijo 0.8” debería significar que, de cada 100 casos así, cerca de 80 son positivos. Eso es frecuencia relativa.</li>
</ul>
<p><strong>Idea central:</strong> <img src="https://latex.codecogs.com/png.latex?P(A%5Cmid%20B)"> y <img src="https://latex.codecogs.com/png.latex?P(B%5Cmid%20A)"> no son el mismo número. Confundirlos es el error que convierte una prueba buena en una alarma inútil.</p>
</section>
<section id="flujo-recomendado-de-trabajo" class="level2">
<h2 class="anchored" data-anchor-id="flujo-recomendado-de-trabajo">3. Flujo recomendado de trabajo</h2>
<ol type="1">
<li><strong>Escribir <img src="https://latex.codecogs.com/png.latex?%5COmega"> y los eventos</strong> con palabras y con conjuntos.</li>
<li><strong>Decidir si se calcula o se simula.</strong> Lo pequeño se cuenta; lo compuesto se simula y se contrasta con la fórmula.</li>
<li><strong>Preguntar qué está a la derecha de la barra.</strong> <img src="https://latex.codecogs.com/png.latex?P(A%5Cmid%20B)"> condiciona a <img src="https://latex.codecogs.com/png.latex?B">, no a <img src="https://latex.codecogs.com/png.latex?A">.</li>
<li><strong>Separar disjuntos de independientes</strong> antes de multiplicar o sumar.</li>
<li><strong>Si se invierte un condicional, usar Bayes</strong> y escribir prior, verosimilitud y evidencia.</li>
<li><strong>Traducir al problema:</strong> ¿qué es la clase? ¿qué es la evidencia? ¿cuál es la frecuencia base?</li>
</ol>
<p><strong>Criterio general:</strong> un número de probabilidad sin el evento escrito es un número suelto.</p>
</section>
<section id="preparar-el-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparar-el-entorno">4. Preparar el entorno</h2>
<div id="c009" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:12.484778Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:12.484297Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:13.601172Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:13.600700Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb1-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Python:"</span>, sys.version.split()[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-7"></span>
<span id="cb1-8">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-9"></span>
<span id="cb1-10">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"figure.figsize"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-11">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"axes.grid"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb1-12">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grid.alpha"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span></span>
<span id="cb1-13"></span>
<span id="cb1-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Entorno listo: numpy, pandas, matplotlib."</span>)</span>
<span id="cb1-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pandas:"</span>, pd.__version__, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"| numpy:"</span>, np.__version__)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Python: 3.13.9
Entorno listo: numpy, pandas, matplotlib.
pandas: 2.3.3 | numpy: 2.3.5</code></pre>
</div>
</div>
<section id="funciones-de-visualización-definidas-una-sola-vez" class="level3">
<h3 class="anchored" data-anchor-id="funciones-de-visualización-definidas-una-sola-vez">Funciones de visualización (definidas una sola vez)</h3>
<p>Cada etapa solo <strong>llama</strong> a la función. El detalle del gráfico queda aquí.</p>
<div id="c011" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:13.602991Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:13.602764Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:13.610806Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:13.610410Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_estabilizacion(ocurrencias, p_teorica, titulo, etiqueta_p<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(A)"</span>):</span>
<span id="cb3-2">    n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(ocurrencias) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb3-3">    frec <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cumsum(ocurrencias) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n</span>
<span id="cb3-4">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>))</span>
<span id="cb3-5">    ax.plot(n, frec, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"frecuencia relativa"</span>)</span>
<span id="cb3-6">    ax.axhline(p_teorica, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>etiqueta_p<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>p_teorica<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-7">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"número de repeticiones n"</span>)</span>
<span id="cb3-8">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fracción de éxitos"</span>)</span>
<span id="cb3-9">    ax.set_title(titulo)</span>
<span id="cb3-10">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-11">    ax.set_ylim(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb3-12">    plt.tight_layout()</span>
<span id="cb3-13">    plt.show()</span>
<span id="cb3-14"></span>
<span id="cb3-15"></span>
<span id="cb3-16"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_barras_probs(etiquetas, teoricas, estimadas, titulo):</span>
<span id="cb3-17">    x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(etiquetas))</span>
<span id="cb3-18">    w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.38</span></span>
<span id="cb3-19">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>))</span>
<span id="cb3-20">    ax.bar(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, teoricas, w, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fórmula"</span>)</span>
<span id="cb3-21">    ax.bar(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, estimadas, w, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"simulación"</span>)</span>
<span id="cb3-22">    ax.set_xticks(x, etiquetas)</span>
<span id="cb3-23">    ax.set_ylim(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb3-24">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"probabilidad"</span>)</span>
<span id="cb3-25">    ax.set_title(titulo)</span>
<span id="cb3-26">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-27">    plt.tight_layout()</span>
<span id="cb3-28">    plt.show()</span>
<span id="cb3-29"></span>
<span id="cb3-30"></span>
<span id="cb3-31"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_prior_vs_posterior(nombres, prior, posterior, titulo):</span>
<span id="cb3-32">    x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(nombres))</span>
<span id="cb3-33">    w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.38</span></span>
<span id="cb3-34">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>))</span>
<span id="cb3-35">    ax.bar(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, prior, w, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"antes de la evidencia (prior)"</span>)</span>
<span id="cb3-36">    ax.bar(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, posterior, w, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"después (posterior)"</span>)</span>
<span id="cb3-37">    ax.set_xticks(x, nombres)</span>
<span id="cb3-38">    ax.set_ylim(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb3-39">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"probabilidad"</span>)</span>
<span id="cb3-40">    ax.set_title(titulo)</span>
<span id="cb3-41">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-42">    plt.tight_layout()</span>
<span id="cb3-43">    plt.show()</span>
<span id="cb3-44"></span>
<span id="cb3-45"></span>
<span id="cb3-46"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_conteos_prueba(enfermos_pos, sanos_pos, enfermos_neg, sanos_neg, titulo):</span>
<span id="cb3-47">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Izquierda: toda la población. Derecha: solo los positivos (ahí se decide P(E | +))."""</span></span>
<span id="cb3-48">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.4</span>), constrained_layout<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-49">    b1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].bar([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], [enfermos_pos, enfermos_neg], <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"enfermos"</span>)</span>
<span id="cb3-50">    b2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].bar([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.4</span>], [sanos_pos, sanos_neg], <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sanos"</span>)</span>
<span id="cb3-51">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].bar_label(b1, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-52">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].bar_label(b2, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-53">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_xticks([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>], [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prueba +"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prueba −"</span>])</span>
<span id="cb3-54">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"personas (simulación)"</span>)</span>
<span id="cb3-55">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Toda la población"</span>)</span>
<span id="cb3-56">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-57">    total_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> enfermos_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> sanos_pos</span>
<span id="cb3-58">    b3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].bar([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"enfermos"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sanos"</span>], [enfermos_pos, sanos_pos], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>])</span>
<span id="cb3-59">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].bar_label(b3, labels<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>enfermos_pos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>enfermos_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> total_pos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)"</span>,</span>
<span id="cb3-60">                                  <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>sanos_pos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>sanos_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> total_pos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.0%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)"</span>], fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span>
<span id="cb3-61">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"personas con prueba +"</span>)</span>
<span id="cb3-62">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Solo los </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>total_pos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> positivos"</span>)</span>
<span id="cb3-63">    fig.suptitle(titulo)</span>
<span id="cb3-64">    plt.show()</span></code></pre></div></div>
</div>
</section>
</section>
<section id="desarrollo-por-etapas" class="level2">
<h2 class="anchored" data-anchor-id="desarrollo-por-etapas">5. Desarrollo por etapas</h2>
<p>Se parte de un dado y una moneda —<img src="https://latex.codecogs.com/png.latex?%5COmega"> se puede listar— y se llega a Bayes con una prueba diagnóstica y un filtro de fraude. Cada simulación se contrasta con la fórmula.</p>
<section id="etapa-1-experimento-omega-y-eventos" class="level3">
<h3 class="anchored" data-anchor-id="etapa-1-experimento-omega-y-eventos">Etapa 1: Experimento, <img src="https://latex.codecogs.com/png.latex?%5COmega"> y eventos</h3>
<p>Se lanza un dado de seis caras. El espacio muestral es <img src="https://latex.codecogs.com/png.latex?%5COmega=%5C%7B1,2,3,4,5,6%5C%7D">. Tres eventos:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?P"> = par <img src="https://latex.codecogs.com/png.latex?=%5C%7B2,4,6%5C%7D">,</li>
<li><img src="https://latex.codecogs.com/png.latex?M"> = mayor que 4 <img src="https://latex.codecogs.com/png.latex?=%5C%7B5,6%5C%7D">,</li>
<li><img src="https://latex.codecogs.com/png.latex?S"> = seis <img src="https://latex.codecogs.com/png.latex?=%5C%7B6%5C%7D">.</li>
</ul>
<p>Si el dado es <strong>honesto</strong>, cada cara tiene probabilidad <img src="https://latex.codecogs.com/png.latex?1/6">. Entonces <img src="https://latex.codecogs.com/png.latex?P(P)=3/6=1/2">, <img src="https://latex.codecogs.com/png.latex?P(M)=2/6=1/3">, <img src="https://latex.codecogs.com/png.latex?P(S)=1/6">.</p>
<div id="c014" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:13.612373Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:13.612215Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:13.616751Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:13.616265Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">Omega <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>])</span>
<span id="cb4-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Espacio muestral Ω ="</span>, Omega)</span>
<span id="cb4-3"></span>
<span id="cb4-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> P_dado(evento):</span>
<span id="cb4-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(evento) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(Omega)</span>
<span id="cb4-6"></span>
<span id="cb4-7">par <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Omega[Omega <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb4-8">mayor4 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Omega[Omega <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>]</span>
<span id="cb4-9">seis <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Omega[Omega <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>]</span>
<span id="cb4-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P = par         "</span>, par, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  P(P) ="</span>, P_dado(par))</span>
<span id="cb4-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"M = mayor que 4 "</span>, mayor4, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  P(M) ="</span>, P_dado(mayor4))</span>
<span id="cb4-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"S = seis        "</span>, seis, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  P(S) ="</span>, P_dado(seis))</span>
<span id="cb4-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Complemento de P (impar):"</span>, Omega[Omega <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  P ="</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> P_dado(par))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Espacio muestral Ω = [1 2 3 4 5 6]
P = par          [2 4 6]   P(P) = 0.5
M = mayor que 4  [5 6]   P(M) = 0.3333333333333333
S = seis         [6]   P(S) = 0.16666666666666666
Complemento de P (impar): [1 3 5]   P = 0.5</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> Listar <img src="https://latex.codecogs.com/png.latex?%5COmega"> no es burocracia: fija el denominador. Si alguien dice “la probabilidad de par” sin decir de qué experimento, el número no está anclado.</p>
</section>
<section id="etapa-2-la-frecuencia-se-parece-a-p-cuando-n-crece" class="level3">
<h3 class="anchored" data-anchor-id="etapa-2-la-frecuencia-se-parece-a-p-cuando-n-crece">Etapa 2: La frecuencia se parece a <img src="https://latex.codecogs.com/png.latex?P"> cuando <img src="https://latex.codecogs.com/png.latex?n"> crece</h3>
<p>Se simulan <img src="https://latex.codecogs.com/png.latex?n=4000"> lanzamientos. La fracción de pares debe acercarse a <img src="https://latex.codecogs.com/png.latex?1/2">.</p>
<p><strong>Antes del gráfico:</strong> al principio la línea tiembla; al final debe pegarse a la horizontal <img src="https://latex.codecogs.com/png.latex?0.5">. Eso no es magia: es la ley de los grandes números, vista como conteo.</p>
<div id="c017" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:13.618273Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:13.618125Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:13.741081Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:13.740574Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4000</span></span>
<span id="cb6-2">lanzamientos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.integers(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb6-3">es_par <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (lanzamientos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)</span>
<span id="cb6-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Frecuencia relativa de par:"</span>, es_par.mean().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (teórica 0.5)"</span>)</span>
<span id="cb6-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Frecuencia de mayor que 4:"</span>, (lanzamientos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>).mean().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (teórica 0.333)"</span>)</span>
<span id="cb6-6">graficar_estabilizacion(es_par, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sacar par en un dado honesto"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(par)"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Frecuencia relativa de par: 0.4995   (teórica 0.5)
Frecuencia de mayor que 4: 0.3332   (teórica 0.333)</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/08-fundamentos-probabilidad/index_files/figure-html/cell-5-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Después.</strong> Con pocos lanzamientos el azar manda; con miles, la fracción se estabiliza. En un dataset, una clase que aparece 7 veces en 10 no “tiene probabilidad 0.7” de forma estable: <img src="https://latex.codecogs.com/png.latex?n"> es chico. La misma lección aplica a una métrica de clasificación calculada en una muestra corta.</p>
</section>
<section id="etapa-3-unión-e-intersección" class="level3">
<h3 class="anchored" data-anchor-id="etapa-3-unión-e-intersección">Etapa 3: Unión e intersección</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(P%5Ccup%20M)=P(P)+P(M)-P(P%5Ccap%20M)%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?P%5Ccap%20M=%5C%7B6%5C%7D">, así que <img src="https://latex.codecogs.com/png.latex?1/2+1/3-1/6=2/3">. Si se sumara <img src="https://latex.codecogs.com/png.latex?P(P)+P(M)"> sin restar la intersección, el 6 se contaría dos veces.</p>
<div id="c020" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:13.742844Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:13.742683Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:13.826963Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:13.826487Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8000</span></span>
<span id="cb8-2">x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.integers(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb8-3">f_union <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean((x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> (x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb8-4">f_inter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean((x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb8-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(P ∪ M) teórica ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  simulada ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(f_union, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb8-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(P ∩ M) teórica ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  simulada ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(f_inter, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb8-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(P)+P(M) sin restar intersección ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (se pasa)"</span>)</span>
<span id="cb8-8"></span>
<span id="cb8-9">graficar_barras_probs(</span>
<span id="cb8-10">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(par)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(&gt;4)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(ambos)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(par o &gt;4)"</span>],</span>
<span id="cb8-11">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>],</span>
<span id="cb8-12">    [np.mean(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), np.mean(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), f_inter, f_union],</span>
<span id="cb8-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Unión e intersección: la fórmula y el conteo coinciden"</span>,</span>
<span id="cb8-14">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>P(P ∪ M) teórica = 0.6667   simulada = 0.6701
P(P ∩ M) teórica = 0.1667   simulada = 0.1594
P(P)+P(M) sin restar intersección = 0.8333   (se pasa)</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/08-fundamentos-probabilidad/index_files/figure-html/cell-6-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> Restar <img src="https://latex.codecogs.com/png.latex?P(A%5Ccap%20B)"> no es un truco algebraico: evita contar dos veces a quien está en los dos conjuntos. En un dashboard, sumar “% de clientes con impago” más “% con alerta” sin restar el cruce <strong>infla</strong> el total.</p>
</section>
<section id="etapa-4-condicional-se-cambia-el-denominador" class="level3">
<h3 class="anchored" data-anchor-id="etapa-4-condicional-se-cambia-el-denominador">Etapa 4: Condicional — se cambia el denominador</h3>
<p>¿Cuál es la probabilidad de sacar un 6 <em>si ya sabemos que salió par</em>?</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(S%5Cmid%20P)=%5Cfrac%7BP(S%5Ccap%20P)%7D%7BP(P)%7D=%5Cfrac%7B1/6%7D%7B1/2%7D=%5Cfrac%7B1%7D%7B3%7D.%0A"></p>
<p>Entre <img src="https://latex.codecogs.com/png.latex?%5C%7B2,4,6%5C%7D"> solo una cara es el 6. El 6 no se volvió más frecuente en el dado; el <strong>universo se redujo</strong>.</p>
<div id="c023" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:13.828475Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:13.828319Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:13.832943Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:13.832552Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9000</span></span>
<span id="cb10-2">x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.integers(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb10-3">pares <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> x[x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb10-4">p_cond <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean(pares <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>)</span>
<span id="cb10-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Casos pares:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(pares), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  de ellos seis:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>((pares <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()))</span>
<span id="cb10-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(seis | par) simulada ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_cond, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  teórica ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb10-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(seis) sin recortar   ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.mean(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  teórica = 0.167"</span>)</span>
<span id="cb10-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb10-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(par | seis) teórica = 1  (si salió 6, es par)"</span>)</span>
<span id="cb10-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(par | seis) simulada ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.mean(x[x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Casos pares: 4444   de ellos seis: 1469
P(seis | par) simulada = 0.3306   teórica = 0.3333
P(seis) sin recortar   = 0.1632   teórica = 0.167

P(par | seis) teórica = 1  (si salió 6, es par)
P(par | seis) simulada = 1.0</code></pre>
</div>
</div>
<p><strong>El contraste.</strong> <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bseis%7D%5Cmid%20%5Ctext%7Bpar%7D)=1/3"> y <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bpar%7D%5Cmid%20%5Ctext%7Bseis%7D)=1">. Invertir la barra cambia el número. En un modelo: <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Benfermedad%7D%5Cmid%20%5Ctext%7Btest%7D+)"> <strong>no</strong> es <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Btest%7D+%5Cmid%20%5Ctext%7Benfermedad%7D)">.</p>
</section>
<section id="etapa-5-independencia-dos-monedas" class="level3">
<h3 class="anchored" data-anchor-id="etapa-5-independencia-dos-monedas">Etapa 5: Independencia — dos monedas</h3>
<p>Se lanzan dos monedas honestas. <img src="https://latex.codecogs.com/png.latex?%5COmega=%5C%7BCC,CS,SC,SS%5C%7D">, cada uno con probabilidad <img src="https://latex.codecogs.com/png.latex?1/4">.</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?A"> = “la primera es cara” <img src="https://latex.codecogs.com/png.latex?=%5C%7BCC,CS%5C%7D">, <img src="https://latex.codecogs.com/png.latex?P(A)=1/2">.</li>
<li><img src="https://latex.codecogs.com/png.latex?B"> = “la segunda es cara” <img src="https://latex.codecogs.com/png.latex?=%5C%7BCC,SC%5C%7D">, <img src="https://latex.codecogs.com/png.latex?P(B)=1/2">.</li>
<li><img src="https://latex.codecogs.com/png.latex?A%5Ccap%20B=%5C%7BCC%5C%7D">, <img src="https://latex.codecogs.com/png.latex?P(A%5Ccap%20B)=1/4=P(A)P(B)">. Son <strong>independientes</strong>.</li>
</ul>
<p>Ahora <img src="https://latex.codecogs.com/png.latex?C"> = “sale exactamente una cara” <img src="https://latex.codecogs.com/png.latex?=%5C%7BCS,SC%5C%7D">. La intuición dice que <img src="https://latex.codecogs.com/png.latex?A"> y <img src="https://latex.codecogs.com/png.latex?C"> dependen: si la primera fue cara, la segunda tiene que ser sello. Pero la cuenta dice otra cosa: <img src="https://latex.codecogs.com/png.latex?P(C)=1/2"> y <img src="https://latex.codecogs.com/png.latex?P(C%5Cmid%20A)=P(%5Ctext%7Bsegunda%20sello%7D)=1/2">. <strong>Son independientes.</strong></p>
<p>En cambio, <img src="https://latex.codecogs.com/png.latex?E"> = “salen dos caras” <img src="https://latex.codecogs.com/png.latex?=%5C%7BCC%5C%7D"> sí depende de <img src="https://latex.codecogs.com/png.latex?A">: <img src="https://latex.codecogs.com/png.latex?P(E)=1/4">, pero <img src="https://latex.codecogs.com/png.latex?P(E%5Cmid%20A)=1/2">.</p>
<div id="c026" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:13.834420Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:13.834267Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:13.840047Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:13.839613Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span></span>
<span id="cb12-2">m1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.integers(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 1 = cara</span></span>
<span id="cb12-3">m2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.integers(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb12-4">A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> m1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb12-5">B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> m2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb12-6">C <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (m1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> m2) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># exactamente una cara</span></span>
<span id="cb12-7">E <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (m1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> m2) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># dos caras</span></span>
<span id="cb12-8"></span>
<span id="cb12-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(A)P(B) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(A.mean() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> B.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  P(A ∩ B) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.mean(A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> B), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb12-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"¿A y B independientes (aprox.)?"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(np.mean(A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> B) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> A.mean() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> B.mean()) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span>)</span>
<span id="cb12-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb12-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C = exactamente una cara:  P(C) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(C.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  P(C | A) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.mean(C[A]), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb12-13">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  → independientes (parecía que no)"</span>)</span>
<span id="cb12-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"E = dos caras:             P(E) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(E.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  P(E | A) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.mean(E[A]), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb12-15">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  → no independientes"</span>)</span>
<span id="cb12-16"></span>
<span id="cb12-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Disjuntos: A y "ambas sellos"</span></span>
<span id="cb12-18">D <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (m1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (m2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb12-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb12-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"A y 'ambas sellos' son disjuntos: P(A ∩ D) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.mean(A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> D), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb12-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(D | A) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.mean(D[A]) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> A.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">any</span>() <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"≠ P(D) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(D.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb12-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Disjuntos con P&gt;0 ⇒ no independientes."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>P(A)P(B) = 0.2555   P(A ∩ B) = 0.2557
¿A y B independientes (aprox.)? True

C = exactamente una cara:  P(C) = 0.4995   P(C | A) = 0.4941   → independientes (parecía que no)
E = dos caras:             P(E) = 0.2557   P(E | A) = 0.5059   → no independientes

A y 'ambas sellos' son disjuntos: P(A ∩ D) = 0.0
P(D | A) = 0.0 ≠ P(D) = 0.2448
Disjuntos con P&gt;0 ⇒ no independientes.</code></pre>
</div>
</div>
<p><strong>La independencia se comprueba con números, no con intuición:</strong> <img src="https://latex.codecogs.com/png.latex?A"> y <img src="https://latex.codecogs.com/png.latex?C"> parecían ligados y no lo están; <img src="https://latex.codecogs.com/png.latex?A"> y <img src="https://latex.codecogs.com/png.latex?E"> sí lo están.</p>
<p><strong>Regla de bolsillo.</strong> Independiente = <em>saber uno no mueve al otro</em>. Disjunto = <em>no caben los dos</em>. Si caben los dos y ambos pueden ocurrir, no uses la intuición de “se excluyen” para multiplicar.</p>
</section>
<section id="etapa-6-probabilidad-total-dos-máquinas" class="level3">
<h3 class="anchored" data-anchor-id="etapa-6-probabilidad-total-dos-máquinas">Etapa 6: Probabilidad total — dos máquinas</h3>
<p>Una fábrica tiene dos líneas:</p>
<ul>
<li>Línea <img src="https://latex.codecogs.com/png.latex?H">: produce el <img src="https://latex.codecogs.com/png.latex?70%5C%25"> de las piezas; el <img src="https://latex.codecogs.com/png.latex?2%5C%25"> sale defectuosa.</li>
<li>Línea <img src="https://latex.codecogs.com/png.latex?H%5Ec">: produce el <img src="https://latex.codecogs.com/png.latex?30%5C%25">; el <img src="https://latex.codecogs.com/png.latex?8%5C%25"> sale defectuosa.</li>
</ul>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(D)=P(D%5Cmid%20H)P(H)+P(D%5Cmid%20H%5Ec)P(H%5Ec)=0.02%5Ccdot%200.70+0.08%5Ccdot%200.30=0.038.%0A"></p>
<p>El <img src="https://latex.codecogs.com/png.latex?3.8%5C%25"> de todas las piezas es defectuoso. No es ni <img src="https://latex.codecogs.com/png.latex?2%5C%25"> ni <img src="https://latex.codecogs.com/png.latex?8%5C%25">: es el <strong>promedio ponderado</strong> por cuánto produce cada línea.</p>
<div id="c029" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:13.841685Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:13.841503Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:13.926526Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:13.926037Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20000</span></span>
<span id="cb14-2">linea <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.70</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># True = H</span></span>
<span id="cb14-3">defectuosa <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(linea, rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span>, rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.08</span>)</span>
<span id="cb14-4">p_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> defectuosa.mean()</span>
<span id="cb14-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(D) simulada ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_d, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  teórica = 0.038"</span>)</span>
<span id="cb14-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(D | H)   ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(defectuosa[linea].mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (debe ~0.02)"</span>)</span>
<span id="cb14-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(D | H^c) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(defectuosa[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>linea].mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (debe ~0.08)"</span>)</span>
<span id="cb14-8"></span>
<span id="cb14-9">graficar_barras_probs(</span>
<span id="cb14-10">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(H)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(D|H)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(D|Hᶜ)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(D)"</span>],</span>
<span id="cb14-11">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.70</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.08</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.038</span>],</span>
<span id="cb14-12">    [linea.mean(), defectuosa[linea].mean(), defectuosa[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>linea].mean(), p_d],</span>
<span id="cb14-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Probabilidad total: el 3.8% mezcla las dos líneas"</span>,</span>
<span id="cb14-14">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>P(D) simulada = 0.0376   teórica = 0.038
P(D | H)   = 0.0194   (debe ~0.02)
P(D | H^c) = 0.0794   (debe ~0.08)</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/08-fundamentos-probabilidad/index_files/figure-html/cell-9-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> <img src="https://latex.codecogs.com/png.latex?P(D)"> es la <strong>evidencia</strong> que más tarde irá al denominador de Bayes. Si solo se reporta “esta línea tiene 2% de defectos”, se oculta que un tercio de la producción es la línea mala.</p>
</section>
<section id="etapa-7-bayes-de-qué-línea-salió-la-pieza-defectuosa" class="level3">
<h3 class="anchored" data-anchor-id="etapa-7-bayes-de-qué-línea-salió-la-pieza-defectuosa">Etapa 7: Bayes — ¿de qué línea salió la pieza defectuosa?</h3>
<p>Ya vimos una defectuosa. ¿Cuál es <img src="https://latex.codecogs.com/png.latex?P(H%5Cmid%20D)">?</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(H%5Cmid%20D)=%5Cfrac%7BP(D%5Cmid%20H)P(H)%7D%7BP(D)%7D=%5Cfrac%7B0.02%5Ccdot%200.70%7D%7B0.038%7D%5Capprox%200.368.%0A"></p>
<p>Aunque la línea <img src="https://latex.codecogs.com/png.latex?H"> produce el <img src="https://latex.codecogs.com/png.latex?70%5C%25"> de las piezas, <strong>solo el <img src="https://latex.codecogs.com/png.latex?37%5C%25"></strong> de los defectos vienen de ella. La línea chica es más sucia y se lleva la mayoría de las alertas.</p>
<div id="c032" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:13.928466Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:13.928291Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:14.012668Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:14.012027Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">p_h_dado_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.70</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.038</span></span>
<span id="cb16-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(H | D) teórica ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_h_dado_d, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb16-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(H | D) simulada ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(linea[defectuosa].mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb16-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(H^c | D) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p_h_dado_d, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb16-5"></span>
<span id="cb16-6">graficar_prior_vs_posterior(</span>
<span id="cb16-7">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"línea H (70</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">% d</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">e la prod.)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"línea Hᶜ (30%)"</span>],</span>
<span id="cb16-8">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.70</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span>],</span>
<span id="cb16-9">    [p_h_dado_d, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p_h_dado_d],</span>
<span id="cb16-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Una pieza defectuosa actualiza: la línea grande ya no es la más creíble"</span>,</span>
<span id="cb16-11">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>P(H | D) teórica = 0.3684
P(H | D) simulada = 0.359
P(H^c | D) = 0.6316</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/08-fundamentos-probabilidad/index_files/figure-html/cell-10-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Idea de esta etapa.</strong> El prior <img src="https://latex.codecogs.com/png.latex?0.70"> se <strong>actualiza</strong> con la verosimilitud <img src="https://latex.codecogs.com/png.latex?0.02"> frente a <img src="https://latex.codecogs.com/png.latex?0.08">. Bayes no “adivina”: repondera. Un clasificador hace lo mismo cuando combina <img src="https://latex.codecogs.com/png.latex?P(y)"> con <img src="https://latex.codecogs.com/png.latex?P(x%5Cmid%20y)">.</p>
</section>
<section id="etapa-8-el-contraste-que-importa-prueba-diagnóstica" class="level3">
<h3 class="anchored" data-anchor-id="etapa-8-el-contraste-que-importa-prueba-diagnóstica">Etapa 8: El contraste que importa — prueba diagnóstica</h3>
<p>Se examinan <img src="https://latex.codecogs.com/png.latex?10%5C,000"> personas.</p>
<ul>
<li>Enfermedad rara: <img src="https://latex.codecogs.com/png.latex?P(E)=0.01"> (1 de cada 100).</li>
<li>Sensibilidad: <img src="https://latex.codecogs.com/png.latex?P(+%5Cmid%20E)=0.99"> (casi no se escapa un enfermo).</li>
<li>Falsos positivos: <img src="https://latex.codecogs.com/png.latex?P(+%5Cmid%20E%5Ec)=0.05"> (5 de cada 100 sanos dan +).</li>
</ul>
<p>La pregunta <strong>incorrecta</strong> que suele hacerse: “la prueba acierta el 99%, ¿entonces un + es casi seguro enfermo?”.</p>
<p>La pregunta <strong>correcta</strong>: <img src="https://latex.codecogs.com/png.latex?P(E%5Cmid%20+)">.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(+)=0.99%5Ccdot%200.01+0.05%5Ccdot(1-0.01)=0.0594,%0A%5Cqquad%0AP(E%5Cmid%20+)=%5Cfrac%7B0.99%5Ccdot%200.01%7D%7B0.0594%7D%5Capprox%200.167.%0A"></p>
<p>Un positivo es enfermo <strong>solo 1 de cada 6 veces</strong>. El 99% mide <img src="https://latex.codecogs.com/png.latex?P(+%5Cmid%20E)">, no <img src="https://latex.codecogs.com/png.latex?P(E%5Cmid%20+)">.</p>
<div id="c035" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:14.014350Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:14.014192Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:14.255114Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:14.254689Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span></span>
<span id="cb18-2">enfermo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span></span>
<span id="cb18-3">positivo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(enfermo, rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.99</span>, rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>)</span>
<span id="cb18-4"></span>
<span id="cb18-5">n_e_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>((enfermo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> positivo).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())</span>
<span id="cb18-6">n_s_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>((<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>enfermo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> positivo).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())</span>
<span id="cb18-7">n_e_neg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>((enfermo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>positivo).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())</span>
<span id="cb18-8">n_s_neg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>((<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>enfermo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>positivo).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())</span>
<span id="cb18-9"></span>
<span id="cb18-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Tabla de conteos:"</span>)</span>
<span id="cb18-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame(</span>
<span id="cb18-12">    [[n_e_pos, n_e_neg], [n_s_pos, n_s_neg]],</span>
<span id="cb18-13">    index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"enfermo"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sano"</span>],</span>
<span id="cb18-14">    columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prueba +"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prueba −"</span>],</span>
<span id="cb18-15">))</span>
<span id="cb18-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb18-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(E | +) simulada ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(n_e_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (n_e_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> n_s_pos), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  teórica ≈ 0.167"</span>)</span>
<span id="cb18-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La diferencia es variación de muestreo (n=10000, pocos enfermos); no un error de la fórmula."</span>)</span>
<span id="cb18-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(+ | E) simulada ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(n_e_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> enfermo.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (sensibilidad, ~0.99)"</span>)</span>
<span id="cb18-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Entre los +, sanos / total + ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(n_s_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (n_e_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> n_s_pos), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb18-21"></span>
<span id="cb18-22">graficar_conteos_prueba(</span>
<span id="cb18-23">    n_e_pos, n_s_pos, n_e_neg, n_s_neg,</span>
<span id="cb18-24">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Casi todos los + son sanos: la enfermedad es rara y hay muchos sanos"</span>,</span>
<span id="cb18-25">)</span>
<span id="cb18-26">graficar_prior_vs_posterior(</span>
<span id="cb18-27">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"enfermo"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sano"</span>],</span>
<span id="cb18-28">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.99</span>],</span>
<span id="cb18-29">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.99</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0594</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.99</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0594</span>],</span>
<span id="cb18-30">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Prior 1% → posterior ≈ 17</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">% s</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">i la prueba da +"</span>,</span>
<span id="cb18-31">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Tabla de conteos:
         prueba +  prueba −
enfermo       113         0
sano          454      9433

P(E | +) simulada = 0.1993   teórica ≈ 0.167
La diferencia es variación de muestreo (n=10000, pocos enfermos); no un error de la fórmula.
P(+ | E) simulada = 1.0   (sensibilidad, ~0.99)
Entre los +, sanos / total + = 0.8007</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/08-fundamentos-probabilidad/index_files/figure-html/cell-11-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/08-fundamentos-probabilidad/index_files/figure-html/cell-11-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>La simulación no tiene que dar 0.167 exacto.</strong> Con unos 100 enfermos en 10 000 filas, el posterior empírico tiembla (aquí puede salir ~0.20). La fórmula 16.7% es el valor de diseño.</p>
<p><strong>Por qué el número es bajo.</strong> Hay 9900 sanos. El 5% de ellos son 495 falsos +. Hay ~100 enfermos y ~99 verdaderos +. En la canasta de positivos, 495 contra 99. La prueba es buena; la <strong>frecuencia base</strong> es pequeña. Un modelo de fraude o de enfermedad rara vive en este régimen.</p>
<p>En clasificación esto se llama <strong>desbalance</strong>. Accuracy “99% de sanos bien clasificados” puede convivir con un posterior miserable.</p>
</section>
<section id="etapa-9-clasificación-binaria-alerta-de-fraude" class="level3">
<h3 class="anchored" data-anchor-id="etapa-9-clasificación-binaria-alerta-de-fraude">Etapa 9: Clasificación binaria — alerta de fraude</h3>
<p>Cada transacción es <img src="https://latex.codecogs.com/png.latex?y=1"> (fraude) o <img src="https://latex.codecogs.com/png.latex?y=0">. Una regla simple dispara <strong>alerta</strong> si el monto es alto <em>y</em> el país no es el habitual. Números diseñados, no de un banco real:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?P(y=1)=0.02">,</li>
<li><img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Balerta%7D%5Cmid%20y=1)=0.80">,</li>
<li><img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Balerta%7D%5Cmid%20y=0)=0.10">.</li>
</ul>
<p>El sistema no entrega “es fraude”: entrega <img src="https://latex.codecogs.com/png.latex?P(y=1%5Cmid%20%5Ctext%7Balerta%7D)">.</p>
<div id="c038" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:14.256699Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:14.256528Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:14.335588Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:14.335214Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">p_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span></span>
<span id="cb20-2">p_a_y1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.80</span></span>
<span id="cb20-3">p_a_y0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.10</span></span>
<span id="cb20-4">p_a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> p_a_y1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> p_a_y0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p_y)</span>
<span id="cb20-5">p_y_a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (p_a_y1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p_y) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> p_a</span>
<span id="cb20-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(alerta) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_a, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb20-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(fraude | alerta) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_y_a, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb20-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(legítima | alerta) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p_y_a, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb20-9"></span>
<span id="cb20-10">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50000</span></span>
<span id="cb20-11">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> p_y</span>
<span id="cb20-12">alerta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(y, rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> p_a_y1, rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> p_a_y0)</span>
<span id="cb20-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb20-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Simulación P(fraude | alerta) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y[alerta].mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb20-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Precision de la alerta (mismo número):"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y[alerta].mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb20-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Recall (fracción de fraudes alertados):"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(alerta[y].mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb20-17"></span>
<span id="cb20-18">graficar_prior_vs_posterior(</span>
<span id="cb20-19">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fraude"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"legítima"</span>],</span>
<span id="cb20-20">    [p_y, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p_y],</span>
<span id="cb20-21">    [p_y_a, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p_y_a],</span>
<span id="cb20-22">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Alerta ≠ certeza: el posterior sube, pero no llega a 0.5"</span>,</span>
<span id="cb20-23">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>P(alerta) = 0.114
P(fraude | alerta) = 0.1404
P(legítima | alerta) = 0.8596

Simulación P(fraude | alerta) = 0.1431
Precision de la alerta (mismo número): 0.1431
Recall (fracción de fraudes alertados): 0.7892</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/08-fundamentos-probabilidad/index_files/figure-html/cell-12-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Traducción a métricas.</strong> <img src="https://latex.codecogs.com/png.latex?P(y=1%5Cmid%20%5Ctext%7Balerta%7D)"> es la <strong>precisión</strong> de la alerta. <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Balerta%7D%5Cmid%20y=1)"> es el <strong>recall</strong>. Una alerta con recall 80% y precisión ~14% es un filtro útil para revisar a mano, no un veredicto automático.</p>
<p>Un umbral de decisión (“si posterior <img src="https://latex.codecogs.com/png.latex?%3E0.5">, bloquear”) aquí <strong>no bloquearía</strong>: <img src="https://latex.codecogs.com/png.latex?0.14%3C0.5">. El umbral se elige con costos (¿cuánto cuesta molestar a un cliente honesto frente a dejar pasar un fraude?), no con el 50% por costumbre.</p>
</section>
<section id="etapa-10-naive-bayes-de-una-palabra-el-mismo-teorema" class="level3">
<h3 class="anchored" data-anchor-id="etapa-10-naive-bayes-de-una-palabra-el-mismo-teorema">Etapa 10: Naive Bayes de una palabra — el mismo teorema</h3>
<p>Un filtro de correo. Solo dos clases y <strong>una</strong> evidencia: si el asunto contiene la palabra “premio”.</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bspam%7D)=0.30">,</li>
<li><img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7B%E2%80%9Cpremio%E2%80%9D%7D%5Cmid%20%5Ctext%7Bspam%7D)=0.40">,</li>
<li><img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7B%E2%80%9Cpremio%E2%80%9D%7D%5Cmid%20%5Ctext%7Bham%7D)=0.02">.</li>
</ul>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(%5Ctext%7Bspam%7D%5Cmid%20%5Ctext%7B%E2%80%9Cpremio%E2%80%9D%7D)%0A=%5Cfrac%7B0.40%5Ccdot%200.30%7D%7B0.40%5Ccdot%200.30+0.02%5Ccdot%200.70%7D%5Capprox%200.895.%0A"></p>
<p>Con una sola palabra bien dispar, el posterior <strong>sí</strong> cruza 0.5. Naive Bayes con muchas palabras multiplica verosimilitudes (asumiendo independencia dada la clase). Esa independencia es una hipótesis: “gratis” y “premio” no son independientes <strong>dentro de cada clase</strong> en la vida real, y aun así el clasificador suele funcionar como baseline.</p>
<div id="c041" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:14.337238Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:14.337061Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:14.412767Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:14.412300Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1">p_spam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span></span>
<span id="cb22-2">p_w_spam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.40</span></span>
<span id="cb22-3">p_w_ham <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span></span>
<span id="cb22-4">p_w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> p_w_spam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p_spam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> p_w_ham <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p_spam)</span>
<span id="cb22-5">p_spam_w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (p_w_spam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p_spam) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> p_w</span>
<span id="cb22-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(palabra) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_w, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb22-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(spam | palabra) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_spam_w, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb22-8"></span>
<span id="cb22-9">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20000</span></span>
<span id="cb22-10">es_spam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> p_spam</span>
<span id="cb22-11">tiene_w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(es_spam, rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> p_w_spam, rng.random(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> p_w_ham)</span>
<span id="cb22-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Simulación:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(es_spam[tiene_w].mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb22-13"></span>
<span id="cb22-14">graficar_prior_vs_posterior(</span>
<span id="cb22-15">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"spam"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ham"</span>],</span>
<span id="cb22-16">    [p_spam, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p_spam],</span>
<span id="cb22-17">    [p_spam_w, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p_spam_w],</span>
<span id="cb22-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Una palabra informativa sí mueve el prior 0.30 → ≈ 0.90"</span>,</span>
<span id="cb22-19">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>P(palabra) = 0.134
P(spam | palabra) = 0.8955
Simulación: 0.9014</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/08-fundamentos-probabilidad/index_files/figure-html/cell-13-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Comparar las etapas 8, 9 y 10.</strong> El teorema es el mismo. Cambia la <strong>frecuencia base</strong> y cuánto separa la evidencia. En la prueba médica el prior es 1% y hay muchos falsos +; en el correo el prior es 30% y la palabra es rara en ham. El número que se reporta siempre es <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bclase%7D%5Cmid%20%5Ctext%7Bdato%7D)">, no al revés.</p>
</section>
<section id="caso-aplicado-reportar-un-posterior" class="level3">
<h3 class="anchored" data-anchor-id="caso-aplicado-reportar-un-posterior">Caso aplicado: reportar un posterior</h3>
<p>Plantilla mínima (el análogo del reporte de PCA, para probabilidad):</p>
<ol type="1">
<li><strong>Experimento y <img src="https://latex.codecogs.com/png.latex?%5COmega">:</strong> qué se observa, qué clases hay.</li>
<li><strong>Prior:</strong> <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bclase%7D)"> y de dónde sale (histórico, diseño).</li>
<li><strong>Verosimilitud:</strong> <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bevidencia%7D%5Cmid%20%5Ctext%7Bclase%7D)"> — sensibilidad, tasa de alerta, etc.</li>
<li><strong>Evidencia:</strong> <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bdato%7D)"> por probabilidad total.</li>
<li><strong>Posterior y decisión:</strong> <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bclase%7D%5Cmid%20%5Ctext%7Bdato%7D)"> y qué se hace con el umbral.</li>
</ol>
<p>Se aplica a la prueba diagnóstica de la etapa 8.</p>
<p><strong>Los cinco pasos, aplicados</strong></p>
<ol type="1">
<li><strong>Experimento.</strong> Persona de una población; <img src="https://latex.codecogs.com/png.latex?%5COmega"> se parte en enfermo / sano. Evidencia: prueba <img src="https://latex.codecogs.com/png.latex?+"> o <img src="https://latex.codecogs.com/png.latex?-">.</li>
<li><strong>Prior.</strong> <img src="https://latex.codecogs.com/png.latex?P(E)=0.01"> (1% de prevalencia, dato de diseño).</li>
<li><strong>Verosimilitud.</strong> <img src="https://latex.codecogs.com/png.latex?P(+%5Cmid%20E)=0.99">, <img src="https://latex.codecogs.com/png.latex?P(+%5Cmid%20E%5Ec)=0.05">.</li>
<li><strong>Evidencia.</strong> <img src="https://latex.codecogs.com/png.latex?P(+)=0.0594"> (casi 6 de cada 100 dan +).</li>
<li><strong>Posterior.</strong> <img src="https://latex.codecogs.com/png.latex?P(E%5Cmid%20+)%5Capprox%200.167">.</li>
</ol>
<blockquote class="blockquote">
<p>En una población con 1% de prevalencia, una prueba con sensibilidad 99% y 5% de falsos positivos produce <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Benfermedad%7D%5Cmid%20+)%5Capprox%2016.7%5C%25">. Se informa ese posterior, no la sensibilidad. Decisión: un + no autoriza tratamiento por sí solo; autoriza una segunda prueba. Limitación: el 1% y el 5% son supuestos; si la prevalencia sube (un brote), el mismo test se vuelve más informativo.</p>
</blockquote>
</section>
<section id="errores-que-conviene-nombrar" class="level3">
<h3 class="anchored" data-anchor-id="errores-que-conviene-nombrar">Errores que conviene nombrar</h3>
<ol type="1">
<li><strong>Invertir el condicional.</strong> Reportar <img src="https://latex.codecogs.com/png.latex?P(+%5Cmid%20E)"> cuando la decisión pide <img src="https://latex.codecogs.com/png.latex?P(E%5Cmid%20+)">.</li>
<li><strong>Ignorar la frecuencia base.</strong> Un test excelente en una clase rara genera más falsos + que verdaderos +.</li>
<li><strong>Confundir disjuntos con independientes.</strong> “No pueden ser las dos” no autoriza a multiplicar <img src="https://latex.codecogs.com/png.latex?P(A)P(B)">.</li>
<li><strong>Tratar una frecuencia de <img src="https://latex.codecogs.com/png.latex?n=20"> como <img src="https://latex.codecogs.com/png.latex?P"> estable.</strong> La etapa 2 muestra el temblor.</li>
<li><strong>Umbral 0.5 por costumbre.</strong> El umbral es un costo, no un teorema.</li>
<li><strong>Decidir la independencia por intuición.</strong> “Primera cara” y “exactamente una cara” parecen ligados y son independientes; se comprueba con <img src="https://latex.codecogs.com/png.latex?P(A%5Ccap%20B)=P(A)P(B)">.</li>
</ol>
</section>
<section id="idea-clave" class="level3">
<h3 class="anchored" data-anchor-id="idea-clave">Idea clave</h3>
<p><strong>La barra del condicional elige el denominador.</strong> Bayes no crea información: cambia la pregunta de “si es de esta clase, ¿cómo se ve el dato?” a “visto el dato, ¿de qué clase es?”. En IA esa inversión es el clasificador.</p>
</section>
<section id="síntesis" class="level3">
<h3 class="anchored" data-anchor-id="síntesis">Síntesis</h3>
<p>Se definió <img src="https://latex.codecogs.com/png.latex?%5COmega">, se contaron eventos, se vio la frecuencia estabilizarse, se recortó el espacio (condicional), se separó independencia de exclusión, se mezclaron grupos (probabilidad total) y se invirtió el condicional (Bayes) en una fábrica, una prueba médica, un fraude y un correo. El objeto que queda para las sesiones de inferencia y de modelos es <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bhip%C3%B3tesis%7D%5Cmid%20%5Ctext%7Bdatos%7D)">.</p>
</section>
</section>
<section id="guía-rápida-qué-fórmula-usar" class="level2">
<h2 class="anchored" data-anchor-id="guía-rápida-qué-fórmula-usar">6. Guía rápida: ¿qué fórmula usar?</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Situación</th>
<th>Qué usar</th>
<th>Por qué</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Listar resultados posibles</td>
<td><img src="https://latex.codecogs.com/png.latex?%5COmega"></td>
<td>Fija el denominador</td>
</tr>
<tr class="even">
<td>“No ocurrió A”</td>
<td><img src="https://latex.codecogs.com/png.latex?1-P(A)"></td>
<td>Complemento</td>
</tr>
<tr class="odd">
<td>A o B, pueden solaparse</td>
<td><img src="https://latex.codecogs.com/png.latex?P(A)+P(B)-P(A%5Ccap%20B)"></td>
<td>No contar dos veces</td>
</tr>
<tr class="even">
<td>Ya sé que ocurrió B</td>
<td><img src="https://latex.codecogs.com/png.latex?P(A%5Cmid%20B)=P(A%5Ccap%20B)/P(B)"></td>
<td>Recorta <img src="https://latex.codecogs.com/png.latex?%5COmega"> a <img src="https://latex.codecogs.com/png.latex?B"></td>
</tr>
<tr class="odd">
<td>Saber B no cambia A</td>
<td><img src="https://latex.codecogs.com/png.latex?P(A%5Ccap%20B)=P(A)P(B)"></td>
<td>Independencia</td>
</tr>
<tr class="even">
<td>El dato puede salir de varios grupos</td>
<td>Probabilidad total</td>
<td>Promedio ponderado por el tamaño de cada grupo</td>
</tr>
<tr class="odd">
<td>Tengo <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bdato%7D%5Cmid%20%5Ctext%7Bclase%7D)"> y quiero la clase</td>
<td>Bayes</td>
<td>Invierte el condicional</td>
</tr>
<tr class="even">
<td>Clase rara + test imperfecto</td>
<td>Bayes con prior chico</td>
<td>El posterior suele ser mucho menor que la sensibilidad</td>
</tr>
</tbody>
</table>
<p><strong>Regla de comunicación:</strong> escribir el evento <em>y</em> qué está a la derecha de la barra.</p>
</section>
<section id="guía-práctica-para-reportar-una-probabilidad" class="level2">
<h2 class="anchored" data-anchor-id="guía-práctica-para-reportar-una-probabilidad">7. Guía práctica para reportar una probabilidad</h2>
<section id="paso-1-experimento-y-espacio" class="level3">
<h3 class="anchored" data-anchor-id="paso-1-experimento-y-espacio">Paso 1: experimento y espacio</h3>
<p>Qué se observa, cuáles son las clases o resultados.</p>
</section>
<section id="paso-2-prior" class="level3">
<h3 class="anchored" data-anchor-id="paso-2-prior">Paso 2: prior</h3>
<p><img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bclase%7D)"> y la fuente (histórico, diseño, supuesto).</p>
</section>
<section id="paso-3-verosimilitud" class="level3">
<h3 class="anchored" data-anchor-id="paso-3-verosimilitud">Paso 3: verosimilitud</h3>
<p><img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bevidencia%7D%5Cmid%20%5Ctext%7Bclase%7D)"> para cada clase.</p>
</section>
<section id="paso-4-evidencia-y-posterior" class="level3">
<h3 class="anchored" data-anchor-id="paso-4-evidencia-y-posterior">Paso 4: evidencia y posterior</h3>
<p><img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bdato%7D)"> y <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bclase%7D%5Cmid%20%5Ctext%7Bdato%7D)">.</p>
</section>
<section id="paso-5-redactar" class="level3">
<h3 class="anchored" data-anchor-id="paso-5-redactar">Paso 5: redactar</h3>
<blockquote class="blockquote">
<p>“En <code>[experimento]</code>, con prior <code>[P]</code>, evidencia <code>[...]</code> y verosimilitud <code>[...]</code>, el posterior es <code>[P(clase|dato)]</code>. Se decide <code>[acción]</code> porque <code>[umbral / costo]</code>. Limitación: <code>[frecuencia base / independencia / n pequeño]</code>.”</p>
</blockquote>
<p>El caso de la prueba diagnóstica (etapa 8) ya llenó esta plantilla.</p>
</section>
</section>
<section id="puente-hacia-las-siguientes-sesiones" class="level2">
<h2 class="anchored" data-anchor-id="puente-hacia-las-siguientes-sesiones">8. Puente hacia las siguientes sesiones</h2>
<p>La probabilidad ya no es un porcentaje suelto: es <img src="https://latex.codecogs.com/png.latex?P(%5Ccdot%5Cmid%20%5Ccdot)"> sobre un <img src="https://latex.codecogs.com/png.latex?%5COmega"> declarado. La inferencia (<strong>Sesión 9</strong>) usa la misma barra para hablar de un <strong>parámetro</strong> desconocido a partir de una muestra, y la <strong>Sesión 10</strong> aplica Bayes al propio parámetro. La clasificación y la validación volverán a <img src="https://latex.codecogs.com/png.latex?P(y%5Cmid%20x)"> y a umbrales con costo.</p>
</section>
<section id="cierre" class="level2">
<h2 class="anchored" data-anchor-id="cierre">9. Cierre</h2>
<p>Este notebook deja el lenguaje mínimo de la incertidumbre:</p>
<ul>
<li>experimento, <img src="https://latex.codecogs.com/png.latex?%5COmega"> y eventos,</li>
<li>probabilidad como frecuencia estable y como axioma,</li>
<li>condicional, independencia y la diferencia con “disjuntos”,</li>
<li>probabilidad total y teorema de Bayes,</li>
<li>tres clasificadores binarios (diagnóstico, fraude, spam) con el mismo teorema,</li>
<li>un reporte que escribe prior, verosimilitud y posterior.</li>
</ul>
<p><strong>Resultado esperado:</strong> el estudiante puede escribir <img src="https://latex.codecogs.com/png.latex?P(A%5Cmid%20B)">, no invertirlo por accidente, simular el conteo y explicar por qué un test del 99% puede dejar un posterior del 17%.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>probabilidad</category>
  <category>bayes</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/basico/08-fundamentos-probabilidad/</guid>
  <pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Estadística para IA — 9. Inferencia estadística</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/basico/09-inferencia-estadistica/</link>
  <description><![CDATA[ 




<section id="sesión-9-inferencia-estadística" class="level1">
<h1>Sesión 9 — Inferencia Estadística</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado es Científico de Datos, Arquitecto de IA, Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), consultor y docente universitario, trabaja en la intersección entre Data Science, Inteligencia Artificial, Big Data e IoT, transformando problemas reales en soluciones aplicadas.</p>
<p>De la teoría a la práctica, un problema a la vez.</p>
</section>
<section id="de-la-muestra-a-la-población-con-margen" class="level2">
<h2 class="anchored" data-anchor-id="de-la-muestra-a-la-población-con-margen">De la muestra a la población, con margen</h2>
<p>Una media de 47 filas no es la media de todos los usuarios. Es un <strong>estadístico</strong>: un número calculado en la muestra. El <strong>parámetro</strong> —el número de la población— no se ve. La inferencia es el aparato que permite hablar del parámetro <strong>y declarar la incertidumbre</strong>.</p>
<p>Este notebook construye ese aparato: <strong>estimación puntual</strong>, <strong>error estándar</strong>, <strong>intervalo de confianza</strong>, <strong>prueba de hipótesis</strong>, <strong>nivel de significancia</strong>, <strong>p-value</strong> y los <strong>errores tipo I y tipo II</strong>. La práctica es simular: se fabrica una población, se extraen muestras y se ve qué cubre el intervalo y qué rechaza la prueba. El contraste que importa es operativo y frecuente en producto: <em>un efecto minúsculo con <img src="https://latex.codecogs.com/png.latex?n"> enorme sale “significativo”; un efecto útil con <img src="https://latex.codecogs.com/png.latex?n"> chico, no</em>.</p>
<p>Contexto: latencia de un servicio de inferencia (milisegundos) y un <strong>A/B</strong> entre dos versiones del modelo. Los datos son sintéticos y diseñados.</p>
<p>Electiva I — Estadística Aplicada a la Inteligencia Artificial · Módulo 3 · Sesión 9</p>
</section>
<section id="objetivos" class="level2">
<h2 class="anchored" data-anchor-id="objetivos">Objetivos</h2>
<ul>
<li>Distinguir <strong>parámetro</strong>, <strong>estadístico</strong> y <strong>distribución muestral</strong>.</li>
<li>Calcular una <strong>estimación puntual</strong> y su <strong>error estándar</strong>.</li>
<li>Construir e interpretar un <strong>intervalo de confianza</strong> para la media (y ver qué significa “95%”).</li>
<li>Plantear <img src="https://latex.codecogs.com/png.latex?H_0"> y <img src="https://latex.codecogs.com/png.latex?H_1">, fijar <img src="https://latex.codecogs.com/png.latex?%5Calpha"> y calcular el <strong>p-value</strong> con SciPy.</li>
<li>Estimar por simulación las tasas de <strong>error tipo I</strong> y <strong>tipo II</strong>, y la <strong>potencia</strong>.</li>
<li>No confundir <strong>significancia estadística</strong> con <strong>relevancia práctica</strong>.</li>
<li>Redactar un reporte de inferencia (estimación, intervalo, prueba, decisión, limitación).</li>
</ul>
<blockquote class="blockquote">
<p>Nota: se recomienda ejecutar las celdas en orden. Las fórmulas usan LaTeX; si no se ven renderizadas, abre el notebook en Jupyter o Colab.</p>
</blockquote>
</section>
<section id="el-lenguaje-de-la-inferencia" class="level2">
<h2 class="anchored" data-anchor-id="el-lenguaje-de-la-inferencia">1. El lenguaje de la inferencia</h2>
<section id="parámetro-y-estadístico" class="level3">
<h3 class="anchored" data-anchor-id="parámetro-y-estadístico">1.1 Parámetro y estadístico</h3>
<p>El <strong>parámetro</strong> <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> describe la población (media <img src="https://latex.codecogs.com/png.latex?%5Cmu">, proporción <img src="https://latex.codecogs.com/png.latex?p">, diferencia de medias). No se observa: se <strong>estima</strong>.</p>
<p>El <strong>estadístico</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta"> se calcula en la muestra: <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x">, <img src="https://latex.codecogs.com/png.latex?%5Chat%20p">, <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x_B-%5Cbar%20x_A">. Cambia si cambia la muestra. Por eso <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta"> es una variable aleatoria.</p>
</section>
<section id="distribución-muestral" class="level3">
<h3 class="anchored" data-anchor-id="distribución-muestral">1.2 Distribución muestral</h3>
<p>La <strong>distribución muestral</strong> de <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta"> es la distribución de ese estadístico si el muestreo se repitiera. Su centro suele estar cerca de <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> (si el estimador es <strong>insesgado</strong>). Su dispersión baja cuando <img src="https://latex.codecogs.com/png.latex?n"> crece.</p>
<p>Esa dispersión se resume con el <strong>error estándar</strong> (SE): la desviación estándar de <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta">, no la de una observación. Para la media, si las observaciones son independientes y <img src="https://latex.codecogs.com/png.latex?s"> estima <img src="https://latex.codecogs.com/png.latex?%5Csigma">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7BSE%7D(%5Cbar%20x)=%5Cfrac%7Bs%7D%7B%5Csqrt%20n%7D.%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?s"> mide cómo varían las filas. El SE mide cómo varía <strong>la media</strong> de una muestra a otra.</p>
</section>
<section id="estimación-puntual" class="level3">
<h3 class="anchored" data-anchor-id="estimación-puntual">1.3 Estimación puntual</h3>
<p>Un número: <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta=%5Cbar%20x">. Es el mejor resumen puntual, y es incompleto. Sin SE no se sabe si <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x=201"> con <img src="https://latex.codecogs.com/png.latex?n=8"> o con <img src="https://latex.codecogs.com/png.latex?n=8000"> son el mismo tipo de afirmación.</p>
</section>
<section id="intervalo-de-confianza" class="level3">
<h3 class="anchored" data-anchor-id="intervalo-de-confianza">1.4 Intervalo de confianza</h3>
<p>Un <strong>intervalo de confianza</strong> de nivel <img src="https://latex.codecogs.com/png.latex?1-%5Calpha"> es un rango aleatorio que, en repeticiones del muestreo, cubre el parámetro en una fracción <img src="https://latex.codecogs.com/png.latex?1-%5Calpha"> de las veces. Para la media, con <img src="https://latex.codecogs.com/png.latex?%5Csigma"> desconocida y muestra aproximadamente normal (o <img src="https://latex.codecogs.com/png.latex?n"> no demasiado chico),</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbar%20x%20%5C;%5Cpm%5C;%20t_%7Bn-1,%5C,1-%5Calpha/2%7D%5C,%5Cfrac%7Bs%7D%7B%5Csqrt%20n%7D.%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?t_%7Bn-1,1-%5Calpha/2%7D"> es el cuantil de la <strong>t de Student</strong> con <img src="https://latex.codecogs.com/png.latex?n-1"> grados de libertad. Si <img src="https://latex.codecogs.com/png.latex?%5Csigma"> se conociera, se usaría <img src="https://latex.codecogs.com/png.latex?z_%7B1-%5Calpha/2%7D"> de la normal estándar (1.96 cuando <img src="https://latex.codecogs.com/png.latex?%5Calpha=0.05">). En la práctica <img src="https://latex.codecogs.com/png.latex?%5Csigma"> no se conoce: se usa <img src="https://latex.codecogs.com/png.latex?t">.</p>
<p><strong>Lectura correcta (frecuentista):</strong> el procedimiento cubre <img src="https://latex.codecogs.com/png.latex?%5Cmu"> el 95% de las veces. <strong>Este</strong> intervalo ya calculado o cubre a <img src="https://latex.codecogs.com/png.latex?%5Cmu"> o no; <img src="https://latex.codecogs.com/png.latex?%5Cmu"> no es aleatorio. Decir “hay 95% de probabilidad de que <img src="https://latex.codecogs.com/png.latex?%5Cmu"> esté aquí” mezcla el procedimiento con el número ya observado.</p>
</section>
<section id="prueba-de-hipótesis" class="level3">
<h3 class="anchored" data-anchor-id="prueba-de-hipótesis">1.5 Prueba de hipótesis</h3>
<p>Se contrastan dos afirmaciones sobre el parámetro:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?H_0">: afirmación de <strong>ningún efecto</strong> o valor de referencia (por ejemplo <img src="https://latex.codecogs.com/png.latex?%5Cmu=200">, o <img src="https://latex.codecogs.com/png.latex?%5Cmu_B=%5Cmu_A">).</li>
<li><img src="https://latex.codecogs.com/png.latex?H_1">: la alternativa (bilateral <img src="https://latex.codecogs.com/png.latex?%5Cmu%5Cneq%20200">, o unilateral <img src="https://latex.codecogs.com/png.latex?%5Cmu%3C200">).</li>
</ul>
<p>El <strong>estadístico de prueba</strong> mide cuánto se aleja la muestra de <img src="https://latex.codecogs.com/png.latex?H_0"> en unidades de error estándar. Para la media,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0At=%5Cfrac%7B%5Cbar%20x-%5Cmu_0%7D%7Bs/%5Csqrt%20n%7D.%0A"></p>
</section>
<section id="nivel-de-significancia-y-p-value" class="level3">
<h3 class="anchored" data-anchor-id="nivel-de-significancia-y-p-value">1.6 Nivel de significancia y p-value</h3>
<p>El <strong>nivel de significancia</strong> <img src="https://latex.codecogs.com/png.latex?%5Calpha"> es la probabilidad, <em>si <img src="https://latex.codecogs.com/png.latex?H_0"> es cierta</em>, de rechazarla por azar. Es una <strong>tasa de error que se elige</strong> (0.05 es costumbre, no teorema).</p>
<p>El <strong>p-value</strong> es la probabilidad, <strong>bajo <img src="https://latex.codecogs.com/png.latex?H_0"></strong>, de obtener un estadístico tan extremo o más que el observado. No es <img src="https://latex.codecogs.com/png.latex?P(H_0%5Cmid%20%5Ctext%7Bdatos%7D)">. No es “qué tan probable es el efecto”. Es un área en la cola de la distribución <strong>suponiendo que no hay efecto</strong>.</p>
<p>Regla operativa: si <img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bp-value%7D%5Cle%5Calpha">, se <strong>rechaza</strong> <img src="https://latex.codecogs.com/png.latex?H_0"> al nivel <img src="https://latex.codecogs.com/png.latex?%5Calpha">. Si no, <strong>no se rechaza</strong>. No rechazar no es “demostrar <img src="https://latex.codecogs.com/png.latex?H_0">”.</p>
</section>
<section id="errores-tipo-i-tipo-ii-y-potencia" class="level3">
<h3 class="anchored" data-anchor-id="errores-tipo-i-tipo-ii-y-potencia">1.7 Errores tipo I, tipo II y potencia</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Error</th>
<th>Qué ocurre</th>
<th>Control</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Tipo I</strong></td>
<td>Se rechaza <img src="https://latex.codecogs.com/png.latex?H_0"> siendo cierta</td>
<td>Su tasa, si <img src="https://latex.codecogs.com/png.latex?H_0"> es cierta, es <img src="https://latex.codecogs.com/png.latex?%5Calpha"></td>
</tr>
<tr class="even">
<td><strong>Tipo II</strong></td>
<td>No se rechaza <img src="https://latex.codecogs.com/png.latex?H_0"> siendo falsa</td>
<td>Su tasa se llama <img src="https://latex.codecogs.com/png.latex?%5Cbeta"></td>
</tr>
</tbody>
</table>
<p>La <strong>potencia</strong> es <img src="https://latex.codecogs.com/png.latex?1-%5Cbeta">: probabilidad de detectar el efecto cuando existe. Sube con <img src="https://latex.codecogs.com/png.latex?n">, con el tamaño del efecto y con <img src="https://latex.codecogs.com/png.latex?%5Csigma"> más chica; baja si <img src="https://latex.codecogs.com/png.latex?%5Calpha"> se hace más estricta.</p>
</section>
<section id="significativo-no-es-importante" class="level3">
<h3 class="anchored" data-anchor-id="significativo-no-es-importante">1.8 Significativo no es importante</h3>
<p>“Significativo” en esta jerga significa <em>el azar, bajo <img src="https://latex.codecogs.com/png.latex?H_0">, rara vez produce algo tan extremo</em>. No significa <em>grande</em>, <em>útil</em> ni <em>desplegable a producción</em>. Con <img src="https://latex.codecogs.com/png.latex?n"> enorme, un efecto de 0.2 ms puede tener p-value <img src="https://latex.codecogs.com/png.latex?10%5E%7B-8%7D">. Con <img src="https://latex.codecogs.com/png.latex?n"> chico, un efecto de 15 ms puede no rechazar.</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Pregunta</th>
<th>Herramienta</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>¿Qué número de la muestra uso para <img src="https://latex.codecogs.com/png.latex?%5Ctheta">?</td>
<td>Estimación puntual</td>
</tr>
<tr class="even">
<td>¿Cuánto tiembla ese número entre muestras?</td>
<td>Error estándar</td>
</tr>
<tr class="odd">
<td>¿Qué rangos produce el procedimiento?</td>
<td>Intervalo de confianza</td>
</tr>
<tr class="even">
<td>¿Los datos son raros si <img src="https://latex.codecogs.com/png.latex?H_0"> es cierta?</td>
<td>p-value / prueba</td>
</tr>
<tr class="odd">
<td>¿Cuánto error de falsa alarma acepto?</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Calpha"></td>
</tr>
<tr class="even">
<td>¿Detectaría este efecto si existiera?</td>
<td>Potencia</td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="por-qué-importa-en-ia-y-machine-learning" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-importa-en-ia-y-machine-learning">2. Por qué importa en IA y Machine Learning</h2>
<p>El modelo en validación entrega <strong>números de muestra</strong>: accuracy 0.81, latencia 118 ms, lift de 1.4%. Sin inferencia esos números se leen como propiedades del sistema. Son propiedades <strong>de estas filas</strong>.</p>
<ul>
<li>Un <strong>A/B</strong> de producto es una prueba de hipótesis sobre <img src="https://latex.codecogs.com/png.latex?%5Cmu_B-%5Cmu_A"> o <img src="https://latex.codecogs.com/png.latex?p_B-p_A">. El p-value no decide el despliegue: informa si el azar basta para explicar la diferencia.</li>
<li>El <strong>intervalo</strong> dice el rango plausible del efecto. Un p pequeño con intervalo <img src="https://latex.codecogs.com/png.latex?(0.001,%5C,0.004)"> en conversión no es el mismo hallazgo que <img src="https://latex.codecogs.com/png.latex?(0.04,%5C,0.11)">.</li>
<li>En <strong>selección de modelos</strong>, comparar dos accuracies con <img src="https://latex.codecogs.com/png.latex?n=80"> en test y declarar un ganador es, en silencio, una inferencia mal hecha.</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Calpha"> y la potencia son <strong>costos</strong>: un falso positivo despliega un cambio inútil; un falso negativo mata un cambio bueno.</li>
</ul>
<p><strong>Idea central:</strong> el p-value responde a <img src="https://latex.codecogs.com/png.latex?H_0">, no a “¿vale la pena?”. El intervalo y el tamaño del efecto contestan la segunda pregunta.</p>
</section>
<section id="flujo-recomendado-de-trabajo" class="level2">
<h2 class="anchored" data-anchor-id="flujo-recomendado-de-trabajo">3. Flujo recomendado de trabajo</h2>
<ol type="1">
<li><strong>Escribir el parámetro</strong> y la población (¿media de latencia? ¿diferencia de conversión?).</li>
<li><strong>Estimar</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta"> y el <strong>SE</strong>.</li>
<li><strong>Intervalo</strong> de nivel declarado (casi siempre 95%) e interpretarlo como cobertura del procedimiento.</li>
<li><strong>Prueba:</strong> <img src="https://latex.codecogs.com/png.latex?H_0">, <img src="https://latex.codecogs.com/png.latex?H_1">, <img src="https://latex.codecogs.com/png.latex?%5Calpha">, estadístico, p-value. No invertir el condicional.</li>
<li><strong>Mirar <img src="https://latex.codecogs.com/png.latex?n"> y el efecto:</strong> ¿la significancia viene del tamaño de la muestra o de un cambio que importa?</li>
<li><strong>Decidir con costos</strong>, no solo con <img src="https://latex.codecogs.com/png.latex?p%3C0.05">.</li>
</ol>
<p><strong>Criterio general:</strong> un p-value sin intervalo, sin <img src="https://latex.codecogs.com/png.latex?n"> y sin unidades del efecto es un sello, no un argumento.</p>
</section>
<section id="preparar-el-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparar-el-entorno">4. Preparar el entorno</h2>
<div id="c009" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:18.077128Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:18.076727Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:19.778657Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:19.778260Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb1-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Python:"</span>, sys.version.split()[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> stats</span>
<span id="cb1-8"></span>
<span id="cb1-9">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-10"></span>
<span id="cb1-11">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"figure.figsize"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-12">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"axes.grid"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb1-13">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grid.alpha"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span></span>
<span id="cb1-14"></span>
<span id="cb1-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Entorno listo: numpy, pandas, matplotlib, scipy."</span>)</span>
<span id="cb1-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"scipy:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">__import__</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"scipy"</span>).__version__, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"| numpy:"</span>, np.__version__)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Python: 3.13.9
Entorno listo: numpy, pandas, matplotlib, scipy.
scipy: 1.16.3 | numpy: 2.3.5</code></pre>
</div>
</div>
<section id="funciones-de-visualización-definidas-una-sola-vez" class="level3">
<h3 class="anchored" data-anchor-id="funciones-de-visualización-definidas-una-sola-vez">Funciones de visualización (definidas una sola vez)</h3>
<p>Cada etapa solo <strong>llama</strong> a la función. El detalle del gráfico queda aquí.</p>
<div id="c011" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:19.780530Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:19.780296Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:19.790698Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:19.790300Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_dist_muestral(medias_nchico, medias_ngrande, mu, n_chico, n_grande, titulo):</span>
<span id="cb3-2">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.3</span>))</span>
<span id="cb3-3">    ax.hist(medias_nchico, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">28</span>, density<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"n = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n_chico<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-4">    ax.hist(medias_ngrande, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">28</span>, density<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"n = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n_grande<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-5">    ax.axvline(mu, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$\m</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">u</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mu<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-6">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"media muestral"</span>)</span>
<span id="cb3-7">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"densidad"</span>)</span>
<span id="cb3-8">    ax.set_title(titulo)</span>
<span id="cb3-9">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-10">    plt.tight_layout()</span>
<span id="cb3-11">    plt.show()</span>
<span id="cb3-12"></span>
<span id="cb3-13"></span>
<span id="cb3-14"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_una_muestra(muestra, mu, low, high, titulo):</span>
<span id="cb3-15">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.6</span>))</span>
<span id="cb3-16">    ax.scatter(muestra, np.zeros_like(muestra), alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">28</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"observaciones"</span>)</span>
<span id="cb3-17">    ax.axvline(mu, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$\m</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">u</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mu<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-18">    ax.axvline(muestra.mean(), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$\b</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">ar x</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>muestra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-19">    ax.hlines(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span>, low, high, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IC 95%"</span>)</span>
<span id="cb3-20">    ax.set_yticks([])</span>
<span id="cb3-21">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"latencia (ms)"</span>)</span>
<span id="cb3-22">    ax.set_title(titulo)</span>
<span id="cb3-23">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"upper right"</span>)</span>
<span id="cb3-24">    plt.tight_layout()</span>
<span id="cb3-25">    plt.show()</span>
<span id="cb3-26"></span>
<span id="cb3-27"></span>
<span id="cb3-28"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_cobertura(intervalos, mu, titulo):</span>
<span id="cb3-29">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.2</span>))</span>
<span id="cb3-30">    cubre <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb3-31">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, (lo, hi) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(intervalos):</span>
<span id="cb3-32">        ok <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> mu <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> hi</span>
<span id="cb3-33">        cubre <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(ok)</span>
<span id="cb3-34">        ax.hlines(i, lo, hi, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> ok <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>)</span>
<span id="cb3-35">    ax.axvline(mu, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.2"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$\m</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">u</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mu<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-36">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"intervalo de confianza 95% para la media"</span>)</span>
<span id="cb3-37">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"réplica"</span>)</span>
<span id="cb3-38">    ax.set_title(titulo)</span>
<span id="cb3-39">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-40">    plt.tight_layout()</span>
<span id="cb3-41">    plt.show()</span>
<span id="cb3-42">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> cubre</span>
<span id="cb3-43"></span>
<span id="cb3-44"></span>
<span id="cb3-45"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_pvalores(p_h0, p_h1, titulo):</span>
<span id="cb3-46">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>))</span>
<span id="cb3-47">    ax.hist(p_h0, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), density<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bajo H0 (debe verse plano)"</span>)</span>
<span id="cb3-48">    ax.hist(p_h1, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), density<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bajo H1 (se acumula a la izquierda)"</span>)</span>
<span id="cb3-49">    ax.axvline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\a</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">lpha</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> = 0</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">.</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">05"</span>)</span>
<span id="cb3-50">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p-value"</span>)</span>
<span id="cb3-51">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"densidad"</span>)</span>
<span id="cb3-52">    ax.set_title(titulo)</span>
<span id="cb3-53">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-54">    plt.tight_layout()</span>
<span id="cb3-55">    plt.show()</span>
<span id="cb3-56"></span>
<span id="cb3-57"></span>
<span id="cb3-58"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_tipo_i_ii(mu0, mu1, se, alpha, titulo):</span>
<span id="cb3-59">    z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.norm.ppf(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb3-60">    crit_lo, crit_hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mu0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se, mu0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se</span>
<span id="cb3-61">    xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(mu0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se, mu1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>)</span>
<span id="cb3-62">    f0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.norm.pdf(xs, mu0, se)</span>
<span id="cb3-63">    f1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.norm.pdf(xs, mu1, se)</span>
<span id="cb3-64">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.4</span>))</span>
<span id="cb3-65">    ax.plot(xs, f0, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"muestral si </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">H_0</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> </span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$\m</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">u</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mu0<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-66">    ax.plot(xs, f1, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"muestral si </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">H_1</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> </span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$\m</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">u</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mu1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-67">    ax.axvline(crit_lo, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.35"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">":"</span>)</span>
<span id="cb3-68">    ax.axvline(crit_hi, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.35"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">":"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"umbrales de rechazo"</span>)</span>
<span id="cb3-69">    ax.fill_between(xs, f0, where<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> crit_lo) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> (xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> crit_hi), alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tipo I (rechazar H0 cierta)"</span>)</span>
<span id="cb3-70">    ax.fill_between(xs, f1, where<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> crit_lo) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> crit_hi), alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tipo II (no rechazar H0 falsa)"</span>)</span>
<span id="cb3-71">    ax.set_xlabel(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r"media muestral </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$\b</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">ar x</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-72">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"densidad"</span>)</span>
<span id="cb3-73">    ax.set_title(titulo)</span>
<span id="cb3-74">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"upper right"</span>)</span>
<span id="cb3-75">    plt.tight_layout()</span>
<span id="cb3-76">    plt.show()</span>
<span id="cb3-77">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> crit_lo, crit_hi</span>
<span id="cb3-78"></span>
<span id="cb3-79"></span>
<span id="cb3-80"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_ab(a, b, titulo):</span>
<span id="cb3-81">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>))</span>
<span id="cb3-82">    ax.boxplot([a, b], tick_labels<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"A (actual)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"B (cuantizado)"</span>], showfliers<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb3-83">    ax.scatter(np.ones(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(a)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.04</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(a)), a, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>)</span>
<span id="cb3-84">    ax.scatter(np.full(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(b), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.04</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(b)), b, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>)</span>
<span id="cb3-85">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"latencia (ms)"</span>)</span>
<span id="cb3-86">    ax.set_title(titulo)</span>
<span id="cb3-87">    plt.tight_layout()</span>
<span id="cb3-88">    plt.show()</span></code></pre></div></div>
</div>
</section>
</section>
<section id="desarrollo-por-etapas" class="level2">
<h2 class="anchored" data-anchor-id="desarrollo-por-etapas">5. Desarrollo por etapas</h2>
<p>Se fabrica una población de latencias con <img src="https://latex.codecogs.com/png.latex?%5Cmu"> conocida. Así se puede <strong>ver</strong> si el intervalo cubre y si la prueba se equivoca. Después se pasa a un A/B donde <img src="https://latex.codecogs.com/png.latex?%5Cmu"> ya no se “conoce” como en el laboratorio: se estima y se reporta.</p>
<section id="etapa-1-población-muestra-y-estadístico" class="level3">
<h3 class="anchored" data-anchor-id="etapa-1-población-muestra-y-estadístico">Etapa 1: Población, muestra y estadístico</h3>
<p>Población de <img src="https://latex.codecogs.com/png.latex?N=20%5C,000"> latencias (ms), <img src="https://latex.codecogs.com/png.latex?%5Cmu=200">, <img src="https://latex.codecogs.com/png.latex?%5Csigma=40">. Se extrae <strong>una</strong> muestra de <img src="https://latex.codecogs.com/png.latex?n=25">. El parámetro no cambia; <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x"> sí.</p>
<div id="c014" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:19.792322Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:19.792161Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:19.796539Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:19.796131Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">mu, sigma, N <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">40.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20_000</span></span>
<span id="cb4-2">poblacion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(mu, sigma, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>N)</span>
<span id="cb4-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Parámetro μ (población) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(poblacion.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (diseño: 200)"</span>)</span>
<span id="cb4-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"σ poblacional ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(poblacion.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb4-5"></span>
<span id="cb4-6">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span></span>
<span id="cb4-7">muestra <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.choice(poblacion, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n, replace<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb4-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb4-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n ="</span>, n)</span>
<span id="cb4-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x̄  ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(muestra.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← estadístico, no es μ"</span>)</span>
<span id="cb4-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"s  ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(muestra.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← estima σ"</span>)</span>
<span id="cb4-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La muestra no 'es' la población: x̄ − μ ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(muestra.mean() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> poblacion.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Parámetro μ (población) = 200.202   (diseño: 200)
σ poblacional = 40.188

n = 25
x̄  = 194.439   ← estadístico, no es μ
s  = 35.769   ← estima σ
La muestra no 'es' la población: x̄ − μ = -5.763</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x"> falló por unos milisegundos. Eso no es un error de código: es el muestreo. Inferir es cuantificar ese fallo, no negarlo.</p>
</section>
<section id="etapa-2-distribución-muestral-el-estadístico-también-tiene-forma" class="level3">
<h3 class="anchored" data-anchor-id="etapa-2-distribución-muestral-el-estadístico-también-tiene-forma">Etapa 2: Distribución muestral — el estadístico también tiene forma</h3>
<p>Se repite el muestreo <img src="https://latex.codecogs.com/png.latex?4%5C,000"> veces con <img src="https://latex.codecogs.com/png.latex?n=10"> y con <img src="https://latex.codecogs.com/png.latex?n=80">. El histograma de las <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x"> <strong>no</strong> es el histograma de las latencias: es la distribución de la media.</p>
<div id="c017" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:19.798044Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:19.797891Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:20.037793Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:20.037023Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> medias_muestrales(n, n_rep<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4000</span>):</span>
<span id="cb6-2">    idx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.integers(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, N, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(n_rep, n))</span>
<span id="cb6-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> poblacion[idx].mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb6-4"></span>
<span id="cb6-5">medias_10 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> medias_muestrales(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb6-6">medias_80 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> medias_muestrales(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>)</span>
<span id="cb6-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n=10:  media de x̄ ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(medias_10.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  DE de x̄ ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(medias_10.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (σ/√n ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(sigma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">")"</span>)</span>
<span id="cb6-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n=80:  media de x̄ ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(medias_80.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  DE de x̄ ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(medias_80.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (σ/√n ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(sigma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">")"</span>)</span>
<span id="cb6-9"></span>
<span id="cb6-10">graficar_dist_muestral(</span>
<span id="cb6-11">    medias_10, medias_80, mu, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>,</span>
<span id="cb6-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La media se concentra alrededor de μ; n grande estrecha la campana"</span>,</span>
<span id="cb6-13">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>n=10:  media de x̄ = 199.842   DE de x̄ = 12.701   (σ/√n = 12.649 )
n=80:  media de x̄ = 200.062   DE de x̄ = 4.492   (σ/√n = 4.472 )</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/09-inferencia-estadistica/index_files/figure-html/cell-5-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Después.</strong> Las dos campanas están centradas en <img src="https://latex.codecogs.com/png.latex?200">. La de <img src="https://latex.codecogs.com/png.latex?n=80"> es más angosta: <img src="https://latex.codecogs.com/png.latex?%5Csigma/%5Csqrt%20n"> cayó. Esa angostura <strong>es</strong> el error estándar cuando <img src="https://latex.codecogs.com/png.latex?%5Csigma"> se conoce. El histograma de una sola muestra de latencias no muestra esto; hace falta el experimento repetido (aquí, simulado).</p>
</section>
<section id="etapa-3-estimación-puntual-y-error-estándar" class="level3">
<h3 class="anchored" data-anchor-id="etapa-3-estimación-puntual-y-error-estándar">Etapa 3: Estimación puntual y error estándar</h3>
<p>Para la muestra de <img src="https://latex.codecogs.com/png.latex?n=25">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%5Cmu=%5Cbar%20x,%5Cqquad%20%5Cmathrm%7BSE%7D=%5Cfrac%7Bs%7D%7B%5Csqrt%20n%7D.%0A"></p>
<p>El SE <strong>no</strong> es “el error de cada medición”. Es el error típico de <strong>la media</strong>.</p>
<div id="c020" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:20.039547Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:20.039367Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:20.043653Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:20.043093Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">xbar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> muestra.mean()</span>
<span id="cb8-2">s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> muestra.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb8-3">se <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(n)</span>
<span id="cb8-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Estimación puntual μ̂ = x̄ ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(xbar, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb8-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"s ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(s, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb8-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SE = s/√n ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(se, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"   (si se usara σ: "</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(sigma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(n), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">")"</span>)</span>
<span id="cb8-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb8-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Un intervalo grosero x̄ ± 2·SE = [</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>xbar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>xbar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">]"</span>)</span>
<span id="cb8-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Eso todavía no es el IC con t; solo ubica la escala del temblor."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Estimación puntual μ̂ = x̄ = 194.439
s = 35.769
SE = s/√n = 7.154    (si se usara σ:  8.0 )

Un intervalo grosero x̄ ± 2·SE = [180.13, 208.75]
Eso todavía no es el IC con t; solo ubica la escala del temblor.</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> Reportar <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x=194.4"> sin SE invita a leer 194.4 como si fuera <img src="https://latex.codecogs.com/png.latex?%5Cmu">. Con <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BSE%7D%5Capprox%207.2">, 194.4 y 200 son compatibles: están a menos de un error estándar. El número suelto sobrestima la precisión.</p>
</section>
<section id="etapa-4-intervalo-de-confianza-para-la-media" class="level3">
<h3 class="anchored" data-anchor-id="etapa-4-intervalo-de-confianza-para-la-media">Etapa 4: Intervalo de confianza para la media</h3>
<p>Con <img src="https://latex.codecogs.com/png.latex?%5Csigma"> desconocida se usa la <img src="https://latex.codecogs.com/png.latex?t"> de Student, <img src="https://latex.codecogs.com/png.latex?n-1"> grados de libertad, <img src="https://latex.codecogs.com/png.latex?%5Calpha=0.05">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbar%20x%20%5Cpm%20t_%7B24,%5C,0.975%7D%5C,%5Cmathrm%7BSE%7D.%0A"></p>
<p>SciPy lo calcula con <code>stats.t.interval</code> o a mano. Las dos vías deben coincidir.</p>
<div id="c023" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:20.046261Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:20.046104Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:20.132282Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:20.131748Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span></span>
<span id="cb10-2">gl <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb10-3">t_crit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.t.ppf(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, df<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>gl)</span>
<span id="cb10-4">low <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> xbar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> t_crit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se</span>
<span id="cb10-5">high <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> xbar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> t_crit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se</span>
<span id="cb10-6">low_sp, high_sp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.t.interval(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> alpha, df<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>gl, loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>xbar, scale<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>se)</span>
<span id="cb10-7"></span>
<span id="cb10-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"t crítico (gl=24, 97.5%) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(t_crit, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (z sería 1.960)"</span>)</span>
<span id="cb10-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IC 95% a mano:   ["</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(low, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(high, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"]"</span>)</span>
<span id="cb10-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IC 95% SciPy:    ["</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(low_sp, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(high_sp, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"]"</span>)</span>
<span id="cb10-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"¿Cubre μ = 200?"</span>, low <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> mu <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> high)</span>
<span id="cb10-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Anchura ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(high <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> low, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ms"</span>)</span>
<span id="cb10-13"></span>
<span id="cb10-14">graficar_una_muestra(</span>
<span id="cb10-15">    muestra, mu, low, high,</span>
<span id="cb10-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Una muestra, su media y el IC 95% (t). μ puede quedar dentro o fuera"</span>,</span>
<span id="cb10-17">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>t crítico (gl=24, 97.5%) = 2.0639   (z sería 1.960)
IC 95% a mano:   [ 179.67 , 209.2 ]
IC 95% SciPy:    [ 179.67 , 209.2 ]
¿Cubre μ = 200? True
Anchura = 29.53 ms</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/09-inferencia-estadistica/index_files/figure-html/cell-7-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> El intervalo es un rango para <img src="https://latex.codecogs.com/png.latex?%5Cmu">, no para “el 95% de las latencias”. El 95% de las observaciones vive cerca de <img src="https://latex.codecogs.com/png.latex?%5Cmu%5Cpm%202%5Csigma"> (unos <img src="https://latex.codecogs.com/png.latex?%5Cpm%2080"> ms), un intervalo mucho más ancho. Confundir IC de la media con rango de los datos es un error de denominador: se está hablando del centro, no de cada fila.</p>
</section>
<section id="etapa-5-qué-significa-el-95-cobertura" class="level3">
<h3 class="anchored" data-anchor-id="etapa-5-qué-significa-el-95-cobertura">Etapa 5: Qué significa el 95% — cobertura</h3>
<p>Se construyen <img src="https://latex.codecogs.com/png.latex?100"> intervalos, cada uno con su propia muestra de <img src="https://latex.codecogs.com/png.latex?n=25">. En teoría, alrededor de 95 cubren <img src="https://latex.codecogs.com/png.latex?%5Cmu">. Los que fallan (en rojo) no son “intervalos mal calculados”: son el 5% que el procedimiento acepta perder.</p>
<div id="c026" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:20.134020Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:20.133835Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:20.316574Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:20.316101Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">n_rep <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb12-2">intervalos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb12-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(n_rep):</span>
<span id="cb12-4">    m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.choice(poblacion, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n, replace<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb12-5">    xb, ss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> m.mean(), m.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb12-6">    lo, hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.t.interval(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span>, df<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>xb, scale<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(n))</span>
<span id="cb12-7">    intervalos.append((lo, hi))</span>
<span id="cb12-8"></span>
<span id="cb12-9">cubre <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> graficar_cobertura(</span>
<span id="cb12-10">    intervalos, mu,</span>
<span id="cb12-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"100 intervalos al 95%: los rojos no cubren μ (eso debe pasar ~5 veces)"</span>,</span>
<span id="cb12-12">)</span>
<span id="cb12-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Intervalos que cubren μ:"</span>, cubre, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"de"</span>, n_rep)</span>
<span id="cb12-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cobertura empírica:"</span>, cubre <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n_rep)</span>
<span id="cb12-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"No es 'este intervalo tiene P=0.95'. Es 'el método acierta ~95 de cada 100'."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/09-inferencia-estadistica/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Intervalos que cubren μ: 98 de 100
Cobertura empírica: 0.98
No es 'este intervalo tiene P=0.95'. Es 'el método acierta ~95 de cada 100'.</code></pre>
</div>
</div>
<p><strong>El contraste de lectura.</strong> Tras ver la figura, “IC 95% = <img src="https://latex.codecogs.com/png.latex?(a,b)">” se redacta así: <em>un procedimiento que, usado una y otra vez, cubre <img src="https://latex.codecogs.com/png.latex?%5Cmu"> en el 95% de las muestras produjo este rango</em>. No: <em><img src="https://latex.codecogs.com/png.latex?%5Cmu"> es aleatorio y vive aquí con probabilidad 0.95</em>. Esa segunda frase es otra escuela (se trata en el enfoque bayesiano). Aquí <img src="https://latex.codecogs.com/png.latex?%5Cmu"> es fijo; el intervalo es lo que se mueve.</p>
</section>
<section id="etapa-6-prueba-de-hipótesis-h_0-mu200" class="level3">
<h3 class="anchored" data-anchor-id="etapa-6-prueba-de-hipótesis-h_0-mu200">Etapa 6: Prueba de hipótesis — <img src="https://latex.codecogs.com/png.latex?H_0">: <img src="https://latex.codecogs.com/png.latex?%5Cmu=200"></h3>
<p>Misma muestra de la etapa 1. ¿Es compatible con un SLA de 200 ms?</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AH_0:%5Cmu=200,%5Cqquad%20H_1:%5Cmu%5Cneq%20200,%5Cqquad%20%5Calpha=0.05.%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0At=%5Cfrac%7B%5Cbar%20x-200%7D%7Bs/%5Csqrt%20n%7D,%5Cqquad%0A%5Ctext%7Bp-value%7D=P%5Cbig(%7CT_%7B24%7D%7C%5Cge%20%7Ct%7C%5Cbig).%0A"></p>
<div id="c029" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:20.318148Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:20.317990Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:20.323053Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:20.322608Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">mu0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200.0</span></span>
<span id="cb14-2">t_obs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (xbar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> mu0) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> se</span>
<span id="cb14-3">p_manual <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> stats.t.sf(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(t_obs), df<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>gl)</span>
<span id="cb14-4">tt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.ttest_1samp(muestra, popmean<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mu0)</span>
<span id="cb14-5"></span>
<span id="cb14-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"t observado ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(t_obs, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb14-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p-value a mano ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_manual, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb14-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SciPy ttest_1samp: t ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(tt.statistic, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  p ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(tt.pvalue, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb14-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"α = 0.05. ¿Rechazar H0?"</span>, tt.pvalue <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>)</span>
<span id="cb14-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb14-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IC 95% y prueba bilateral a α=0.05 son la misma frontera:"</span>)</span>
<span id="cb14-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  200 está en el IC  ↔  p &gt; 0.05  →"</span>, (low <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> mu0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> high), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y p ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(tt.pvalue, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>t observado = -0.7774
p-value a mano = 0.4445
SciPy ttest_1samp: t = -0.7774   p = 0.4445
α = 0.05. ¿Rechazar H0? False

IC 95% y prueba bilateral a α=0.05 son la misma frontera:
  200 está en el IC  ↔  p &gt; 0.05  → True y p = 0.4445</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> Aquí <strong>no</strong> se rechaza <img src="https://latex.codecogs.com/png.latex?H_0"> (<img src="https://latex.codecogs.com/png.latex?p=0.44">): una media muestral de 194.4 es perfectamente compatible con <img src="https://latex.codecogs.com/png.latex?%5Cmu=200">. Eso tampoco demuestra que <img src="https://latex.codecogs.com/png.latex?%5Cmu"> sea 200: el IC incluye todo el rango de 179.7 a 209.2 ms. Y si se hubiera rechazado, tampoco probaría que <img src="https://latex.codecogs.com/png.latex?%5Cmu"> sea <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x">: solo diría que 200 queda incómodo como explicación. En la prueba bilateral a <img src="https://latex.codecogs.com/png.latex?%5Calpha=0.05">, <strong><img src="https://latex.codecogs.com/png.latex?H_0"> se rechaza si y solo si <img src="https://latex.codecogs.com/png.latex?%5Cmu_0"> queda fuera del IC 95%</strong>.</p>
</section>
<section id="etapa-7-el-p-value-no-es-ph_0mid-textdatos" class="level3">
<h3 class="anchored" data-anchor-id="etapa-7-el-p-value-no-es-ph_0mid-textdatos">Etapa 7: El p-value no es <img src="https://latex.codecogs.com/png.latex?P(H_0%5Cmid%20%5Ctext%7Bdatos%7D)"></h3>
<p>Bajo <img src="https://latex.codecogs.com/png.latex?H_0"> (datos con <img src="https://latex.codecogs.com/png.latex?%5Cmu=200">), el p-value de una prueba bilateral bien calibrada se reparte <strong>casi uniforme</strong> en <img src="https://latex.codecogs.com/png.latex?(0,1)">. Por eso el 5% de las réplicas tiene <img src="https://latex.codecogs.com/png.latex?p%5Cle%200.05"> aunque <img src="https://latex.codecogs.com/png.latex?H_0"> sea cierta: esa es la definición de <img src="https://latex.codecogs.com/png.latex?%5Calpha">.</p>
<p>Bajo <img src="https://latex.codecogs.com/png.latex?H_1"> (aquí <img src="https://latex.codecogs.com/png.latex?%5Cmu=220">), los p-values se acumulan cerca de 0.</p>
<div id="c032" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:20.324695Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:20.324541Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:20.460491Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:20.460049Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> pvalores_unamuestra(mu_true, n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, n_rep<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3000</span>, mu0<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200.0</span>):</span>
<span id="cb16-2">    datos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(mu_true, sigma, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(n_rep, n))</span>
<span id="cb16-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> stats.ttest_1samp(datos, popmean<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mu0, axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>).pvalue</span>
<span id="cb16-4"></span>
<span id="cb16-5">p_h0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pvalores_unamuestra(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200.0</span>)</span>
<span id="cb16-6">p_h1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pvalores_unamuestra(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">220.0</span>)</span>
<span id="cb16-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bajo H0:  P(p ≤ 0.05) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>((p_h0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>).mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← debe ≈ α = 0.05"</span>)</span>
<span id="cb16-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bajo H0:  media de p  ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_h0.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← uniforme ⇒ cerca de 0.50"</span>)</span>
<span id="cb16-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bajo H1 (μ=220): P(p ≤ 0.05) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>((p_h1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>).mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← potencia"</span>)</span>
<span id="cb16-10"></span>
<span id="cb16-11">graficar_pvalores(</span>
<span id="cb16-12">    p_h0, p_h1,</span>
<span id="cb16-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Si H0 es cierta el p-value no se pega a cero: se reparte en [0, 1]"</span>,</span>
<span id="cb16-14">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Bajo H0:  P(p ≤ 0.05) = 0.0417   ← debe ≈ α = 0.05
Bajo H0:  media de p  = 0.502   ← uniforme ⇒ cerca de 0.50
Bajo H1 (μ=220): P(p ≤ 0.05) = 0.669   ← potencia</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/09-inferencia-estadistica/index_files/figure-html/cell-10-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Qué no es el p-value.</strong> No es la probabilidad de que el SLA se cumpla. No es <img src="https://latex.codecogs.com/png.latex?1-%5Ctext%7Bconfianza%7D">. No es el tamaño del efecto. Es un área de cola <strong>condicional a <img src="https://latex.codecogs.com/png.latex?H_0"></strong>. Invertirlo —leer <img src="https://latex.codecogs.com/png.latex?p=0.03"> como “hay 3% de probabilidad de que no haya efecto”— es el mismo error que <img src="https://latex.codecogs.com/png.latex?P(E%5Cmid%20+)"> versus <img src="https://latex.codecogs.com/png.latex?P(+%5Cmid%20E)">.</p>
</section>
<section id="etapa-8-tipo-i-tipo-ii-y-potencia" class="level3">
<h3 class="anchored" data-anchor-id="etapa-8-tipo-i-tipo-ii-y-potencia">Etapa 8: Tipo I, tipo II y potencia</h3>
<p>Se usa <img src="https://latex.codecogs.com/png.latex?%5Csigma"> conocida solo para <strong>dibujar</strong> el argumento (normal, umbrales <img src="https://latex.codecogs.com/png.latex?%5Cpm%20z_%7B1-%5Calpha/2%7D%5C,%5Cmathrm%7BSE%7D">). <img src="https://latex.codecogs.com/png.latex?H_0:%5Cmu=200">. La alternativa dibujada es <img src="https://latex.codecogs.com/png.latex?%5Cmu=215">. <img src="https://latex.codecogs.com/png.latex?n=30">, <img src="https://latex.codecogs.com/png.latex?%5Calpha=0.05">.</p>
<ul>
<li>Área roja bajo la campana de <img src="https://latex.codecogs.com/png.latex?H_0"> y fuera de los umbrales: <strong>tipo I</strong>.</li>
<li>Área naranja bajo la campana de <img src="https://latex.codecogs.com/png.latex?H_1"> y <em>entre</em> los umbrales: <strong>tipo II</strong>.</li>
</ul>
<div id="c035" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:20.462308Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:20.462125Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:20.617364Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:20.616869Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">n_pot, mu1, alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">215.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span></span>
<span id="cb18-2">se_con <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sigma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(n_pot)</span>
<span id="cb18-3">crit_lo, crit_hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> graficar_tipo_i_ii(</span>
<span id="cb18-4">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200.0</span>, mu1, se_con, alpha,</span>
<span id="cb18-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Tipo I (falsa alarma) y tipo II (efecto que se escapa), n=30"</span>,</span>
<span id="cb18-6">)</span>
<span id="cb18-7">z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.norm.ppf(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb18-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Tipo I teórico (bilateral, H0 cierta) = alpha</span></span>
<span id="cb18-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Tipo II: P(crit_lo &lt; Xbar &lt; crit_hi | μ=215)</span></span>
<span id="cb18-10">beta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.norm.cdf(crit_hi, loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mu1, scale<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>se_con) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> stats.norm.cdf(crit_lo, loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mu1, scale<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>se_con)</span>
<span id="cb18-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SE (σ conocida) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(se_con, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb18-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Umbrales de x̄: ["</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(crit_lo, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(crit_hi, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"]"</span>)</span>
<span id="cb18-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"α (tipo I, teoría) ="</span>, alpha)</span>
<span id="cb18-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"β (tipo II, μ=215) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(beta, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  potencia ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> beta, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb18-15"></span>
<span id="cb18-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simulación t (σ desconocida), más realista</span></span>
<span id="cb18-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> tasa_rechazo(mu_true, n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, n_rep<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4000</span>, mu0<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200.0</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>):</span>
<span id="cb18-18">    x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(mu_true, sigma, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(n_rep, n))</span>
<span id="cb18-19">    p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.ttest_1samp(x, popmean<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mu0, axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>).pvalue</span>
<span id="cb18-20">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> alpha).mean()</span>
<span id="cb18-21"></span>
<span id="cb18-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb18-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Simulación t, n=30:  P(rechazar | H0) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(tasa_rechazo(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200.0</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← tipo I ≈ 0.05"</span>)</span>
<span id="cb18-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Simulación t, n=30:  P(rechazar | μ=215) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(tasa_rechazo(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">215.0</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← potencia"</span>)</span>
<span id="cb18-25"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Simulación t, n=80:  P(rechazar | μ=215) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(tasa_rechazo(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">215.0</span>, n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← más n, más potencia"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/09-inferencia-estadistica/index_files/figure-html/cell-11-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>SE (σ conocida) = 7.303
Umbrales de x̄: [ 185.69 , 214.31 ]
α (tipo I, teoría) = 0.05
β (tipo II, μ=215) = 0.463   potencia = 0.537

Simulación t, n=30:  P(rechazar | H0) = 0.046   ← tipo I ≈ 0.05
Simulación t, n=30:  P(rechazar | μ=215) = 0.4985   ← potencia
Simulación t, n=80:  P(rechazar | μ=215) = 0.9132   ← más n, más potencia</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> Bajar <img src="https://latex.codecogs.com/png.latex?%5Calpha"> (pedir <img src="https://latex.codecogs.com/png.latex?p%3C0.01">) encoge la zona roja y <strong>agranda</strong> la naranja: menos falsas alarmas, más efectos perdidos. Subir <img src="https://latex.codecogs.com/png.latex?n"> estrecha las dos campanas y aumenta la potencia sin tocar <img src="https://latex.codecogs.com/png.latex?%5Calpha">. En un A/B, “no salió significativo” puede ser <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> alto, no ausencia de efecto.</p>
</section>
<section id="etapa-9-el-contraste-que-importa-n-grande-no-hace-importante-el-efecto" class="level3">
<h3 class="anchored" data-anchor-id="etapa-9-el-contraste-que-importa-n-grande-no-hace-importante-el-efecto">Etapa 9: El contraste que importa — <img src="https://latex.codecogs.com/png.latex?n"> grande no hace importante el efecto</h3>
<p>Dos experimentos con el <strong>mismo</strong> efecto verdadero <img src="https://latex.codecogs.com/png.latex?%5Cdelta=0.4"> ms (irrelevante para un servicio de ~200 ms) y <img src="https://latex.codecogs.com/png.latex?%5Csigma=8">.</p>
<ul>
<li>Experimento chico: <img src="https://latex.codecogs.com/png.latex?n=20">.</li>
<li>Experimento enorme: <img src="https://latex.codecogs.com/png.latex?n=4%5C,000">.</li>
</ul>
<p>La pregunta no es cuál tiene razón. Es qué afirma cada p-value.</p>
<div id="c038" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:20.619200Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:20.619033Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:20.628749Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:20.628254Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">delta, sigma_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span></span>
<span id="cb20-2"></span>
<span id="cb20-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> experimento(n, delta<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>delta, sigma<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>sigma_c):</span>
<span id="cb20-4">    a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200.0</span>, sigma, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb20-5">    b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200.0</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> delta, sigma, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb20-6">    tt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.ttest_ind(a, b, equal_var<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb20-7">    dif <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> b.mean() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> a.mean()</span>
<span id="cb20-8">    se_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sqrt(a.var(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b.var(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n)</span>
<span id="cb20-9">    lo, hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.t.interval(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span>, df<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>dif, scale<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>se_d)</span>
<span id="cb20-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb20-11">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n"</span>: n,</span>
<span id="cb20-12">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dif"</span>: dif,</span>
<span id="cb20-13">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p"</span>: tt.pvalue,</span>
<span id="cb20-14">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lo"</span>: lo,</span>
<span id="cb20-15">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hi"</span>: hi,</span>
<span id="cb20-16">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rechaza"</span>: tt.pvalue <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>,</span>
<span id="cb20-17">    }</span>
<span id="cb20-18"></span>
<span id="cb20-19">e_chico <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> experimento(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)</span>
<span id="cb20-20">e_grande <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> experimento(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4000</span>)</span>
<span id="cb20-21">tab <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame([e_chico, e_grande]).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb20-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(tab.to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb20-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb20-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Efecto de diseño δ = 0.4 ms (el usuario no lo percibe)."</span>)</span>
<span id="cb20-25"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n=20:   rechaza H0 (igualdad de medias) ="</span>, e_chico[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rechaza"</span>])</span>
<span id="cb20-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n=4000: rechaza H0 ="</span>, e_grande[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rechaza"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  pero el IC sigue siendo de décimas de ms."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>   n    dif      p      lo     hi  rechaza
  20 2.2581 0.3852 -2.9451 7.4612    False
4000 0.6133 0.0006  0.2636 0.9629     True

Efecto de diseño δ = 0.4 ms (el usuario no lo percibe).
n=20:   rechaza H0 (igualdad de medias) = False
n=4000: rechaza H0 = True   pero el IC sigue siendo de décimas de ms.</code></pre>
</div>
</div>
<p><strong>El contraste.</strong> Con <img src="https://latex.codecogs.com/png.latex?n=4%5C,000"> el azar ya no explica <img src="https://latex.codecogs.com/png.latex?0.4"> ms: el p-value cae y se “gana” el A/B. El intervalo, si está bien leído, delata que el ganador es <strong>minúsculo</strong>. Desplegar B por <img src="https://latex.codecogs.com/png.latex?p%3C0.05"> sería adorar el sello. El número que decide es el efecto en milisegundos (y su costo), no la estrella al lado del p.</p>
</section>
<section id="etapa-10-ab-de-un-servicio-de-inferencia" class="level3">
<h3 class="anchored" data-anchor-id="etapa-10-ab-de-un-servicio-de-inferencia">Etapa 10: A/B de un servicio de inferencia</h3>
<p>Versión A: modelo actual. Versión B: modelo cuantizado. <img src="https://latex.codecogs.com/png.latex?n=90"> latencias por rama, diseñadas con</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?%5Cmu_A=120"> ms, <img src="https://latex.codecogs.com/png.latex?%5Cmu_B=108"> ms, <img src="https://latex.codecogs.com/png.latex?%5Csigma=18"> ms.</li>
</ul>
<p>Aquí el efecto (12 ms) <strong>sí</strong> importa para experiencia y costo. SciPy: <code>ttest_ind</code>.</p>
<div id="c041" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:20.630420Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:20.630263Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:20.714915Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:20.714461Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1">n_ab <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span></span>
<span id="cb22-2">lat_a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">120</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_ab)</span>
<span id="cb22-3">lat_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">108</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_ab)</span>
<span id="cb22-4"></span>
<span id="cb22-5">tt_ab <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.ttest_ind(lat_b, lat_a, equal_var<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># B − A: mismo signo que la diferencia</span></span>
<span id="cb22-6">dif_ab <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lat_b.mean() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> lat_a.mean()</span>
<span id="cb22-7">se_ab <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sqrt(lat_a.var(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n_ab <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> lat_b.var(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n_ab)</span>
<span id="cb22-8">lo_ab, hi_ab <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.t.interval(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span>, df<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> n_ab <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>dif_ab, scale<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>se_ab)</span>
<span id="cb22-9"></span>
<span id="cb22-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"A: x̄ ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(lat_a.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  s ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(lat_a.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb22-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"B: x̄ ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(lat_b.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  s ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(lat_b.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb22-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"B − A ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(dif_ab, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ms   SE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(se_ab, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb22-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IC 95% para μB − μA: ["</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(lo_ab, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(hi_ab, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"]"</span>)</span>
<span id="cb22-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"t ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(tt_ab.statistic, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  p ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>tt_ab<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>pvalue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2e}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>))</span>
<span id="cb22-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"¿Rechazar igualdad de medias a α=0.05?"</span>, tt_ab.pvalue <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>)</span>
<span id="cb22-16"></span>
<span id="cb22-17">graficar_ab(lat_a, lat_b, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"A/B de latencia: B está corrido hacia abajo (n=90 por rama)"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>A: x̄ = 118.61   s = 16.78
B: x̄ = 107.85   s = 18.47
B − A = -10.76 ms   SE = 2.63
IC 95% para μB − μA: [ -15.95 , -5.57 ]
t = -4.091   p = 6.5e-05
¿Rechazar igualdad de medias a α=0.05? True</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/09-inferencia-estadistica/index_files/figure-html/cell-13-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Traducción.</strong> <img src="https://latex.codecogs.com/png.latex?H_0">: las dos versiones tienen la misma media. Se rechaza. El IC de <img src="https://latex.codecogs.com/png.latex?%5Cmu_B-%5Cmu_A"> queda por debajo de 0 y su orden de magnitud es de <strong>varios milisegundos</strong>, no de décimas. A diferencia de la etapa 9, aquí coinciden significancia y relevancia. Eso no siempre pasa: por eso se reportan las dos.</p>
</section>
<section id="caso-aplicado-reportar-una-inferencia" class="level3">
<h3 class="anchored" data-anchor-id="caso-aplicado-reportar-una-inferencia">Caso aplicado: reportar una inferencia</h3>
<p>Plantilla mínima:</p>
<ol type="1">
<li><strong>Población y parámetro.</strong> Qué se mide, en quién, qué <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> se discute.</li>
<li><strong>Diseño.</strong> <img src="https://latex.codecogs.com/png.latex?n">, grupos, <img src="https://latex.codecogs.com/png.latex?%5Calpha">, si la prueba es uni o bilateral.</li>
<li><strong>Estimación.</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta">, SE.</li>
<li><strong>Intervalo.</strong> Nivel y rango, en las unidades del problema.</li>
<li><strong>Prueba.</strong> <img src="https://latex.codecogs.com/png.latex?H_0">, <img src="https://latex.codecogs.com/png.latex?H_1">, estadístico, p-value, decisión a ese <img src="https://latex.codecogs.com/png.latex?%5Calpha">.</li>
<li><strong>Relevancia y límite.</strong> ¿El efecto importa? ¿Qué amenaza la lectura (n chico, <img src="https://latex.codecogs.com/png.latex?%5Csigma"> alta, muchas pruebas)?</li>
</ol>
<p>Se aplica al A/B de la etapa 10.</p>
<p><strong>Los seis pasos, aplicados</strong></p>
<ol type="1">
<li><strong>Población.</strong> Requests de un servicio de inferencia. Parámetro: <img src="https://latex.codecogs.com/png.latex?%5Cmu_B-%5Cmu_A">, diferencia de latencia media (ms).</li>
<li><strong>Diseño.</strong> <img src="https://latex.codecogs.com/png.latex?n=90"> por rama, asignación como dos muestras independientes, <img src="https://latex.codecogs.com/png.latex?%5Calpha=0.05">, alternativa bilateral.</li>
<li><strong>Estimación.</strong> <img src="https://latex.codecogs.com/png.latex?%5Cwidehat%7B%5Cmu_B-%5Cmu_A%7D=%5Cbar%20x_B-%5Cbar%20x_A=-10.76"> ms, con SE <img src="https://latex.codecogs.com/png.latex?=2.63"> ms.</li>
<li><strong>Intervalo.</strong> IC 95% <img src="https://latex.codecogs.com/png.latex?t"> para la diferencia: <img src="https://latex.codecogs.com/png.latex?%5B-15.95,%5C,-5.57%5D"> ms. Queda entero bajo 0.</li>
<li><strong>Prueba.</strong> <img src="https://latex.codecogs.com/png.latex?H_0:%5Cmu_B=%5Cmu_A"> vs <img src="https://latex.codecogs.com/png.latex?H_1:%5Cmu_B%5Cneq%5Cmu_A">. <code>ttest_ind</code>: <img src="https://latex.codecogs.com/png.latex?t=-4.09">, <img src="https://latex.codecogs.com/png.latex?p=6.5%5Ctimes10%5E%7B-5%7D">. Se rechaza <img src="https://latex.codecogs.com/png.latex?H_0">.</li>
<li><strong>Relevancia.</strong> El corrimiento es del orden de 10 ms sobre una base de ~120 ms: relevante para cola p95 y costo de cómputo. Limitación: datos sintéticos, varianzas tratadas como iguales, una sola métrica, sin corrección por múltiples tests.</li>
</ol>
<blockquote class="blockquote">
<p>En un A/B de latencia con 90 observaciones por versión, la diferencia muestral <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x_B-%5Cbar%20x_A"> es <img src="https://latex.codecogs.com/png.latex?-10.8"> ms (IC 95%: <img src="https://latex.codecogs.com/png.latex?-16.0"> a <img src="https://latex.codecogs.com/png.latex?-5.6"> ms), el intervalo no cruza 0 y se rechaza igualdad de medias a <img src="https://latex.codecogs.com/png.latex?%5Calpha=0.05">. Se recomienda B por el <strong>tamaño del efecto en ms</strong>, no solo por el p-value. Limitación: una métrica, sin p95 ni costo, y <img src="https://latex.codecogs.com/png.latex?n"> fijo de antemano (no se detuvo el test al primer <img src="https://latex.codecogs.com/png.latex?p%3C0.05">).</p>
</blockquote>
</section>
<section id="errores-que-conviene-nombrar" class="level3">
<h3 class="anchored" data-anchor-id="errores-que-conviene-nombrar">Errores que conviene nombrar</h3>
<ol type="1">
<li><strong>Leer el p-value como <img src="https://latex.codecogs.com/png.latex?P(H_0%5Cmid%20%5Ctext%7Bdatos%7D)">.</strong> Es <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bdato%20tan%20extremo%7D%5Cmid%20H_0)">.</li>
<li><strong>Leer el IC 95% como probabilidad sobre <img src="https://latex.codecogs.com/png.latex?%5Cmu">.</strong> El 95% es cobertura del procedimiento.</li>
<li><strong>Confundir IC de la media con el rango del 95% de las observaciones.</strong></li>
<li><strong>“No significativo = no hay efecto.”</strong> Puede ser <img src="https://latex.codecogs.com/png.latex?n"> chico (potencia baja).</li>
<li><strong>“Significativo = importante.”</strong> Puede ser <img src="https://latex.codecogs.com/png.latex?n"> enorme y <img src="https://latex.codecogs.com/png.latex?%5Cdelta"> irrelevante.</li>
<li><strong><img src="https://latex.codecogs.com/png.latex?%5Calpha=0.05"> como ley.</strong> Es un costo de falsa alarma, no un teorema.</li>
<li><strong>Mirar <img src="https://latex.codecogs.com/png.latex?p"> a cada minuto del A/B y parar en el primer 0.049.</strong> Infla el tipo I.</li>
</ol>
</section>
<section id="idea-clave" class="level3">
<h3 class="anchored" data-anchor-id="idea-clave">Idea clave</h3>
<p><strong>La inferencia declara incertidumbre; no convierte la muestra en población.</strong> El SE y el intervalo miden el temblor de <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta">. El p-value mide la rareza bajo <img src="https://latex.codecogs.com/png.latex?H_0">. Ninguno de los dos mide, por sí solo, si el cambio vale el despliegue.</p>
</section>
<section id="síntesis" class="level3">
<h3 class="anchored" data-anchor-id="síntesis">Síntesis</h3>
<p>Se partió de una población con <img src="https://latex.codecogs.com/png.latex?%5Cmu"> conocida para ver la distribución muestral, el SE, la cobertura del IC y la calibración del p-value. Se separaron tipo I, tipo II y potencia. El contraste <img src="https://latex.codecogs.com/png.latex?n=20"> versus <img src="https://latex.codecogs.com/png.latex?n=4%5C,000"> con el mismo <img src="https://latex.codecogs.com/png.latex?%5Cdelta"> irrelevante mostró que la significancia no es magnitud. El A/B de latencia aplicó la misma plantilla a una diferencia que sí importa. El objeto que queda es <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta%5Cpm%5Ctext%7Bincertidumbre%7D">, no un sello <img src="https://latex.codecogs.com/png.latex?p%3C0.05">.</p>
</section>
</section>
<section id="guía-rápida-qué-fórmula-usar" class="level2">
<h2 class="anchored" data-anchor-id="guía-rápida-qué-fórmula-usar">6. Guía rápida: ¿qué fórmula usar?</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Situación</th>
<th>Qué usar</th>
<th>Por qué</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Un número para <img src="https://latex.codecogs.com/png.latex?%5Cmu"> o <img src="https://latex.codecogs.com/png.latex?p"></td>
<td><img src="https://latex.codecogs.com/png.latex?%5Cbar%20x">, <img src="https://latex.codecogs.com/png.latex?%5Chat%20p"></td>
<td>Estimación puntual</td>
</tr>
<tr class="even">
<td>Precisión de esa media</td>
<td><img src="https://latex.codecogs.com/png.latex?s/%5Csqrt%20n"></td>
<td>Error estándar, no <img src="https://latex.codecogs.com/png.latex?s"></td>
</tr>
<tr class="odd">
<td>Rango para <img src="https://latex.codecogs.com/png.latex?%5Cmu"> (<img src="https://latex.codecogs.com/png.latex?%5Csigma"> desconocida)</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Cbar%20x%5Cpm%20t_%7Bn-1%7D%5C,s/%5Csqrt%20n"></td>
<td>IC de la media</td>
</tr>
<tr class="even">
<td><img src="https://latex.codecogs.com/png.latex?%5Csigma"> conocida, <img src="https://latex.codecogs.com/png.latex?n"> grande</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Cbar%20x%5Cpm%20z_%7B1-%5Calpha/2%7D%5C,%5Csigma/%5Csqrt%20n"></td>
<td>Límite normal</td>
</tr>
<tr class="odd">
<td>¿Estos datos son raros si <img src="https://latex.codecogs.com/png.latex?%5Cmu=%5Cmu_0">?</td>
<td><img src="https://latex.codecogs.com/png.latex?t"> / <code>ttest_1samp</code></td>
<td>Prueba de una media</td>
</tr>
<tr class="even">
<td>¿Dos grupos difieren?</td>
<td><code>ttest_ind</code> (o z de proporciones)</td>
<td>A/B de medias</td>
</tr>
<tr class="odd">
<td>¿Cuántas alarmas falsas acepto?</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Calpha"></td>
<td>Tipo I</td>
</tr>
<tr class="even">
<td>¿Detectaría este <img src="https://latex.codecogs.com/png.latex?%5Cdelta"> con este <img src="https://latex.codecogs.com/png.latex?n">?</td>
<td>Potencia <img src="https://latex.codecogs.com/png.latex?1-%5Cbeta"></td>
<td>Tipo II</td>
</tr>
</tbody>
</table>
<p><strong>Regla de comunicación:</strong> parámetro, <img src="https://latex.codecogs.com/png.latex?n">, estimación, intervalo, p-value y <strong>unidades del efecto</strong>, en ese orden.</p>
</section>
<section id="guía-práctica-para-reportar-una-inferencia" class="level2">
<h2 class="anchored" data-anchor-id="guía-práctica-para-reportar-una-inferencia">7. Guía práctica para reportar una inferencia</h2>
<section id="paso-1-población-y-parámetro" class="level3">
<h3 class="anchored" data-anchor-id="paso-1-población-y-parámetro">Paso 1: población y parámetro</h3>
<p>Qué se observa y qué <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> se discute (<img src="https://latex.codecogs.com/png.latex?%5Cmu">, <img src="https://latex.codecogs.com/png.latex?p">, <img src="https://latex.codecogs.com/png.latex?%5Cmu_B-%5Cmu_A">).</p>
</section>
<section id="paso-2-diseño-y-alpha" class="level3">
<h3 class="anchored" data-anchor-id="paso-2-diseño-y-alpha">Paso 2: diseño y <img src="https://latex.codecogs.com/png.latex?%5Calpha"></h3>
<p><img src="https://latex.codecogs.com/png.latex?n">, grupos, unilateral o bilateral, nivel de significancia.</p>
</section>
<section id="paso-3-estimación-y-se" class="level3">
<h3 class="anchored" data-anchor-id="paso-3-estimación-y-se">Paso 3: estimación y SE</h3>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta"> y cómo tiembla.</p>
</section>
<section id="paso-4-intervalo-y-prueba" class="level3">
<h3 class="anchored" data-anchor-id="paso-4-intervalo-y-prueba">Paso 4: intervalo y prueba</h3>
<p>IC de nivel declarado; <img src="https://latex.codecogs.com/png.latex?H_0">, estadístico, p-value, decisión.</p>
</section>
<section id="paso-5-redactar" class="level3">
<h3 class="anchored" data-anchor-id="paso-5-redactar">Paso 5: redactar</h3>
<blockquote class="blockquote">
<p>“En <code>[población]</code>, con <img src="https://latex.codecogs.com/png.latex?n="><code>[...]</code>, la estimación de <code>[parámetro]</code> es <code>[θ̂]</code> (SE <code>[...]</code>). El IC <code>[nivel]</code> es <code>[rango]</code>. Se prueba <code>[H0]</code> frente a <code>[H1]</code>: <code>t/z</code>=<code>[...]</code>, p=<code>[...]</code>. A <img src="https://latex.codecogs.com/png.latex?%5Calpha="><code>[...]</code> se <code>[rechaza / no rechaza]</code> <img src="https://latex.codecogs.com/png.latex?H_0">. El efecto en unidades de <code>[ms / %]</code> <code>[sí / no]</code> es relevante porque <code>[...]</code>. Limitación: <code>[n / potencia / una métrica / múltiples tests]</code>.”</p>
</blockquote>
<p>El A/B de latencia (etapa 10) ya llenó esta plantilla.</p>
</section>
</section>
<section id="puente-hacia-las-siguientes-sesiones" class="level2">
<h2 class="anchored" data-anchor-id="puente-hacia-las-siguientes-sesiones">8. Puente hacia las siguientes sesiones</h2>
<p>La inferencia de esta sesión es <strong>frecuentista</strong>: el parámetro es fijo, los datos varían, el 95% es cobertura. Otra lectura trata <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> como incierta y actualiza <img src="https://latex.codecogs.com/png.latex?P(%5Ctheta%5Cmid%20%5Ctext%7Bdatos%7D)">. Esa es la comparación entre máxima verosimilitud, MAP y posterior de la <strong>Sesión 10</strong>. Los modelos (regresión, clasificación) volverán a estimar parámetros y a necesitar intervalos, pruebas y —sobre todo— no confundir <img src="https://latex.codecogs.com/png.latex?p"> con importancia.</p>
</section>
<section id="cierre" class="level2">
<h2 class="anchored" data-anchor-id="cierre">9. Cierre</h2>
<p>Este notebook deja el aparato mínimo para hablar de un parámetro con margen:</p>
<ul>
<li>estadístico frente a parámetro, y la distribución muestral,</li>
<li>estimación puntual y error estándar,</li>
<li>intervalo de confianza y su cobertura,</li>
<li><img src="https://latex.codecogs.com/png.latex?H_0">, <img src="https://latex.codecogs.com/png.latex?%5Calpha">, p-value (sin invertirlo),</li>
<li>tipo I, tipo II y potencia,</li>
<li>el contraste <img src="https://latex.codecogs.com/png.latex?n"> enorme / efecto minúsculo,</li>
<li>un A/B de latencia reportado con intervalo y decisión.</li>
</ul>
<p><strong>Resultado esperado:</strong> el estudiante puede construir un IC y una prueba con SciPy, explicar el 95% sin convertir <img src="https://latex.codecogs.com/png.latex?%5Cmu"> en aleatorio, y negarse a desplegar un modelo solo porque <img src="https://latex.codecogs.com/png.latex?p%3C0.05">.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>inferencia</category>
  <category>intervalos</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/basico/09-inferencia-estadistica/</guid>
  <pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Estadística para IA — 10. Enfoques frecuentista y bayesiano</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/basico/10-enfoques-frecuentista-bayesiano/</link>
  <description><![CDATA[ 




<section id="sesión-10-enfoques-frecuentista-y-bayesiano" class="level1">
<h1>Sesión 10 — Enfoques Frecuentista y Bayesiano</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado es Científico de Datos, Arquitecto de IA, Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), consultor y docente universitario, trabaja en la intersección entre Data Science, Inteligencia Artificial, Big Data e IoT, transformando problemas reales en soluciones aplicadas.</p>
<p>De la teoría a la práctica, un problema a la vez.</p>
</section>
<section id="dos-lecturas-de-la-misma-muestra" class="level2">
<h2 class="anchored" data-anchor-id="dos-lecturas-de-la-misma-muestra">Dos lecturas de la misma muestra</h2>
<p>La sesión de inferencia ya dejó un aparato: estimador, error estándar, intervalo, prueba. Ese aparato es <strong>frecuentista</strong>: el parámetro <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> es un número fijo; lo aleatorio es la muestra. Otra lectura trata <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> como incierta <em>antes</em> de ver los datos y actualiza <img src="https://latex.codecogs.com/png.latex?p(%5Ctheta%5Cmid%20x)"> cuando llegan. No cambia el dado; cambia <strong>de qué es la probabilidad</strong>.</p>
<p>Este notebook construye los dos marcos sobre el mismo objeto: <strong>verosimilitud</strong>, <strong>máxima verosimilitud (MLE)</strong>, <strong>prior</strong>, <strong>evidencia</strong>, <strong>posterior</strong> y <strong>MAP</strong>. El contraste que importa es operativo: <em>con <img src="https://latex.codecogs.com/png.latex?n"> chico un prior fuerte mueve el MAP; con <img src="https://latex.codecogs.com/png.latex?n"> grande MLE y MAP coinciden</em>. El MLE no es “más científico”; es el MAP de un prior plano.</p>
<p>Contexto: una moneda (Bernoulli) para ver las curvas, y un filtro de <strong>una palabra</strong> donde el MLE asigna probabilidad 0 a un token no visto (y el clasificador se rompe).</p>
<p>Electiva I — Estadística Aplicada a la Inteligencia Artificial · Módulo 3 · Sesión 10</p>
</section>
<section id="objetivos" class="level2">
<h2 class="anchored" data-anchor-id="objetivos">Objetivos</h2>
<ul>
<li>Distinguir qué pregunta hace el marco <strong>frecuentista</strong> y cuál el <strong>bayesiano</strong>.</li>
<li>Escribir la <strong>verosimilitud</strong> <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%20L(%5Ctheta;x)=p(x%5Cmid%5Ctheta)"> y no tratarla como <img src="https://latex.codecogs.com/png.latex?p(%5Ctheta%5Cmid%20x)">.</li>
<li>Calcular el <strong>MLE</strong> (a mano y sobre la curva de <img src="https://latex.codecogs.com/png.latex?%5Cell(%5Ctheta)">).</li>
<li>Actualizar un <strong>prior</strong> a un <strong>posterior</strong> y nombrar la <strong>evidencia</strong> <img src="https://latex.codecogs.com/png.latex?p(x)">.</li>
<li>Obtener el <strong>MAP</strong> y verlo como MLE penalizado por <img src="https://latex.codecogs.com/png.latex?%5Clog%20p(%5Ctheta)">.</li>
<li>Contrastar un <strong>intervalo de confianza</strong> con un <strong>intervalo creíble</strong> sobre la misma muestra.</li>
<li>Usar el MAP (suavizado de Laplace) en un <strong>clasificador</strong> que el MLE deja en cero.</li>
</ul>
<blockquote class="blockquote">
<p>Nota: se recomienda ejecutar las celdas en orden. Las fórmulas usan LaTeX; si no se ven renderizadas, abre el notebook en Jupyter o Colab.</p>
</blockquote>
</section>
<section id="dos-ontologías-de-theta" class="level2">
<h2 class="anchored" data-anchor-id="dos-ontologías-de-theta">1. Dos ontologías de <img src="https://latex.codecogs.com/png.latex?%5Ctheta"></h2>
<section id="la-pregunta-no-es-la-misma" class="level3">
<h3 class="anchored" data-anchor-id="la-pregunta-no-es-la-misma">1.1 La pregunta no es la misma</h3>
<p>Hay un parámetro <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> (una <img src="https://latex.codecogs.com/png.latex?p"> de Bernoulli, una media, un peso). Se observa <img src="https://latex.codecogs.com/png.latex?x=(x_1,%5Cldots,x_n)">.</p>
<ul>
<li><strong>Frecuentista:</strong> <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> es fijo y desconocido. <img src="https://latex.codecogs.com/png.latex?x"> es aleatoria. Se pregunta: <em>si <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> fuera este valor, ¿qué tan rara sería esta muestra?</em> De ahí salen el MLE, el error estándar, el IC y el p-value.</li>
<li><strong>Bayesiano:</strong> <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> tiene una distribución <strong>previa</strong> <img src="https://latex.codecogs.com/png.latex?p(%5Ctheta)"> (el <strong>prior</strong>: creencia o regularidad <em>antes</em> del dato). Tras ver <img src="https://latex.codecogs.com/png.latex?x">, se pregunta: <em>¿cómo se actualiza la creencia?</em> La respuesta es el <strong>posterior</strong> <img src="https://latex.codecogs.com/png.latex?p(%5Ctheta%5Cmid%20x)">.</li>
</ul>
<p>No son dos algoritmos para el mismo número. Son dos respuestas a “qué es una probabilidad”.</p>
</section>
<section id="verosimilitud" class="level3">
<h3 class="anchored" data-anchor-id="verosimilitud">1.2 Verosimilitud</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathcal%20L(%5Ctheta;x)=p(x%5Cmid%5Ctheta).%0A"></p>
<p>Es función de <img src="https://latex.codecogs.com/png.latex?%5Ctheta">, con <img src="https://latex.codecogs.com/png.latex?x"> fija. <strong>No</strong> integra a 1 en <img src="https://latex.codecogs.com/png.latex?%5Ctheta">. No es “la probabilidad del parámetro”. Es <em>qué tan compatible es <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> con lo que se vio</em>.</p>
<p>Si las observaciones son i.i.d.,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathcal%20L(%5Ctheta;x)=%5Cprod_%7Bi=1%7D%5En%20p(x_i%5Cmid%5Ctheta),%5Cqquad%0A%5Cell(%5Ctheta)=%5Clog%5Cmathcal%20L(%5Ctheta;x)=%5Csum_i%5Clog%20p(x_i%5Cmid%5Ctheta).%0A"></p>
<p>Se maximiza <img src="https://latex.codecogs.com/png.latex?%5Cell"> porque el log es monótono y convierte productos en sumas.</p>
</section>
<section id="máxima-verosimilitud" class="level3">
<h3 class="anchored" data-anchor-id="máxima-verosimilitud">1.3 Máxima verosimilitud</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%5Ctheta_%7B%5Cmathrm%7BMLE%7D%7D=%5Carg%5Cmax_%5Ctheta%20%5Cmathcal%20L(%5Ctheta;x)=%5Carg%5Cmax_%5Ctheta%20%5Cell(%5Ctheta).%0A"></p>
<p>En Bernoulli(<img src="https://latex.codecogs.com/png.latex?p">), <img src="https://latex.codecogs.com/png.latex?k=%5Csum%20x_i"> caras en <img src="https://latex.codecogs.com/png.latex?n"> lanzamientos,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%20p_%7B%5Cmathrm%7BMLE%7D%7D=%5Cfrac%7Bk%7D%7Bn%7D.%0A"></p>
<p>El MLE usa <strong>solo</strong> la muestra. Si <img src="https://latex.codecogs.com/png.latex?k=0">, <img src="https://latex.codecogs.com/png.latex?%5Chat%20p=0">: el modelo afirma que el próximo resultado es imposible. En un clasificador, un token no visto en <em>spam</em> deja <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bpalabra%7D%5Cmid%5Ctext%7Bspam%7D)=0"> y tumba el producto de Naive Bayes.</p>
</section>
<section id="prior-evidencia-y-posterior" class="level3">
<h3 class="anchored" data-anchor-id="prior-evidencia-y-posterior">1.4 Prior, evidencia y posterior</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0Ap(%5Ctheta%5Cmid%20x)=%5Cfrac%7Bp(x%5Cmid%5Ctheta)%5C,p(%5Ctheta)%7D%7Bp(x)%7D,%5Cqquad%0Ap(x)=%5Cint%20p(x%5Cmid%5Ctheta)%5C,p(%5Ctheta)%5C,d%5Ctheta.%0A"></p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?p(%5Ctheta)">: <strong>prior</strong>.</li>
<li><img src="https://latex.codecogs.com/png.latex?p(x%5Cmid%5Ctheta)">: verosimilitud.</li>
<li><img src="https://latex.codecogs.com/png.latex?p(x)">: <strong>evidencia</strong> (verosimilitud marginal). Normaliza; es la predicción de los datos <em>promediando</em> el prior. No es “el dato”.</li>
<li><img src="https://latex.codecogs.com/png.latex?p(%5Ctheta%5Cmid%20x)">: <strong>posterior</strong>. Ya es una distribución sobre <img src="https://latex.codecogs.com/png.latex?%5Ctheta">: se integra, se toman cuantiles, se predicen datos nuevos.</li>
</ul>
<p>Para Bernoulli, el prior conjugado es <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(%5Calpha,%5Cbeta)">. Tras <img src="https://latex.codecogs.com/png.latex?k"> éxitos en <img src="https://latex.codecogs.com/png.latex?n">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ap%5Cmid%20x%20%5C;%5Csim%5C;%20%5Cmathrm%7BBeta%7D(%5Calpha+k,%5C;%5Cbeta+n-k).%0A"></p>
<p><strong>Conjugado</strong> = el posterior queda en la misma familia que el prior. No es obligatorio; es cómodo.</p>
</section>
<section id="map" class="level3">
<h3 class="anchored" data-anchor-id="map">1.5 MAP</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%5Ctheta_%7B%5Cmathrm%7BMAP%7D%7D=%5Carg%5Cmax_%5Ctheta%20p(%5Ctheta%5Cmid%20x)=%5Carg%5Cmax_%5Ctheta%5Cbig(%5Clog%20p(x%5Cmid%5Ctheta)+%5Clog%20p(%5Ctheta)%5Cbig).%0A"></p>
<p>El MAP es un MLE <strong>con penalización</strong> <img src="https://latex.codecogs.com/png.latex?%5Clog%20p(%5Ctheta)">. Prior plano <img src="https://latex.codecogs.com/png.latex?%5CRightarrow"> MAP <img src="https://latex.codecogs.com/png.latex?="> MLE. Prior concentrado <img src="https://latex.codecogs.com/png.latex?%5CRightarrow"> el máximo se corre hacia la creencia previa.</p>
<p>Para <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(%5Calpha,%5Cbeta)"> y Bernoulli, el modo del posterior (definido si <img src="https://latex.codecogs.com/png.latex?%5Calpha+k%3E1"> y <img src="https://latex.codecogs.com/png.latex?%5Cbeta+n-k%3E1">) es</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%20p_%7B%5Cmathrm%7BMAP%7D%7D=%5Cfrac%7B%5Calpha+k-1%7D%7B%5Calpha+%5Cbeta+n-2%7D.%0A"></p>
<p>Con <img src="https://latex.codecogs.com/png.latex?%5Calpha=%5Cbeta=1"> (uniforme) coincide con <img src="https://latex.codecogs.com/png.latex?k/n">. El suavizado de Laplace <img src="https://latex.codecogs.com/png.latex?%5Chat%20p=(k+1)/(n+2)"> es el <strong>posterior mean</strong> de <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(1,1)">, no el modo; en la práctica de texto se usa esa media (o <img src="https://latex.codecogs.com/png.latex?%5Calpha"> pequeño) para <strong>nunca escribir un 0</strong>.</p>
</section>
<section id="intervalo-de-confianza-vs-intervalo-creíble" class="level3">
<h3 class="anchored" data-anchor-id="intervalo-de-confianza-vs-intervalo-creíble">1.6 Intervalo de confianza vs intervalo creíble</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th></th>
<th>IC frecuentista</th>
<th>Intervalo creíble</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Aleatorio</td>
<td>Los extremos (la muestra)</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Ctheta"> (según el posterior)</td>
</tr>
<tr class="even">
<td>Lectura</td>
<td>El <em>procedimiento</em> cubre <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> el 95% de las réplicas</td>
<td>El 95% de la <em>masa posterior</em> vive aquí</td>
</tr>
<tr class="odd">
<td>Usa prior</td>
<td>No</td>
<td>Sí</td>
</tr>
</tbody>
</table>
<p>El mismo <img src="https://latex.codecogs.com/png.latex?x"> produce dos rangos que <strong>no tienen por qué coincidir</strong>. Llamarlos “el 95%” sin decir cuál es mezclar escuelas.</p>
</section>
<section id="el-contraste-que-importa" class="level3">
<h3 class="anchored" data-anchor-id="el-contraste-que-importa">1.7 El contraste que importa</h3>
<table class="caption-top table">
<thead>
<tr class="header">
<th><img src="https://latex.codecogs.com/png.latex?n"></th>
<th>Prior</th>
<th>Qué se ve</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Chico</td>
<td>Fuerte (p.&nbsp;ej. <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(20,20)">)</td>
<td>MAP lejos del MLE</td>
</tr>
<tr class="even">
<td>Grande</td>
<td>El que sea</td>
<td>MAP <img src="https://latex.codecogs.com/png.latex?%5Capprox"> MLE: el dato gana</td>
</tr>
<tr class="odd">
<td>Cualquiera</td>
<td>Plano</td>
<td>MAP <img src="https://latex.codecogs.com/png.latex?="> MLE</td>
</tr>
</tbody>
</table>
<p>El prior no es “hacer trampa”. Es <strong>declarar</strong> información (o regularizar). Un prior oculto (un 0.5 por costumbre, un <code>class_weight</code>) sigue siendo prior.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Pregunta</th>
<th>Marco</th>
<th>Herramienta</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>¿Qué <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> hace más creíble <img src="https://latex.codecogs.com/png.latex?x">?</td>
<td>Frecuentista</td>
<td>MLE</td>
</tr>
<tr class="even">
<td>¿Qué <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> es más creíble <em>después</em> de <img src="https://latex.codecogs.com/png.latex?x">?</td>
<td>Bayesiano</td>
<td>MAP / posterior</td>
</tr>
<tr class="odd">
<td>¿Qué tan compatible es <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> con <img src="https://latex.codecogs.com/png.latex?x">?</td>
<td>Ambos</td>
<td>Verosimilitud</td>
</tr>
<tr class="even">
<td>¿Cuánto pesaba la creencia previa?</td>
<td>Bayesiano</td>
<td>Prior</td>
</tr>
<tr class="odd">
<td>¿Cómo se predice un <img src="https://latex.codecogs.com/png.latex?x"> nuevo?</td>
<td>Bayesiano</td>
<td><img src="https://latex.codecogs.com/png.latex?p(x_%7B%5Cmathrm%7Bnuevo%7D%7D%5Cmid%20x)"> (predicitiva)</td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="por-qué-importa-en-ia-y-machine-learning" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-importa-en-ia-y-machine-learning">2. Por qué importa en IA y Machine Learning</h2>
<p>Casi todo <code>fit</code> que maximiza una log-verosimilitud es MLE. Casi toda <strong>regularización</strong> (una penalización sobre pesos, un suavizado de conteos) es un MAP con el prior escrito como término extra.</p>
<ul>
<li>La <strong>regresión lineal</strong> por OLS es el MLE de <img src="https://latex.codecogs.com/png.latex?y%5Csim%5Cmathcal%20N(X%5Cbeta,%5Csigma%5E2%20I)">.</li>
<li>Un <strong>Naive Bayes</strong> con <img src="https://latex.codecogs.com/png.latex?P(w%5Cmid%20c)=0"> para una palabra nueva es un MLE crudo. El “add-one” es MAP / media posterior.</li>
<li>El prior de clase <img src="https://latex.codecogs.com/png.latex?P(y=1)"> es exactamente la <strong>frecuencia base</strong>: sin él, precisión y posterior se leen mal.</li>
<li>Un IC y un intervalo creíble <strong>no se comunican igual</strong> a un comité: “el procedimiento cubre” frente a “creo que <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> está aquí”.</li>
</ul>
<p><strong>Idea central:</strong> elegir MLE o MAP no es elegir librería; es decidir si <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> se estima solo con <img src="https://latex.codecogs.com/png.latex?x"> o también con una creencia (o una penalización) que hay que <strong>escribir</strong>.</p>
</section>
<section id="flujo-recomendado-de-trabajo" class="level2">
<h2 class="anchored" data-anchor-id="flujo-recomendado-de-trabajo">3. Flujo recomendado de trabajo</h2>
<ol type="1">
<li><strong>Nombrar <img src="https://latex.codecogs.com/png.latex?%5Ctheta"></strong> y el modelo <img src="https://latex.codecogs.com/png.latex?p(x%5Cmid%5Ctheta)">.</li>
<li><strong>Escribir <img src="https://latex.codecogs.com/png.latex?%5Cell(%5Ctheta)"></strong> y, si el marco es frecuentista, el MLE y su incertidumbre (SE / IC).</li>
<li><strong>Si hay información previa o hay que evitar ceros</strong>, escribir el prior y el posterior (o el MAP).</li>
<li><strong>Separar</strong> “este rango es un IC” de “este rango es creíble”.</li>
<li><strong>Predecir</strong> un dato nuevo con <img src="https://latex.codecogs.com/png.latex?p(x_%7B%5Cmathrm%7Bnuevo%7D%7D%5Cmid%20x)">, no con <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta"> a ciegas si <img src="https://latex.codecogs.com/png.latex?n"> es chico.</li>
<li><strong>Traducir al modelo:</strong> ¿el 0 de un conteo es MLE? ¿el <code>+1</code> es un prior?</li>
</ol>
<p><strong>Criterio general:</strong> un <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta"> sin decir si es MLE o MAP, y sin <img src="https://latex.codecogs.com/png.latex?n">, es un número suelto.</p>
</section>
<section id="preparar-el-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparar-el-entorno">4. Preparar el entorno</h2>
<div id="c009" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:24.421609Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:24.421226Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:26.173913Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:26.173432Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb1-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Python:"</span>, sys.version.split()[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> stats</span>
<span id="cb1-8"></span>
<span id="cb1-9">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-10"></span>
<span id="cb1-11">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"figure.figsize"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-12">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"axes.grid"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb1-13">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grid.alpha"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span></span>
<span id="cb1-14"></span>
<span id="cb1-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Entorno listo: numpy, pandas, matplotlib, scipy."</span>)</span>
<span id="cb1-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"scipy:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">__import__</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"scipy"</span>).__version__, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"| numpy:"</span>, np.__version__)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Python: 3.13.9
Entorno listo: numpy, pandas, matplotlib, scipy.
scipy: 1.16.3 | numpy: 2.3.5</code></pre>
</div>
</div>
<section id="funciones-de-visualización-definidas-una-sola-vez" class="level3">
<h3 class="anchored" data-anchor-id="funciones-de-visualización-definidas-una-sola-vez">Funciones de visualización (definidas una sola vez)</h3>
<div id="c011" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:26.175662Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:26.175440Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:26.183528Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:26.183065Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> logverosimilitud_bernoulli(p, k, n):</span>
<span id="cb3-2">    p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.clip(np.asarray(p, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>), <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-12</span>)</span>
<span id="cb3-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.log(p) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> k) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.log(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p)</span>
<span id="cb3-4"></span>
<span id="cb3-5"></span>
<span id="cb3-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> mle_bernoulli(k, n):</span>
<span id="cb3-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n</span>
<span id="cb3-8"></span>
<span id="cb3-9"></span>
<span id="cb3-10"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> map_beta(k, n, alpha, beta):</span>
<span id="cb3-11">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> beta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb3-12"></span>
<span id="cb3-13"></span>
<span id="cb3-14"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> media_posterior_beta(k, n, alpha, beta):</span>
<span id="cb3-15">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> k) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> beta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> n)</span>
<span id="cb3-16"></span>
<span id="cb3-17"></span>
<span id="cb3-18"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_loglik(k, n, titulo):</span>
<span id="cb3-19">    p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.99</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>)</span>
<span id="cb3-20">    ell <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> logverosimilitud_bernoulli(p, k, n)</span>
<span id="cb3-21">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.1</span>))</span>
<span id="cb3-22">    ax.plot(p, ell, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span>)</span>
<span id="cb3-23">    ax.axvline(k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"MLE = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-24">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p"</span>)</span>
<span id="cb3-25">    ax.set_ylabel(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">ell</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">(</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">p</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-26">    ax.set_title(titulo)</span>
<span id="cb3-27">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-28">    plt.tight_layout()</span>
<span id="cb3-29">    plt.show()</span>
<span id="cb3-30"></span>
<span id="cb3-31"></span>
<span id="cb3-32"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_prior_post(k, n, alpha, beta, titulo):</span>
<span id="cb3-33">    p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.001</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.999</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)</span>
<span id="cb3-34">    prior <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.beta.pdf(p, alpha, beta)</span>
<span id="cb3-35">    post <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.beta.pdf(p, alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> k, beta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> k)</span>
<span id="cb3-36">    lik <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(logverosimilitud_bernoulli(p, k, n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> logverosimilitud_bernoulli(k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n, k, n))</span>
<span id="cb3-37">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.3</span>))</span>
<span id="cb3-38">    ax.plot(p, prior <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> prior.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(), linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"prior Beta</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">(</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>alpha<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">,</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>beta<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-39">    ax.plot(p, lik, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.85</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"verosimilitud (escala 1)"</span>)</span>
<span id="cb3-40">    ax.plot(p, post <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> post.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C2"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"posterior Beta</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">(</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>k<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">,</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>beta<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>k<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-41">    ax.axvline(k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">":"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"MLE = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-42">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p"</span>)</span>
<span id="cb3-43">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"escala relativa (máximo = 1)"</span>)</span>
<span id="cb3-44">    ax.set_title(titulo)</span>
<span id="cb3-45">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-46">    plt.tight_layout()</span>
<span id="cb3-47">    plt.show()</span>
<span id="cb3-48"></span>
<span id="cb3-49"></span>
<span id="cb3-50"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_mle_vs_map(ns, k_de_n, alpha, beta, p_true, titulo):</span>
<span id="cb3-51">    mles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> n, k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(ns, k_de_n)])</span>
<span id="cb3-52">    maps <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([map_beta(k, n, alpha, beta) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> n, k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(ns, k_de_n)])</span>
<span id="cb3-53">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>))</span>
<span id="cb3-54">    ax.plot(ns, mles, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MLE"</span>)</span>
<span id="cb3-55">    ax.plot(ns, maps, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"s"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"MAP </span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">(</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">Beta</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">(</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>alpha<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">,</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>beta<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:g}</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">))</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-56">    ax.axhline(p_true, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">p</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> de diseño = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>p_true<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-57">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n"</span>)</span>
<span id="cb3-58">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"estimación de p"</span>)</span>
<span id="cb3-59">    ax.set_title(titulo)</span>
<span id="cb3-60">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-61">    plt.tight_layout()</span>
<span id="cb3-62">    plt.show()</span></code></pre></div></div>
</div>
</section>
</section>
<section id="desarrollo-por-etapas" class="level2">
<h2 class="anchored" data-anchor-id="desarrollo-por-etapas">5. Desarrollo por etapas</h2>
<p>Se fabrica una moneda con <img src="https://latex.codecogs.com/png.latex?p=0.62"> conocida en el laboratorio. Así se ve cuándo el MLE acierta por muestreo y cuándo el prior <strong>corre</strong> el MAP. El caso de clasificación usa conteos de una palabra: el cero del MLE frente al suavizado.</p>
<section id="etapa-1-el-dato-y-el-mle" class="level3">
<h3 class="anchored" data-anchor-id="etapa-1-el-dato-y-el-mle">Etapa 1: El dato y el MLE</h3>
<p><img src="https://latex.codecogs.com/png.latex?n=40"> lanzamientos de una moneda con <img src="https://latex.codecogs.com/png.latex?p=0.62">. <img src="https://latex.codecogs.com/png.latex?k"> es el número de caras. El MLE es <img src="https://latex.codecogs.com/png.latex?k/n">. No usa el 0.62: el ajuste no “ve” el laboratorio.</p>
<div id="c014" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:26.185110Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:26.184958Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:26.188174Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:26.187763Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">p_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.62</span></span>
<span id="cb4-2">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span></span>
<span id="cb4-3">x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.binomial(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, p_true, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb4-4">k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(x.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())</span>
<span id="cb4-5">p_mle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mle_bernoulli(k, n)</span>
<span id="cb4-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"k ="</span>, k, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  n ="</span>, n)</span>
<span id="cb4-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MLE  p̂ = k/n ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_mle, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"   (diseño p = 0.62)"</span>)</span>
<span id="cb4-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"No coincide al milímetro: n es finito."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>k = 21   n = 40
MLE  p̂ = k/n = 0.525    (diseño p = 0.62)
No coincide al milímetro: n es finito.</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%20p_%7B%5Cmathrm%7BMLE%7D%7D"> es un estadístico. El 0.62 es el parámetro. Confundirlos es el error de la <strong>Sesión 9</strong> (inferencia), ahora con una <img src="https://latex.codecogs.com/png.latex?p"> de Bernoulli.</p>
</section>
<section id="etapa-2-la-curva-de-ellp-el-máximo-se-ve" class="level3">
<h3 class="anchored" data-anchor-id="etapa-2-la-curva-de-ellp-el-máximo-se-ve">Etapa 2: La curva de <img src="https://latex.codecogs.com/png.latex?%5Cell(p)"> — el máximo se ve</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cell(p)=k%5Clog%20p+(n-k)%5Clog(1-p).%0A"></p>
<p>El MLE es el <img src="https://latex.codecogs.com/png.latex?p"> donde esa curva alcanza el pico. No hace falta derivar a mano si se evalúa la grilla; la derivada confirma <img src="https://latex.codecogs.com/png.latex?k/n">.</p>
<div id="c017" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:26.189650Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:26.189496Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:26.384841Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:26.384338Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">p_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">181</span>)</span>
<span id="cb6-2">ell <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> logverosimilitud_bernoulli(p_grid, k, n)</span>
<span id="cb6-3">p_max_num <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> p_grid[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmax(ell))]</span>
<span id="cb6-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Máximo numérico de ℓ en la grilla ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_max_num, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb6-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MLE analítico k/n                 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_mle, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb6-6">graficar_loglik(k, n, <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r"Log-verosimilitud Bernoulli: el pico es el MLE"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Máximo numérico de ℓ en la grilla = 0.525
MLE analítico k/n                 = 0.525</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/10-enfoques-frecuentista-bayesiano/index_files/figure-html/cell-5-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> La verosimilitud <strong>no</strong> es una densidad sobre <img src="https://latex.codecogs.com/png.latex?p">: el área bajo <img src="https://latex.codecogs.com/png.latex?%5Cell"> no vale 1 (ni siquiera está en escala de densidad). El pico responde “qué <img src="https://latex.codecogs.com/png.latex?p"> hace más creíble <em>esta</em> <img src="https://latex.codecogs.com/png.latex?x">”, no “cuánta masa creo en cada <img src="https://latex.codecogs.com/png.latex?p">”.</p>
</section>
<section id="etapa-3-prior-plano-el-posterior-se-parece-a-la-verosimilitud" class="level3">
<h3 class="anchored" data-anchor-id="etapa-3-prior-plano-el-posterior-se-parece-a-la-verosimilitud">Etapa 3: Prior plano — el posterior se parece a la verosimilitud</h3>
<p><img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(1,1)"> es uniforme en <img src="https://latex.codecogs.com/png.latex?(0,1)">. El posterior es <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(1+k,%5C,1+n-k)">. El modo coincide con el MLE.</p>
<div id="c020" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:26.386648Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:26.386458Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:26.493953Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:26.493304Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Prior Beta(1,1)  →  posterior Beta("</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> k, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> k, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">")"</span>, sep<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>)</span>
<span id="cb8-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MAP (modo) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(map_beta(k, n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  MLE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_mle, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb8-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Media posterior ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(media_posterior_beta(k, n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (Laplace: (k+1)/(n+2))"</span>)</span>
<span id="cb8-4">graficar_prior_post(k, n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Prior uniforme: el posterior sigue a la verosimilitud"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Prior Beta(1,1)  →  posterior Beta(22,20)
MAP (modo) = 0.525   MLE = 0.525
Media posterior = 0.5238   (Laplace: (k+1)/(n+2))</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/10-enfoques-frecuentista-bayesiano/index_files/figure-html/cell-6-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> Con prior plano, <strong>actualizar es reescalar la verosimilitud</strong> hasta que integre 1. El MAP no aporta otra historia que el MLE. La media posterior sí se corre un poco hacia 0.5: <img src="https://latex.codecogs.com/png.latex?(k+1)/(n+2)"> no es <img src="https://latex.codecogs.com/png.latex?k/n">.</p>
</section>
<section id="etapa-4-el-contraste-prior-fuerte-y-n-chico" class="level3">
<h3 class="anchored" data-anchor-id="etapa-4-el-contraste-prior-fuerte-y-n-chico">Etapa 4: El contraste — prior fuerte y <img src="https://latex.codecogs.com/png.latex?n"> chico</h3>
<p>Prior <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(20,20)">: mucha masa cerca de <img src="https://latex.codecogs.com/png.latex?1/2"> (“creo que la moneda es casi honesta”); pesa como <strong>40 tiradas imaginarias</strong>. El MAP debe <strong>acercarse</strong> a 0.5 respecto del MLE.</p>
<p>Se aplica a la muestra de la etapa 1 (<img src="https://latex.codecogs.com/png.latex?n=40">) y a una muestra <strong>chica</strong> —8 caras en 10 tiradas—, cuyo MLE (0.8) está lejos de 0.5. Ahí se ve el contraste.</p>
<div id="c023" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:26.495902Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:26.495709Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:26.609026Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:26.608470Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">a_f, b_f <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span></span>
<span id="cb10-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Muestra de la etapa 1 (k=21, n=40):"</span>)</span>
<span id="cb10-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  MLE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_mle, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  MAP prior fuerte ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(map_beta(k, n, a_f, b_f), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb10-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  El prior pesa como 40 tiradas: el MAP queda a mitad de camino entre el MLE y 0.5."</span>)</span>
<span id="cb10-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  Casi no se nota porque el MLE ya estaba cerca de 0.5."</span>)</span>
<span id="cb10-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb10-7">k_c, n_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># muestra chica y lejos de 0.5</span></span>
<span id="cb10-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Muestra chica (k=8, n=10):"</span>)</span>
<span id="cb10-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  MLE              ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(mle_bernoulli(k_c, n_c), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb10-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  MAP prior plano  ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(map_beta(k_c, n_c, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb10-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  MAP prior fuerte ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(map_beta(k_c, n_c, a_f, b_f), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (se desplaza hacia 0.5)"</span>)</span>
<span id="cb10-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  Media post fuerte="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(media_posterior_beta(k_c, n_c, a_f, b_f), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb10-13">graficar_prior_post(k_c, n_c, a_f, b_f, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n = 10 y prior Beta(20,20): el posterior se queda cerca del prior"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Muestra de la etapa 1 (k=21, n=40):
  MLE = 0.525   MAP prior fuerte = 0.5128
  El prior pesa como 40 tiradas: el MAP queda a mitad de camino entre el MLE y 0.5.
  Casi no se nota porque el MLE ya estaba cerca de 0.5.

Muestra chica (k=8, n=10):
  MLE              = 0.8
  MAP prior plano  = 0.8
  MAP prior fuerte = 0.5625   (se desplaza hacia 0.5)
  Media post fuerte= 0.56</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/10-enfoques-frecuentista-bayesiano/index_files/figure-html/cell-7-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>El contraste.</strong> Con 8 caras en 10 tiradas, el MLE dice 0.80 y el MAP con prior fuerte, 0.56: diez datos no alcanzan para mover una creencia que vale por cuarenta. El dato no cambió. Cambió la <strong>pregunta</strong>: “qué <img src="https://latex.codecogs.com/png.latex?p"> maximiza <img src="https://latex.codecogs.com/png.latex?x">” frente a “qué <img src="https://latex.codecogs.com/png.latex?p"> es más creíble <em>si yo ya creía en ~0.5</em>”. Ninguna de las dos es trampa. Ocultar el <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(20,20)"> y publicar solo el MAP sí lo es.</p>
<p><strong>Pregunta de análisis.</strong> Si el negocio <em>sabe</em> que las monedas de esta máquina salen cerca de 0.5, ¿publicas el MLE o el MAP? ¿Qué escribes junto al número?</p>
</section>
<section id="etapa-5-n-grande-el-dato-gana" class="level3">
<h3 class="anchored" data-anchor-id="etapa-5-n-grande-el-dato-gana">Etapa 5: <img src="https://latex.codecogs.com/png.latex?n"> grande — el dato gana</h3>
<p>Se simulan muestras crecientes de la misma moneda. Prior fuerte fijo <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(20,20)">. MLE y MAP deben <strong>juntarse</strong>.</p>
<div id="c026" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:26.610825Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:26.610648Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:26.722204Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:26.721713Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">ns <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">160</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">320</span>])</span>
<span id="cb12-2">ks <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb12-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ni <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> ns:</span>
<span id="cb12-4">    ks.append(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(rng.binomial(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, p_true, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(ni)).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()))</span>
<span id="cb12-5">graficar_mle_vs_map(ns, ks, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, p_true, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mismo prior fuerte: al crecer n, MAP ≈ MLE"</span>)</span>
<span id="cb12-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame({</span>
<span id="cb12-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n"</span>: ns,</span>
<span id="cb12-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"k"</span>: ks,</span>
<span id="cb12-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MLE"</span>: [<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(k_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> n_, k_ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(ns, ks)],</span>
<span id="cb12-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MAP"</span>: [<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(map_beta(k_, n_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> n_, k_ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(ns, ks)],</span>
<span id="cb12-11">}).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/10-enfoques-frecuentista-bayesiano/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>  n   k   MLE   MAP
 10   5 0.500 0.500
 20  13 0.650 0.552
 40  25 0.625 0.564
 80  52 0.650 0.602
160 101 0.631 0.606
320 187 0.584 0.575</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> El prior no se “apaga” por decreto: se <strong>diluye</strong> porque <img src="https://latex.codecogs.com/png.latex?%5Calpha+k"> y <img src="https://latex.codecogs.com/png.latex?%5Cbeta+n-k"> los termina mandando <img src="https://latex.codecogs.com/png.latex?n">. Con <img src="https://latex.codecogs.com/png.latex?n=20">, MLE y MAP difieren en casi 0.10 (0.650 frente a 0.552); con <img src="https://latex.codecogs.com/png.latex?n=320">, en menos de 0.01 (0.584 frente a 0.575). Con <img src="https://latex.codecogs.com/png.latex?n=10"> coinciden por azar: salieron 5 caras, justo el centro del prior. A partir de unos cientos de datos, discutir el prior de <img src="https://latex.codecogs.com/png.latex?p"> es, para el punto, pedantería; para las colas del posterior, todavía no.</p>
</section>
<section id="etapa-6-el-95-no-es-el-mismo-objeto" class="level3">
<h3 class="anchored" data-anchor-id="etapa-6-el-95-no-es-el-mismo-objeto">Etapa 6: El 95% no es el mismo objeto</h3>
<p>Misma muestra <img src="https://latex.codecogs.com/png.latex?(n,k)"> de la etapa 1.</p>
<ul>
<li><strong>IC de Wald</strong> (frecuentista, aproximación normal): <img src="https://latex.codecogs.com/png.latex?%5Chat%20p%5Cpm%201.96%5Csqrt%7B%5Chat%20p(1-%5Chat%20p)/n%7D">.</li>
<li><strong>Intervalo creíble central 95%:</strong> cuantiles 2.5% y 97.5% del <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(1+k,1+n-k)">.</li>
</ul>
<p>Se imprimen los dos. No se pide que coincidan.</p>
<div id="c029" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:26.723807Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:26.723645Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:26.728281Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:26.727889Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">se <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sqrt(p_mle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p_mle) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n)</span>
<span id="cb14-2">z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.norm.ppf(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.975</span>)</span>
<span id="cb14-3">ic_lo, ic_hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> p_mle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se, p_mle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se</span>
<span id="cb14-4">cred_lo, cred_hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.beta.ppf([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.025</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.975</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> k, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> k)</span>
<span id="cb14-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Muestra: k ="</span>, k, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" n ="</span>, n, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  MLE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_mle, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb14-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IC Wald 95%          = ["</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(ic_lo, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(ic_hi, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"]  ← cobertura del procedimiento"</span>)</span>
<span id="cb14-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Creíble 95% (plano)  = ["</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(cred_lo, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(cred_hi, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"]  ← masa del posterior"</span>)</span>
<span id="cb14-8">cred2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.beta.ppf([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.025</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.975</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> k, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> k)</span>
<span id="cb14-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Creíble 95% (fuerte) = ["</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(cred2[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(cred2[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"]  ← el prior encoge el rango"</span>)</span>
<span id="cb14-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb14-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"El 95% no se copia de un renglón a otro. Se declara el marco."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Muestra: k = 21  n = 40   MLE = 0.525
IC Wald 95%          = [ 0.37 , 0.68 ]  ← cobertura del procedimiento
Creíble 95% (plano)  = [ 0.374 , 0.671 ]  ← masa del posterior
Creíble 95% (fuerte) = [ 0.404 , 0.621 ]  ← el prior encoge el rango

El 95% no se copia de un renglón a otro. Se declara el marco.</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> El IC no afirma <img src="https://latex.codecogs.com/png.latex?P(%5Ctheta%5Cin%5Ba,b%5D%5Cmid%20x)=0.95">. El creíble, <strong>sí</strong> (bajo el prior). El prior fuerte <strong>estrecha</strong> el creíble: eso no es más dato; es más creencia. Mezclar las dos frases en un informe es el error de la etapa.</p>
<p>Con prior plano y <img src="https://latex.codecogs.com/png.latex?n=40">, el IC de Wald y el creíble casi coinciden en números (<img src="https://latex.codecogs.com/png.latex?%5B0.37,%5C,0.68%5D"> frente a <img src="https://latex.codecogs.com/png.latex?%5B0.374,%5C,0.671%5D">). Lo que cambia no es el rango, es la <strong>frase</strong> que se puede escribir junto a él.</p>
</section>
<section id="etapa-7-evidencia-y-predicción-del-próximo-lanzamiento" class="level3">
<h3 class="anchored" data-anchor-id="etapa-7-evidencia-y-predicción-del-próximo-lanzamiento">Etapa 7: Evidencia y predicción del próximo lanzamiento</h3>
<p>La <strong>predicativa posterior</strong> de una moneda Beta–Bernoulli es la media del posterior:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(X_%7B%5Cmathrm%7Bnuevo%7D%7D=1%5Cmid%20x)=%5Cfrac%7B%5Calpha+k%7D%7B%5Calpha+%5Cbeta+n%7D.%0A"></p>
<p>No es <img src="https://latex.codecogs.com/png.latex?k/n"> salvo prior plano en el límite. La evidencia <img src="https://latex.codecogs.com/png.latex?p(x)"> de una secuencia concreta es el valor de la Beta-binomial; aquí basta la predicción de <em>un</em> ensayo más, que es lo que un modelo usa.</p>
<div id="c032" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:26.730120Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:26.729965Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:26.733349Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:26.732968Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> pred_cara(k, n, alpha, beta):</span>
<span id="cb16-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> k) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> beta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> n)</span>
<span id="cb16-3"></span>
<span id="cb16-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(próxima = cara | x)"</span>)</span>
<span id="cb16-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  con MLE (plug-in)     ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_mle, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← trata p̂ como si fuera p"</span>)</span>
<span id="cb16-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  predicativa, prior 1,1 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pred_cara(k, n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb16-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  predicativa, prior 20,20 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pred_cara(k, n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb16-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb16-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Si k=0, n=8:"</span>)</span>
<span id="cb16-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  MLE plug-in           ="</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← 'la próxima cara es imposible'"</span>)</span>
<span id="cb16-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  predicativa Laplace   ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pred_cara(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← nunca 0"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>P(próxima = cara | x)
  con MLE (plug-in)     = 0.525   ← trata p̂ como si fuera p
  predicativa, prior 1,1 = 0.5238
  predicativa, prior 20,20 = 0.5125

Si k=0, n=8:
  MLE plug-in           = 0.0   ← 'la próxima cara es imposible'
  predicativa Laplace   = 0.1   ← nunca 0</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> El MLE <em>enchufado</em> a <img src="https://latex.codecogs.com/png.latex?P(X_%7B%5Cmathrm%7Bnuevo%7D%7D%5Cmid%5Chat%20p)"> ignora que <img src="https://latex.codecogs.com/png.latex?%5Chat%20p"> tiembla. La predicativa <strong>promedia</strong> esa incertidumbre. Con <img src="https://latex.codecogs.com/png.latex?k=0"> la diferencia no es cosmética: un 0 y un <img src="https://latex.codecogs.com/png.latex?1/10"> deciden si un clasificador sobrevive a un token nuevo.</p>
</section>
<section id="etapa-8-clasificación-el-mle-pone-un-0-y-se-rompe" class="level3">
<h3 class="anchored" data-anchor-id="etapa-8-clasificación-el-mle-pone-un-0-y-se-rompe">Etapa 8: Clasificación — el MLE pone un 0 y se rompe</h3>
<p>Filtro de una palabra. Clase <img src="https://latex.codecogs.com/png.latex?y=1"> = <em>spam</em>. En entrenamiento, la palabra <strong>“premio”</strong> aparece 8 veces en 40 <em>spam</em> y 0 veces en 80 <em>ham</em>. Un correo de prueba <strong>trae</strong> “premio”.</p>
<p>Naive Bayes (una palabra):</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(y%5Cmid%20w)%5Cpropto%20P(w%5Cmid%20y)%5C,P(y).%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?P(w%5Cmid%20y=0)_%7B%5Cmathrm%7BMLE%7D%7D=0/80=0">. El <em>ham</em> queda anulado: el correo <em>tiene</em> que ser spam, aunque el prior de spam sea bajo. El MAP / Laplace usa <img src="https://latex.codecogs.com/png.latex?(c+1)/(n+2)">.</p>
<div id="c035" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:26.734737Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:26.734594Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:26.738399Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:26.738032Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Conteos de diseño (una palabra)</span></span>
<span id="cb18-2">c_spam, n_spam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span></span>
<span id="cb18-3">c_ham, n_ham <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span></span>
<span id="cb18-4">prior_spam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span></span>
<span id="cb18-5">prior_ham <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.70</span></span>
<span id="cb18-6"></span>
<span id="cb18-7">p_w_spam_mle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> c_spam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n_spam</span>
<span id="cb18-8">p_w_ham_mle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> c_ham <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n_ham</span>
<span id="cb18-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Laplace = media posterior Beta(1,1)</span></span>
<span id="cb18-10">p_w_spam_map <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> media_posterior_beta(c_spam, n_spam, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb18-11">p_w_ham_map <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> media_posterior_beta(c_ham, n_ham, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb18-12"></span>
<span id="cb18-13"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> posterior_spam(p_w_spam, p_w_ham):</span>
<span id="cb18-14">    num <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> p_w_spam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> prior_spam</span>
<span id="cb18-15">    den <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> num <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> p_w_ham <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> prior_ham</span>
<span id="cb18-16">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> num <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> den <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> den <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> np.nan</span>
<span id="cb18-17"></span>
<span id="cb18-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(palabra | spam)  MLE ="</span>, p_w_spam_mle, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  Laplace ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_w_spam_map, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb18-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(palabra | ham)   MLE ="</span>, p_w_ham_mle, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  Laplace ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(p_w_ham_map, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb18-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb18-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(spam | palabra)  MLE     ="</span>, posterior_spam(p_w_spam_mle, p_w_ham_mle),</span>
<span id="cb18-22">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← 1.0 forzado: ham quedó en 0"</span>)</span>
<span id="cb18-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(spam | palabra)  Laplace ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(posterior_spam(p_w_spam_map, p_w_ham_map), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb18-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb18-25"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"El 1.0 del MLE no es certeza: es un cero en el denominador del ham."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>P(palabra | spam)  MLE = 0.2   Laplace = 0.2143
P(palabra | ham)   MLE = 0.0   Laplace = 0.0122

P(spam | palabra)  MLE     = 1.0   ← 1.0 forzado: ham quedó en 0
P(spam | palabra)  Laplace = 0.8828

El 1.0 del MLE no es certeza: es un cero en el denominador del ham.</code></pre>
</div>
</div>
<p><strong>El contraste en producto.</strong> El MLE “ganó” una certeza falsa. El Laplace <strong>no inventa</strong> que la palabra sea frecuente en ham: pone <img src="https://latex.codecogs.com/png.latex?1/82">. Eso basta para que el prior 0.30 y la verosimilitud en spam (alta) produzcan un posterior alto <em>pero no 1</em>. El suavizado es el prior <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(1,1)"> escrito como <code>+1</code> en el código.</p>
<p><strong>Veredicto parcial.</strong> En texto, el MLE crudo de <img src="https://latex.codecogs.com/png.latex?P(w%5Cmid%20c)"> <strong>no es aceptable</strong>. El MAP/Laplace es el mínimo oficio.</p>
</section>
<section id="etapa-9-simular-el-filtro-los-correos-que-traen-la-palabra" class="level3">
<h3 class="anchored" data-anchor-id="etapa-9-simular-el-filtro-los-correos-que-traen-la-palabra">Etapa 9: Simular el filtro — los correos que traen la palabra</h3>
<p>Se generan 400 correos con las tasas <strong>verdaderas</strong> de diseño: “premio” aparece en el 20% del spam y en el 1% del ham (el 0 del entrenamiento fue mala suerte de muestra, con <img src="https://latex.codecogs.com/png.latex?n"> chico). Entre los correos que traen la palabra se compara la probabilidad que <strong>afirma</strong> cada regla con la frecuencia <strong>real</strong> de spam, y la decisión al umbral habitual <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5">.</p>
<div id="c038" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T10:19:26.739841Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T10:19:26.739693Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T10:19:26.743966Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T10:19:26.743588Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">n_mail <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span></span>
<span id="cb20-2">es_spam <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.random(n_mail) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span></span>
<span id="cb20-3">tiene <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(es_spam, rng.random(n_mail) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.20</span>, rng.random(n_mail) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>)</span>
<span id="cb20-4">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> es_spam[tiene].astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># solo los correos que traen la palabra</span></span>
<span id="cb20-5">post_l <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> posterior_spam(p_w_spam_map, p_w_ham_map)</span>
<span id="cb20-6"></span>
<span id="cb20-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Correos con la palabra:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  spam:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(y.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ham:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()))</span>
<span id="cb20-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Frecuencia real de spam entre ellos  ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb20-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MLE afirma     P(spam | palabra) = 1.0   ← declara imposibles a los ham"</span>)</span>
<span id="cb20-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Laplace afirma P(spam | palabra) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(post_l, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb20-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb20-12">tau <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span></span>
<span id="cb20-13">yhat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.full_like(y, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(post_l <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> tau))   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a τ = 0.5, MLE (1.0) y Laplace (0.883) alertan igual</span></span>
<span id="cb20-14">vp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(((y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (yhat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())</span>
<span id="cb20-15">fp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(((y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (yhat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>())</span>
<span id="cb20-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"A τ = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>tau<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, las dos reglas alertan en los </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> correos: VP = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>vp<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, FP = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>fp<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb20-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La decisión es la misma; lo que difiere es la probabilidad que se reporta."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Correos con la palabra: 30   spam: 28   ham: 2
Frecuencia real de spam entre ellos  = 0.933
MLE afirma     P(spam | palabra) = 1.0   ← declara imposibles a los ham
Laplace afirma P(spam | palabra) = 0.883

A τ = 0.5, las dos reglas alertan en los 30 correos: VP = 28, FP = 2
La decisión es la misma; lo que difiere es la probabilidad que se reporta.</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> Entre los 30 correos con la palabra, 28 eran spam (93%). El MLE afirma certeza (1.0) y declara <strong>imposibles</strong> a los 2 ham que sí aparecieron; Laplace afirma 0.88, una cifra discutible pero <strong>posible</strong>. A <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5"> las dos reglas deciden igual, así que la diferencia no se ve en la matriz de confusión. Se ve cuando la probabilidad se usa como probabilidad: al combinar varias palabras (un solo 0 anula todo el producto), al fijar el umbral por costos o al medir calibración. Una métrica de probabilidad como la pérdida logarítmica castiga con un error <strong>infinito</strong> a quien dijo 1.0 y se equivocó.</p>
<p><strong>Qué no se concluye.</strong> Que Laplace sea el mejor prior. Es el prior mínimo que impide el colapso. Un <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(2,8)"> en ham sería otra creencia, otra probabilidad.</p>
</section>
<section id="caso-aplicado-reportar-un-mle-o-un-map" class="level3">
<h3 class="anchored" data-anchor-id="caso-aplicado-reportar-un-mle-o-un-map">Caso aplicado: reportar un MLE o un MAP</h3>
<p>Plantilla:</p>
<ol type="1">
<li><strong>Parámetro y modelo.</strong> Qué es <img src="https://latex.codecogs.com/png.latex?%5Ctheta">, qué <img src="https://latex.codecogs.com/png.latex?p(x%5Cmid%5Ctheta)">.</li>
<li><strong>Marco.</strong> Frecuentista (MLE + IC) o bayesiano (prior + posterior / MAP).</li>
<li><strong>Prior, si existe.</strong> Familia, parámetros, justificación (plano, regularización, dominio).</li>
<li><strong>Números.</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta">, <img src="https://latex.codecogs.com/png.latex?n">, intervalo (y de <em>qué</em> tipo).</li>
<li><strong>Predicción.</strong> Plug-in vs predicativa; ¿hay ceros?</li>
<li><strong>Decisión y límite.</strong> Para qué uso sirve; qué pasa si <img src="https://latex.codecogs.com/png.latex?n"> cambia.</li>
</ol>
<p><strong>Los seis pasos, aplicados al filtro (etapas 8–9)</strong></p>
<ol type="1">
<li><strong>Parámetro.</strong> <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7B%E2%80%9Cpremio%E2%80%9D%7D%5Cmid%20%5Ctext%7Bspam%7D)"> y <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7B%E2%80%9Cpremio%E2%80%9D%7D%5Cmid%20%5Ctext%7Bham%7D)">, Bernoulli / multinomial de una palabra.</li>
<li><strong>Marco.</strong> Se comparan MLE y media posterior <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(1,1)"> (Laplace).</li>
<li><strong>Prior.</strong> Plano en <img src="https://latex.codecogs.com/png.latex?p">; equivale a un conteo ficticio <img src="https://latex.codecogs.com/png.latex?(1,1)">. Justificación: evitar probabilidad 0, no un estudio de dominio.</li>
<li><strong>Números.</strong> MLE ham <img src="https://latex.codecogs.com/png.latex?=0">; Laplace ham <img src="https://latex.codecogs.com/png.latex?=(0+1)/(80+2)">. Posterior <img src="https://latex.codecogs.com/png.latex?P(%5Ctext%7Bspam%7D%5Cmid%5Ctext%7Bpalabra%7D)">: 1.0 (MLE) frente a 0.883 (Laplace).</li>
<li><strong>Predicción.</strong> El MLE no puede predecir <em>ham</em> si la palabra aparece. Laplace sí.</li>
<li><strong>Decisión.</strong> <em>Rechazar el MLE crudo para este clasificador.</em> Aceptar Laplace (o un prior mejor) como suelo. Limitación: una palabra, prior no elicitado con negocio, <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5"> por costumbre.</li>
</ol>
<blockquote class="blockquote">
<p>En un filtro con una palabra nunca vista en ham, el MLE asigna <img src="https://latex.codecogs.com/png.latex?P(w%5Cmid%5Cmathrm%7Bham%7D)=0"> y fuerza posterior 1. Con suavizado de Laplace el posterior es 0.883 y el modelo deja de colapsar. Se reporta el prior <img src="https://latex.codecogs.com/png.latex?(1,1)">, <img src="https://latex.codecogs.com/png.latex?n_%7B%5Cmathrm%7Bham%7D%7D=80"> y que el 1.0 del MLE no es certeza, es un cero. Limitación: una <em>feature</em>, sin calibración de <img src="https://latex.codecogs.com/png.latex?%5Ctau">.</p>
</blockquote>
</section>
<section id="errores-que-conviene-nombrar" class="level3">
<h3 class="anchored" data-anchor-id="errores-que-conviene-nombrar">Errores que conviene nombrar</h3>
<ol type="1">
<li><strong>Tratar <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%20L(%5Ctheta;x)"> como <img src="https://latex.codecogs.com/png.latex?p(%5Ctheta%5Cmid%20x)">.</strong> La primera no integra a 1 en <img src="https://latex.codecogs.com/png.latex?%5Ctheta">.</li>
<li><strong>Publicar un MAP sin el prior.</strong> Es un MLE disfrazado o una creencia oculta.</li>
<li><strong>Leer el IC como “<img src="https://latex.codecogs.com/png.latex?%5Ctheta"> está aquí con probabilidad 0.95”.</strong></li>
<li><strong>Leer el creíble como cobertura de un procedimiento</strong> que se repite.</li>
<li><strong>MLE con <img src="https://latex.codecogs.com/png.latex?k=0"> como “imposible”.</strong> En texto, tumba el clasificador.</li>
<li><strong>“Bayesiano = más moderno.”</strong> Es otra pregunta, no una medalla.</li>
<li><strong>Reusar el 16.7% de la prueba médica como si fuera este tema.</strong> Ahí se invierte un condicional; aquí se elige un marco para <img src="https://latex.codecogs.com/png.latex?%5Ctheta">.</li>
</ol>
</section>
<section id="idea-clave" class="level3">
<h3 class="anchored" data-anchor-id="idea-clave">Idea clave</h3>
<p><strong>El MLE responde “qué <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> hace más creíble <img src="https://latex.codecogs.com/png.latex?x">”. El posterior responde “qué creo de <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> después de <img src="https://latex.codecogs.com/png.latex?x">”.</strong> El MAP está en medio: un punto del posterior, un MLE con prior. El oficio es <strong>nombrar</strong> cuál se publica y, si hay prior, escribirlo.</p>
</section>
<section id="síntesis" class="level3">
<h3 class="anchored" data-anchor-id="síntesis">Síntesis</h3>
<p>Se escribió <img src="https://latex.codecogs.com/png.latex?%5Cell(p)"> y se vio el pico (MLE). Un prior plano no cambió el modo; uno fuerte sí, y <img src="https://latex.codecogs.com/png.latex?n"> grande lo diluyó. El 95% de Wald y el 95% creíble no se copiaron. La predicativa evitó el 0 que el plug-in fabrica. En el filtro, el MLE impuso spam; Laplace dejó un posterior usable. El objeto que queda es <img src="https://latex.codecogs.com/png.latex?p(%5Ctheta%5Cmid%20x)"> <em>o</em> <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta_%7B%5Cmathrm%7BMLE%7D%7D">, declarado, no un <img src="https://latex.codecogs.com/png.latex?%5Chat%20p"> anónimo.</p>
</section>
</section>
<section id="guía-rápida-qué-marco-usar" class="level2">
<h2 class="anchored" data-anchor-id="guía-rápida-qué-marco-usar">6. Guía rápida: ¿qué marco usar?</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Situación</th>
<th>Qué usar</th>
<th>Por qué</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Solo la muestra, un punto</td>
<td>MLE</td>
<td>Maximiza <img src="https://latex.codecogs.com/png.latex?p(x%5Cmid%5Ctheta)"></td>
</tr>
<tr class="even">
<td>Hay creencia o hay que regularizar</td>
<td>MAP / posterior</td>
<td>Suma <img src="https://latex.codecogs.com/png.latex?%5Clog%20p(%5Ctheta)"></td>
</tr>
<tr class="odd">
<td>Evitar <img src="https://latex.codecogs.com/png.latex?P=0"> en conteos</td>
<td>Laplace / <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BBeta%7D(1,1)"></td>
<td>Media posterior, no un 0</td>
</tr>
<tr class="even">
<td>Rango “el procedimiento cubre”</td>
<td>IC</td>
<td>Frecuentista</td>
</tr>
<tr class="odd">
<td>Rango “creo que <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> está aquí”</td>
<td>Intervalo creíble</td>
<td>Posterior</td>
</tr>
<tr class="even">
<td>Predecir el próximo <img src="https://latex.codecogs.com/png.latex?x"> con <img src="https://latex.codecogs.com/png.latex?n"> chico</td>
<td>Predicativa</td>
<td>Promedia <img src="https://latex.codecogs.com/png.latex?%5Ctheta">, no enchufa <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta"></td>
</tr>
<tr class="odd">
<td><img src="https://latex.codecogs.com/png.latex?n"> enorme, prior razonable</td>
<td>MLE <img src="https://latex.codecogs.com/png.latex?%5Capprox"> MAP</td>
<td>El dato manda</td>
</tr>
</tbody>
</table>
<p><strong>Regla de comunicación:</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta">, <img src="https://latex.codecogs.com/png.latex?n">, si es MLE o MAP, el prior si existe, y el tipo de intervalo.</p>
</section>
<section id="guía-práctica-para-reportar-mle-o-map" class="level2">
<h2 class="anchored" data-anchor-id="guía-práctica-para-reportar-mle-o-map">7. Guía práctica para reportar MLE o MAP</h2>
<section id="paso-1-theta-y-pxmidtheta" class="level3">
<h3 class="anchored" data-anchor-id="paso-1-theta-y-pxmidtheta">Paso 1: <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> y <img src="https://latex.codecogs.com/png.latex?p(x%5Cmid%5Ctheta)"></h3>
<p>Qué se estima y con qué modelo.</p>
</section>
<section id="paso-2-marco-y-prior" class="level3">
<h3 class="anchored" data-anchor-id="paso-2-marco-y-prior">Paso 2: marco y prior</h3>
<p>MLE solo, o prior (familia, parámetros, por qué).</p>
</section>
<section id="paso-3-punto-n-intervalo" class="level3">
<h3 class="anchored" data-anchor-id="paso-3-punto-n-intervalo">Paso 3: punto, <img src="https://latex.codecogs.com/png.latex?n">, intervalo</h3>
<p>Declarar si el rango es IC o creíble.</p>
</section>
<section id="paso-4-redactar" class="level3">
<h3 class="anchored" data-anchor-id="paso-4-redactar">Paso 4: redactar</h3>
<blockquote class="blockquote">
<p>“Se modeló <code>[X]</code> como <code>[Bernoulli/…]</code>. <img src="https://latex.codecogs.com/png.latex?n="><code>[...]</code>. <strong>MLE</strong> = <code>[…]</code>. <strong>MAP</strong> con prior <code>[Beta(α,β) / …]</code> = <code>[…]</code>. Intervalo <code>[IC Wald / creíble 95%]</code> = <code>[…]</code>. Para predecir se usó <code>[plug-in / predicativa]</code>. <strong>Veredicto:</strong> <code>[basta el MLE / hace falta prior porque…]</code>. Limitación: <code>[n chico / prior no elicitado]</code>.”</p>
</blockquote>
<p>El filtro de la etapa 8 ya llenó esta plantilla.</p>
</section>
</section>
<section id="puente-hacia-las-siguientes-sesiones" class="level2">
<h2 class="anchored" data-anchor-id="puente-hacia-las-siguientes-sesiones">8. Puente hacia las siguientes sesiones</h2>
<p>La recta de mínimos cuadrados es el MLE de un ruido gaussiano. Un clasificador que multiplica <img src="https://latex.codecogs.com/png.latex?P(x%5Cmid%20y)"> hereda el 0 del MLE o el <code>+1</code> del MAP. Las métricas (precisión, recall) y la validación (no elegir el prior <em>en</em> la prueba) se aplican igual: el marco de <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> no sustituye el conjunto no visto.</p>
</section>
<section id="cierre" class="level2">
<h2 class="anchored" data-anchor-id="cierre">9. Cierre</h2>
<p>Este notebook deja los dos marcos sobre la misma muestra:</p>
<ul>
<li>verosimilitud frente a posterior,</li>
<li>MLE y su curva <img src="https://latex.codecogs.com/png.latex?%5Cell(%5Ctheta)">,</li>
<li>prior, evidencia y actualización Beta–Bernoulli,</li>
<li>MAP como MLE penalizado,</li>
<li>IC frente a intervalo creíble,</li>
<li>predicativa frente a plug-in,</li>
<li>un clasificador que el MLE rompe y el Laplace sostiene.</li>
</ul>
<p><strong>Resultado esperado:</strong> el estudiante escribe <img src="https://latex.codecogs.com/png.latex?%5Chat%20p_%7B%5Cmathrm%7BMLE%7D%7D"> o <img src="https://latex.codecogs.com/png.latex?%5Chat%20p_%7B%5Cmathrm%7BMAP%7D%7D"> con el prior a la vista, no publica un 0 de conteo como certeza, y no llama “95%” a dos objetos distintos.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>bayesiano</category>
  <category>mle</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/basico/10-enfoques-frecuentista-bayesiano/</guid>
  <pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Estadística para IA — 11. Regresión lineal</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/basico/11-regresion-lineal/</link>
  <description><![CDATA[ 




<section id="sesión-11-regresión-lineal" class="level1">
<h1>Sesión 11 — Regresión Lineal</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado es Científico de Datos, Arquitecto de IA, Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), consultor y docente universitario, trabaja en la intersección entre Data Science, Inteligencia Artificial, Big Data e IoT, transformando problemas reales en soluciones aplicadas.</p>
<p>De la teoría a la práctica, un problema a la vez.</p>
</section>
<section id="una-recta-no-es-la-nube" class="level2">
<h2 class="anchored" data-anchor-id="una-recta-no-es-la-nube">Una recta no es la nube</h2>
<p>Predecir un número —latencia, precio, puntuación— a partir de otro es la tarea más corta del modelado: <strong>una recta</strong>. El modelo lineal simple escribe esa recta, la ajusta por <strong>mínimos cuadrados</strong> y resume el error con el <strong>MSE</strong>. El coeficiente que sale no es un hechizo: es <em>cuánto cambia <img src="https://latex.codecogs.com/png.latex?y"> por cada unidad de <img src="https://latex.codecogs.com/png.latex?x"></em>, dentro del modelo y del rango observado.</p>
<p>Este notebook construye el modelo, sus <strong>supuestos</strong>, el ajuste <strong>a mano y con scikit-learn</strong>, el <strong>MSE</strong> y la lectura de <img src="https://latex.codecogs.com/png.latex?%5Cbeta_0"> y <img src="https://latex.codecogs.com/png.latex?%5Cbeta_1">. El contraste que importa es clásico y todavía se ignora: <em>cuatro nubes distintas pueden compartir la misma pendiente y el mismo error</em> (cuartetos de Anscombe). Sin el diagrama y sin los residuos, el coeficiente miente con educación.</p>
<p>Contexto: una nube diseñada <img src="https://latex.codecogs.com/png.latex?y=%5Cbeta_0+%5Cbeta_1%20x+%5Cvarepsilon"> y un caso de <strong>latencia (ms) frente a tamaño de lote</strong>.</p>
<p>Electiva I — Estadística Aplicada a la Inteligencia Artificial · Módulo 4 · Sesión 11</p>
</section>
<section id="objetivos" class="level2">
<h2 class="anchored" data-anchor-id="objetivos">Objetivos</h2>
<ul>
<li>Escribir el <strong>modelo lineal simple</strong> <img src="https://latex.codecogs.com/png.latex?y=%5Cbeta_0+%5Cbeta_1%20x+%5Cvarepsilon"> y nombrar cada pieza.</li>
<li>Enunciar los <strong>supuestos</strong> (linealidad, independencia, varianza constante; normalidad para inferir).</li>
<li>Ajustar por <strong>mínimos cuadrados</strong> a mano y reproducir el resultado con <code>LinearRegression</code>.</li>
<li>Calcular el <strong>MSE</strong> (y distinguirlo de <img src="https://latex.codecogs.com/png.latex?s%5E2"> residual).</li>
<li>Interpretar <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0"> y <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> en unidades del problema, sin convertirlos en causa.</li>
<li>Diagnosticar con <strong>residuos</strong> y no fiarse de una recta que comparte números con otra nube.</li>
</ul>
<blockquote class="blockquote">
<p>Nota: se recomienda ejecutar las celdas en orden. Las fórmulas usan LaTeX; si no se ven renderizadas, abre el notebook en Jupyter o Colab.</p>
</blockquote>
</section>
<section id="el-modelo-y-la-recta" class="level2">
<h2 class="anchored" data-anchor-id="el-modelo-y-la-recta">1. El modelo y la recta</h2>
<section id="modelo-lineal-simple" class="level3">
<h3 class="anchored" data-anchor-id="modelo-lineal-simple">1.1 Modelo lineal simple</h3>
<p>Se observa un par <img src="https://latex.codecogs.com/png.latex?(x_i,%5C,y_i)">. El modelo afirma</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ay_i=%5Cbeta_0+%5Cbeta_1%20x_i+%5Cvarepsilon_i,%5Cqquad%20i=1,%5Cldots,n.%0A"></p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?%5Cbeta_0"> (<strong>intercepto</strong>): valor esperado de <img src="https://latex.codecogs.com/png.latex?y"> cuando <img src="https://latex.codecogs.com/png.latex?x=0">, si <img src="https://latex.codecogs.com/png.latex?x=0"> tiene sentido en el problema.</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Cbeta_1"> (<strong>pendiente</strong>): cambio esperado de <img src="https://latex.codecogs.com/png.latex?y"> por <strong>una unidad</strong> de <img src="https://latex.codecogs.com/png.latex?x">.</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Cvarepsilon_i"> (<strong>error</strong>): lo que el modelo no explica. No es un fallo de Python; es la parte no lineal, no medida o aleatoria.</li>
</ul>
<p>La <strong>predicción</strong> en un <img src="https://latex.codecogs.com/png.latex?x"> es <img src="https://latex.codecogs.com/png.latex?%5Chat%20y=%5Chat%5Cbeta_0+%5Chat%5Cbeta_1%20x">. El <strong>residuo</strong> es <img src="https://latex.codecogs.com/png.latex?e_i=y_i-%5Chat%20y_i">: lo que quedó sin explicar <em>en esta muestra</em>, después de ajustar.</p>
<p><img src="https://latex.codecogs.com/png.latex?x"> es la variable explicativa (<em>feature</em>). <img src="https://latex.codecogs.com/png.latex?y"> es la respuesta (<em>target</em>). El modelo es <strong>simple</strong> porque hay una sola <img src="https://latex.codecogs.com/png.latex?x">. Varias <img src="https://latex.codecogs.com/png.latex?x"> son regresión múltiple: misma idea, otra geometría.</p>
</section>
<section id="qué-se-minimiza-mínimos-cuadrados" class="level3">
<h3 class="anchored" data-anchor-id="qué-se-minimiza-mínimos-cuadrados">1.2 Qué se minimiza: mínimos cuadrados</h3>
<p>Los <strong>mínimos cuadrados ordinarios</strong> (OLS) eligen <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0,%5Chat%5Cbeta_1"> que minimizan la suma de residuos al cuadrado:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AS(%5Cbeta_0,%5Cbeta_1)=%5Csum_%7Bi=1%7D%5E%7Bn%7D(y_i-%5Cbeta_0-%5Cbeta_1%20x_i)%5E2.%0A"></p>
<p>La solución (si <img src="https://latex.codecogs.com/png.latex?x"> no es constante) es</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%5Cbeta_1=%5Cfrac%7B%5Csum_i%20(x_i-%5Cbar%20x)(y_i-%5Cbar%20y)%7D%7B%5Csum_i%20(x_i-%5Cbar%20x)%5E2%7D,%5Cqquad%0A%5Chat%5Cbeta_0=%5Cbar%20y-%5Chat%5Cbeta_1%5Cbar%20x.%0A"></p>
<p>La recta <strong>pasa por el punto</strong> <img src="https://latex.codecogs.com/png.latex?(%5Cbar%20x,%5Cbar%20y)">. Elevar al cuadrado penaliza más los residuos grandes: un solo punto extremo puede <strong>inclinar</strong> la pendiente. Eso no es un defecto oculto; es la función objetivo.</p>
<p>En forma matricial, con <img src="https://latex.codecogs.com/png.latex?X"> la matriz <img src="https://latex.codecogs.com/png.latex?n%5Ctimes%202"> de unos y la columna <img src="https://latex.codecogs.com/png.latex?x">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7B%5Cboldsymbol%5Cbeta%7D=(X%5E%5Ctop%20X)%5E%7B-1%7DX%5E%5Ctop%20%5Cmathbf%7By%7D.%0A"></p>
<p>Es la misma solución.</p>
</section>
<section id="mse" class="level3">
<h3 class="anchored" data-anchor-id="mse">1.3 MSE</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7BMSE%7D=%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi=1%7D%5E%7Bn%7D(y_i-%5Chat%20y_i)%5E2.%0A"></p>
<p>Está en <strong>unidades de <img src="https://latex.codecogs.com/png.latex?y"> al cuadrado</strong>. Su raíz (RMSE) vuelve a las unidades de <img src="https://latex.codecogs.com/png.latex?y"> y se compara con el rango de la respuesta. scikit-learn reporta el MSE con divisor <img src="https://latex.codecogs.com/png.latex?n">.</p>
<p>La varianza residual que usa la inferencia divide por <img src="https://latex.codecogs.com/png.latex?n-2"> (se perdieron dos grados de libertad: intercepto y pendiente):</p>
<p><img src="https://latex.codecogs.com/png.latex?%0As%5E2=%5Cfrac%7B1%7D%7Bn-2%7D%5Csum_i%20e_i%5E2.%0A"></p>
<p>No son el mismo número. El MSE mide ajuste; <img src="https://latex.codecogs.com/png.latex?s%5E2"> estima <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BVar%7D(%5Cvarepsilon)"> bajo el modelo.</p>
</section>
<section id="supuestos-lo-que-la-recta-pide" class="level3">
<h3 class="anchored" data-anchor-id="supuestos-lo-que-la-recta-pide">1.4 Supuestos (lo que la recta pide)</h3>
<p>OLS <strong>siempre</strong> produce una recta. Los supuestos dicen cuándo esa recta es una descripción honesta y cuándo un intervalo o una prueba sobre <img src="https://latex.codecogs.com/png.latex?%5Cbeta_1"> es legible.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Supuesto</th>
<th>En palabras</th>
<th>Cómo se mira</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Linealidad</strong></td>
<td><img src="https://latex.codecogs.com/png.latex?E%5By%5Cmid%20x%5D=%5Cbeta_0+%5Cbeta_1%20x"></td>
<td>Residuos contra <img src="https://latex.codecogs.com/png.latex?%5Chat%20y"> o contra <img src="https://latex.codecogs.com/png.latex?x">: no debe quedar una curva</td>
</tr>
<tr class="even">
<td><strong>Independencia</strong></td>
<td>Los <img src="https://latex.codecogs.com/png.latex?%5Cvarepsilon_i"> no se arrastran (tiempo, grupos)</td>
<td>Residuos contra el orden; el modelo simple no “sabe” de series</td>
</tr>
<tr class="odd">
<td><strong>Varianza constante</strong> (homocedasticidad)</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BVar%7D(%5Cvarepsilon%5Cmid%20x)"> no crece ni se estrecha con <img src="https://latex.codecogs.com/png.latex?x"></td>
<td>Residuos contra <img src="https://latex.codecogs.com/png.latex?%5Chat%20y">: la nube no debe abrirse en embudo</td>
</tr>
<tr class="even">
<td><strong>Normalidad de <img src="https://latex.codecogs.com/png.latex?%5Cvarepsilon"></strong></td>
<td>Necesaria para <em>inferir</em> con <img src="https://latex.codecogs.com/png.latex?t"> sobre <img src="https://latex.codecogs.com/png.latex?%5Cbeta">; no para obtener <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"></td>
<td>Histograma o gráfico Q-Q de residuos</td>
</tr>
</tbody>
</table>
<p><strong>Homocedasticidad</strong> = varianza de los residuos más o menos igual a lo largo de <img src="https://latex.codecogs.com/png.latex?x">. Lo contrario es <strong>heterocedasticidad</strong>: el error es chico a la izquierda y ancho a la derecha (o al revés).</p>
<p>Gauss–Markov: si la media es lineal, los errores son independientes y de varianza constante, OLS es el mejor estimador <strong>lineal e insesgado</strong>. La normalidad no entra en esa frase.</p>
</section>
<section id="interpretar-coeficientes" class="level3">
<h3 class="anchored" data-anchor-id="interpretar-coeficientes">1.5 Interpretar coeficientes</h3>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1=1.8"> con <img src="https://latex.codecogs.com/png.latex?x"> = tamaño de lote y <img src="https://latex.codecogs.com/png.latex?y"> = latencia en ms se lee: <em>en esta muestra, y bajo este modelo, un lote una unidad mayor se asocia a <img src="https://latex.codecogs.com/png.latex?1.8"> ms más de latencia media</em>.</p>
<p>No se lee: <em>si yo aumento el lote, la latencia subirá <img src="https://latex.codecogs.com/png.latex?1.8"> ms</em>. Eso es una afirmación causal. La recta no la otorga.</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0"> es la latencia predicha en lote <img src="https://latex.codecogs.com/png.latex?0">. Si lote <img src="https://latex.codecogs.com/png.latex?0"> no existe, el intercepto es un ancla algebraica, no un experimento.</p>
</section>
<section id="el-contraste-que-importa" class="level3">
<h3 class="anchored" data-anchor-id="el-contraste-que-importa">1.6 El contraste que importa</h3>
<p>Pendiente, intercepto y MSE son <strong>resúmenes</strong>. El cuarteto de Anscombe (1973) construye cuatro nubes con los mismos resúmenes y cuatro geometrías: recta, curva, recta más un atípico, y un <img src="https://latex.codecogs.com/png.latex?x"> constante salvo un punto que <strong>apalanca</strong> la pendiente (un <img src="https://latex.codecogs.com/png.latex?x"> muy lejos de <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x">).</p>
<table class="caption-top table">
<colgroup>
<col style="width: 50%">
<col style="width: 50%">
</colgroup>
<thead>
<tr class="header">
<th>Pregunta</th>
<th>Herramienta</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>¿Qué recta resume <img src="https://latex.codecogs.com/png.latex?y"> frente a <img src="https://latex.codecogs.com/png.latex?x">?</td>
<td>Modelo lineal simple</td>
</tr>
<tr class="even">
<td>¿Cómo se eligen <img src="https://latex.codecogs.com/png.latex?%5Cbeta_0,%5Cbeta_1">?</td>
<td>Mínimos cuadrados</td>
</tr>
<tr class="odd">
<td>¿Cuánto error queda, en <img src="https://latex.codecogs.com/png.latex?y%5E2">?</td>
<td>MSE</td>
</tr>
<tr class="even">
<td>¿La recta es la forma de la nube?</td>
<td>Residuos + diagrama</td>
</tr>
<tr class="odd">
<td>¿Cuánto cambia <img src="https://latex.codecogs.com/png.latex?y"> por unidad de <img src="https://latex.codecogs.com/png.latex?x">?</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> (asociación, no causa)</td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="por-qué-importa-en-ia-y-machine-learning" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-importa-en-ia-y-machine-learning">2. Por qué importa en IA y Machine Learning</h2>
<p>Casi todo modelo paramétrico que se enseña después <strong>empieza</strong> aquí: una predicción que es combinación lineal de <em>features</em>. La logística es una recta en el logit; una red sin activación es una recta en muchas dimensiones.</p>
<ul>
<li><strong>Baseline.</strong> Antes de un modelo complejo, la recta (o un lineal con las <img src="https://latex.codecogs.com/png.latex?x"> crudas) fija el MSE a vencer.</li>
<li><strong>Interpretación.</strong> En producto se pregunta “¿cuánto mueve <img src="https://latex.codecogs.com/png.latex?y"> esta <em>feature</em>?”. <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> es la respuesta más corta —y la más fácil de sobreleer.</li>
<li><strong>Diagnóstico.</strong> Un residuo en U delata que el lineal es el modelo <em>equivocado</em>, no que “falta un hiperparámetro”.</li>
<li><strong>MSE.</strong> Es la función de pérdida <img src="https://latex.codecogs.com/png.latex?L_2">. Entenderla en una recta es entender qué minimizan muchos ajustes.</li>
</ul>
<p><strong>Idea central:</strong> el coeficiente resume una recta; los residuos dicen si esa recta era la pregunta correcta.</p>
</section>
<section id="flujo-recomendado-de-trabajo" class="level2">
<h2 class="anchored" data-anchor-id="flujo-recomendado-de-trabajo">3. Flujo recomendado de trabajo</h2>
<ol type="1">
<li><strong>Dibujar</strong> <img src="https://latex.codecogs.com/png.latex?(x,y)"> antes de ajustar. Si no hay nube, no hay recta que contar.</li>
<li><strong>Ajustar</strong> OLS (fórmula o <code>LinearRegression</code>) y anotar <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0">, <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> con unidades.</li>
<li><strong>Predecir</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%20y"> y calcular <strong>MSE</strong> (y RMSE, para leerlo en unidades de <img src="https://latex.codecogs.com/png.latex?y">).</li>
<li><strong>Diagnosticar</strong> residuos contra <img src="https://latex.codecogs.com/png.latex?%5Chat%20y"> y, si se va a inferir, la forma de <img src="https://latex.codecogs.com/png.latex?e_i">.</li>
<li><strong>Interpretar</strong> la pendiente como asociación en el rango de <img src="https://latex.codecogs.com/png.latex?x">. No extrapolar a <img src="https://latex.codecogs.com/png.latex?x=0"> si <img src="https://latex.codecogs.com/png.latex?0"> no existe.</li>
<li><strong>Desconfiar</strong> de un MSE o una pendiente sin el diagrama (Anscombe).</li>
</ol>
<p><strong>Criterio general:</strong> un <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> sin scatter y sin residuos es un número suelto.</p>
</section>
<section id="preparar-el-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparar-el-entorno">4. Preparar el entorno</h2>
<div id="entorno-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:12:57.066852Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:12:57.066439Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:12:59.503162Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:12:59.502396Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb1-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Python:"</span>, sys.version.split()[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> stats</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LinearRegression</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> mean_squared_error, r2_score</span>
<span id="cb1-10"></span>
<span id="cb1-11">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-12"></span>
<span id="cb1-13">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"figure.figsize"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-14">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"axes.grid"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb1-15">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grid.alpha"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span></span>
<span id="cb1-16"></span>
<span id="cb1-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Entorno listo: numpy, pandas, matplotlib, scipy, sklearn."</span>)</span>
<span id="cb1-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sklearn:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">__import__</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sklearn"</span>).__version__, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"| numpy:"</span>, np.__version__)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Python: 3.13.9
Entorno listo: numpy, pandas, matplotlib, scipy, sklearn.
sklearn: 1.8.0 | numpy: 2.3.5</code></pre>
</div>
</div>
<section id="funciones-de-visualización-definidas-una-sola-vez" class="level3">
<h3 class="anchored" data-anchor-id="funciones-de-visualización-definidas-una-sola-vez">Funciones de visualización (definidas una sola vez)</h3>
<p>Cada etapa solo <strong>llama</strong> a la función. El detalle del gráfico queda aquí.</p>
<div id="viz-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:12:59.506021Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:12:59.505575Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:12:59.514891Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:12:59.514082Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> ajustar_ols(x, y):</span>
<span id="cb3-2">    x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(x, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb3-3">    y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(y, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb3-4">    xm, ym <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> x.mean(), y.mean()</span>
<span id="cb3-5">    beta1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>((x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> xm) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> ym)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>((x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> xm) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb3-6">    beta0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ym <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> beta1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xm</span>
<span id="cb3-7">    yhat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> beta0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> beta1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x</span>
<span id="cb3-8">    e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> yhat</span>
<span id="cb3-9">    mse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean(e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb3-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>: beta0, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>: beta1, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yhat"</span>: yhat, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"e"</span>: e, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mse"</span>: mse}</span>
<span id="cb3-11"></span>
<span id="cb3-12"></span>
<span id="cb3-13"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_recta(x, y, beta0, beta1, titulo, xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>):</span>
<span id="cb3-14">    xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(x.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), x.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>)</span>
<span id="cb3-15">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.4</span>))</span>
<span id="cb3-16">    ax.scatter(x, y, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.65</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">32</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"observaciones"</span>)</span>
<span id="cb3-17">    ax.plot(xs, beta0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> beta1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xs, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">fr"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">hat y = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>beta0<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> </span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>beta1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\,</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">x</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-18">    ax.set_xlabel(xlabel)</span>
<span id="cb3-19">    ax.set_ylabel(ylabel)</span>
<span id="cb3-20">    ax.set_title(titulo)</span>
<span id="cb3-21">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-22">    plt.tight_layout()</span>
<span id="cb3-23">    plt.show()</span>
<span id="cb3-24"></span>
<span id="cb3-25"></span>
<span id="cb3-26"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_residuos(yhat, e, titulo):</span>
<span id="cb3-27">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.8</span>))</span>
<span id="cb3-28">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].scatter(yhat, e, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">28</span>)</span>
<span id="cb3-29">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>)</span>
<span id="cb3-30">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_xlabel(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r"ajustado </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">hat y</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-31">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"residuo"</span>)</span>
<span id="cb3-32">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Residuos contra ajustados"</span>)</span>
<span id="cb3-33">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].hist(e, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb3-34">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"residuo"</span>)</span>
<span id="cb3-35">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Histograma de residuos"</span>)</span>
<span id="cb3-36">    fig.suptitle(titulo, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.02</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>)</span>
<span id="cb3-37">    plt.tight_layout()</span>
<span id="cb3-38">    plt.show()</span>
<span id="cb3-39"></span>
<span id="cb3-40"></span>
<span id="cb3-41"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_curva_vs_recta(x, y, beta0, beta1, titulo):</span>
<span id="cb3-42">    orden <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argsort(x)</span>
<span id="cb3-43">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.4</span>))</span>
<span id="cb3-44">    ax.scatter(x, y, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.65</span>, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">32</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"nube (curva + ruido)"</span>)</span>
<span id="cb3-45">    xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(x.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), x.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>)</span>
<span id="cb3-46">    ax.plot(xs, beta0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> beta1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xs, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"recta OLS"</span>)</span>
<span id="cb3-47">    ax.plot(x[orden], y[orden], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.5"</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>)</span>
<span id="cb3-48">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>)</span>
<span id="cb3-49">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>)</span>
<span id="cb3-50">    ax.set_title(titulo)</span>
<span id="cb3-51">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-52">    plt.tight_layout()</span>
<span id="cb3-53">    plt.show()</span>
<span id="cb3-54"></span>
<span id="cb3-55"></span>
<span id="cb3-56"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_anscombe(conjuntos, ajustes, titulo):</span>
<span id="cb3-57">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.0</span>), sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, sharey<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb3-58">    nombres <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"I — recta"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"II — curva"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"III — un atípico"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IV — un x extremo"</span>]</span>
<span id="cb3-59">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax, (x, y), fit, nom <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(axes.ravel(), conjuntos, ajustes, nombres):</span>
<span id="cb3-60">        ax.scatter(x, y, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">36</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.85</span>)</span>
<span id="cb3-61">        xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>)</span>
<span id="cb3-62">        ax.plot(xs, fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xs, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>)</span>
<span id="cb3-63">        ax.set_title(</span>
<span id="cb3-64">            <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>nom<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">β̂₀=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'beta0'</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, β̂₁=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'beta1'</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, MSE=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mse'</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>,</span>
<span id="cb3-65">            fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>,</span>
<span id="cb3-66">        )</span>
<span id="cb3-67">        ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>)</span>
<span id="cb3-68">        ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>)</span>
<span id="cb3-69">    fig.suptitle(titulo, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb3-70">    plt.tight_layout()</span>
<span id="cb3-71">    plt.show()</span></code></pre></div></div>
</div>
</section>
</section>
<section id="desarrollo-por-etapas" class="level2">
<h2 class="anchored" data-anchor-id="desarrollo-por-etapas">5. Desarrollo por etapas</h2>
<p>Primero una nube <strong>diseñada</strong> para que la recta sea la respuesta correcta. Después se rompe un supuesto a la vez y se mira el cuarteto de Anscombe. El caso aplicado es latencia frente a tamaño de lote.</p>
<section id="etapa-1-la-nube-que-sí-es-una-recta" class="level3">
<h3 class="anchored" data-anchor-id="etapa-1-la-nube-que-sí-es-una-recta">Etapa 1: La nube que sí es una recta</h3>
<p>Se generan <img src="https://latex.codecogs.com/png.latex?n=80"> puntos</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ay=2.5+1.8%5C,x+%5Cvarepsilon,%5Cqquad%20%5Cvarepsilon%5Csim%5Cmathcal%20N(0,%5C,1.2%5E2),%5Cquad%20x%5Csim%5Cmathrm%7BUnif%7D(1,10).%0A"></p>
<p>Los parámetros verdaderos se conocen porque el laboratorio los eligió. El ajuste no los “ve”: solo ve la muestra.</p>
<div id="e1-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:12:59.517641Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:12:59.517328Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:12:59.531679Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:12:59.530846Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span></span>
<span id="cb4-2">x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb4-3">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.8</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb4-4">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>: x, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>: y})</span>
<span id="cb4-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(df.describe().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb4-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb4-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Parámetros de diseño: β0 = 2.5,  β1 = 1.8,  σ = 1.2"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>            x       y
count  80.000  80.000
mean    5.559  12.358
std     2.447   4.690
min     1.066   3.235
25%     3.579   8.899
50%     5.632  12.159
75%     7.830  16.606
max     9.781  20.328

Parámetros de diseño: β0 = 2.5,  β1 = 1.8,  σ = 1.2</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> <img src="https://latex.codecogs.com/png.latex?x"> vive entre 1 y 10: el intercepto <img src="https://latex.codecogs.com/png.latex?%5Cbeta_0=2.5"> es una extrapolación a <img src="https://latex.codecogs.com/png.latex?x=0">, fuera del soporte. Ya queda anunciado que <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0"> se leerá con cuidado.</p>
</section>
<section id="etapa-2-mínimos-cuadrados-a-mano" class="level3">
<h3 class="anchored" data-anchor-id="etapa-2-mínimos-cuadrados-a-mano">Etapa 2: Mínimos cuadrados a mano</h3>
<p>Se aplican las fórmulas de <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> y <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0">, y la vía matricial. Deben coincidir.</p>
<div id="e2-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:12:59.534154Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:12:59.533874Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:12:59.542000Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:12:59.541254Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">fit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ajustar_ols(x, y)</span>
<span id="cb6-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Fórmulas:   β̂0 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  β̂1 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb6-3"></span>
<span id="cb6-4">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([np.ones(n), x])</span>
<span id="cb6-5">beta_mat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.inv(X.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> X) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> (X.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> y)</span>
<span id="cb6-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Matricial:  β̂0 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(beta_mat[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  β̂1 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(beta_mat[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb6-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb6-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Diseño:     β0 = 2.5         β1 = 1.8"</span>)</span>
<span id="cb6-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La muestra no recupera el diseño al milímetro: n es finito y hay ruido."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Fórmulas:   β̂0 = 2.0071   β̂1 = 1.8621
Matricial:  β̂0 = 2.0071   β̂1 = 1.8621

Diseño:     β0 = 2.5         β1 = 1.8
La muestra no recupera el diseño al milímetro: n es finito y hay ruido.</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> quedó cerca de <img src="https://latex.codecogs.com/png.latex?1.8">. Esa cercanía es muestreo, no magia de la librería. Con <img src="https://latex.codecogs.com/png.latex?n"> chico o <img src="https://latex.codecogs.com/png.latex?%5Csigma"> grande, el mismo diseño produce pendientes más lejos.</p>
</section>
<section id="etapa-3-la-misma-recta-con-scikit-learn" class="level3">
<h3 class="anchored" data-anchor-id="etapa-3-la-misma-recta-con-scikit-learn">Etapa 3: La misma recta con scikit-learn</h3>
<p><code>LinearRegression</code> estima el intercepto por defecto. <code>coef_</code> es <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1">; <code>intercept_</code> es <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0">. <img src="https://latex.codecogs.com/png.latex?x"> entra como matriz <img src="https://latex.codecogs.com/png.latex?(n,1)">.</p>
<div id="e3-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:12:59.543683Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:12:59.543523Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:12:59.948926Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:12:59.947957Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">modelo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression()</span>
<span id="cb8-2">modelo.fit(x.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), y)</span>
<span id="cb8-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sklearn  β̂0 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(modelo.intercept_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  β̂1 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(modelo.coef_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb8-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"a mano   β̂0 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  β̂1 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb8-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"¿Coinciden?"</span>, np.allclose([modelo.intercept_, modelo.coef_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]], [fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>], fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>]]))</span>
<span id="cb8-6"></span>
<span id="cb8-7">graficar_recta(</span>
<span id="cb8-8">    x, y, fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>], fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>],</span>
<span id="cb8-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Nube diseñada y recta de mínimos cuadrados"</span>,</span>
<span id="cb8-10">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>sklearn  β̂0 = 2.0071   β̂1 = 1.8621
a mano   β̂0 = 2.0071   β̂1 = 1.8621
¿Coinciden? True</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/11-regresion-lineal/index_files/figure-html/cell-6-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Después.</strong> La librería no inventa otro criterio: OLS es OLS. scikit-learn aporta API, predicción y (más adelante) pipelines. El número de la pendiente ya estaba en la etapa 2.</p>
</section>
<section id="etapa-4-predicción-residuo-y-mse" class="level3">
<h3 class="anchored" data-anchor-id="etapa-4-predicción-residuo-y-mse">Etapa 4: Predicción, residuo y MSE</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%20y_i=%5Chat%5Cbeta_0+%5Chat%5Cbeta_1%20x_i,%5Cqquad%20e_i=y_i-%5Chat%20y_i,%5Cqquad%0A%5Cmathrm%7BMSE%7D=%5Cfrac%7B1%7D%7Bn%7D%5Csum%20e_i%5E2.%0A"></p>
<p><code>mean_squared_error</code> usa el divisor <img src="https://latex.codecogs.com/png.latex?n">. <img src="https://latex.codecogs.com/png.latex?s%5E2"> usa <img src="https://latex.codecogs.com/png.latex?n-2">.</p>
<div id="e4-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:12:59.952712Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:12:59.952371Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:12:59.960810Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:12:59.960042Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">yhat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelo.predict(x.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb10-2">e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> yhat</span>
<span id="cb10-3">mse_mano <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean(e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb10-4">mse_sk <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mean_squared_error(y, yhat)</span>
<span id="cb10-5">s2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb10-6">rmse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sqrt(mse_sk)</span>
<span id="cb10-7">r2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> r2_score(y, yhat)</span>
<span id="cb10-8"></span>
<span id="cb10-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MSE a mano     ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(mse_mano, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb10-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MSE sklearn    ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(mse_sk, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb10-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"s² (divisor n-2) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(s2, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← no es el MSE"</span>)</span>
<span id="cb10-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE           ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (unidades de y)"</span>)</span>
<span id="cb10-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R²             ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(r2, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (1 − SCres/SCtot; no sustituye al diagrama)"</span>)</span>
<span id="cb10-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"σ de diseño    = 1.2;  RMSE debería vivir cerca de ese orden."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>MSE a mano     = 1.23
MSE sklearn    = 1.23
s² (divisor n-2) = 1.2615   ← no es el MSE
RMSE           = 1.109   (unidades de y)
R²             = 0.9434   (1 − SCres/SCtot; no sustituye al diagrama)
σ de diseño    = 1.2;  RMSE debería vivir cerca de ese orden.</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> El RMSE es comparable con <img src="https://latex.codecogs.com/png.latex?%5Csigma=1.2">: el modelo no puede bajar de la niebla que se inyectó. Un MSE cercano a <img src="https://latex.codecogs.com/png.latex?0"> aquí sería sospechoso (sobreajuste a <img src="https://latex.codecogs.com/png.latex?n=80"> puntos ruidosos), no un triunfo. <img src="https://latex.codecogs.com/png.latex?R%5E2"> se menciona porque aparece en todos los reportes; no se usa como sello de calidad sin residuos.</p>
</section>
<section id="etapa-5-residuos-cuando-el-modelo-es-el-correcto" class="level3">
<h3 class="anchored" data-anchor-id="etapa-5-residuos-cuando-el-modelo-es-el-correcto">Etapa 5: Residuos cuando el modelo es el correcto</h3>
<p>Si <img src="https://latex.codecogs.com/png.latex?E%5By%5Cmid%20x%5D"> es lineal y la varianza es constante, los residuos contra <img src="https://latex.codecogs.com/png.latex?%5Chat%20y"> son una banda horizontal alrededor de 0, sin curva y sin embudo.</p>
<div id="e5-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:12:59.963360Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:12:59.963068Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:00.227603Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:00.226980Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">graficar_residuos(yhat, e, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Supuestos razonables: banda horizontal, sin patrón"</span>)</span>
<span id="cb12-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Media de residuos (debe ~ 0):"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(e.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb12-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Correlación(x, e) (OLS la anula):"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.corrcoef(x, e)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/11-regresion-lineal/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Media de residuos (debe ~ 0): -0.0
Correlación(x, e) (OLS la anula): -0.0</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> La media de <img src="https://latex.codecogs.com/png.latex?e"> es <img src="https://latex.codecogs.com/png.latex?0"> por construcción del intercepto. <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7Bcorr%7D(x,e)=0"> también: OLS gasta la pendiente hasta agotar la asociación <em>lineal</em> con <img src="https://latex.codecogs.com/png.latex?x">. Eso no prueba que no quede estructura <strong>no lineal</strong>. En esta etapa no queda, porque el diseño era lineal.</p>
</section>
<section id="etapa-6-interpretar-hatbeta_0-y-hatbeta_1" class="level3">
<h3 class="anchored" data-anchor-id="etapa-6-interpretar-hatbeta_0-y-hatbeta_1">Etapa 6: Interpretar <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0"> y <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"></h3>
<p><img src="https://latex.codecogs.com/png.latex?x"> está en “unidades de <img src="https://latex.codecogs.com/png.latex?x">” y <img src="https://latex.codecogs.com/png.latex?y"> en “unidades de <img src="https://latex.codecogs.com/png.latex?y">”. La pendiente hereda <img src="https://latex.codecogs.com/png.latex?y/x">.</p>
<div id="e6-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:00.230453Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:00.230184Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:00.236318Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:00.235679Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">b0, b1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>], fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>]</span>
<span id="cb14-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"β̂0 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>b0<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  → predicción en x = 0 (fuera del rango [</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">])"</span>)</span>
<span id="cb14-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"β̂1 = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>b1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  → Δŷ por cada +1 en x"</span>)</span>
<span id="cb14-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb14-5">x0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span></span>
<span id="cb14-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"ŷ(x=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>x0<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">) = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>b0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x0<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb14-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"No se afirma: 'si yo fuerzo x = 4, y valdrá ese número'."</span>)</span>
<span id="cb14-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Se afirma: 'en nubes como esta, en x = 4, la recta predice ese número'."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>β̂0 = 2.007  → predicción en x = 0 (fuera del rango [1.07, 9.78])
β̂1 = 1.862  → Δŷ por cada +1 en x

ŷ(x=4.0) = 9.455
No se afirma: 'si yo fuerzo x = 4, y valdrá ese número'.
Se afirma: 'en nubes como esta, en x = 4, la recta predice ese número'.</code></pre>
</div>
</div>
<p><strong>Regla de bolsillo.</strong> La pendiente es una <strong>asociación condicional al modelo</strong>. Cambiar <img src="https://latex.codecogs.com/png.latex?x"> en el mundo puede mover otras variables (confusores) que la recta simple no ve. Sin diseño experimental o un argumento causal, <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> no es un efecto de intervención.</p>
</section>
<section id="etapa-7-cuando-la-nube-es-una-curva-la-recta-igual-se-dibuja" class="level3">
<h3 class="anchored" data-anchor-id="etapa-7-cuando-la-nube-es-una-curva-la-recta-igual-se-dibuja">Etapa 7: Cuando la nube es una curva — la recta igual se dibuja</h3>
<p>Se genera <img src="https://latex.codecogs.com/png.latex?y=0.4%5C,x%5E2+%5Cvarepsilon"> en el mismo rango de <img src="https://latex.codecogs.com/png.latex?x">. OLS <strong>no se niega</strong>: entrega una pendiente. El MSE puede parecer “aceptable”. Los residuos quedan en <strong>U</strong>.</p>
<div id="e7-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:00.238669Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:00.238406Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:00.805995Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:00.805190Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">x_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb16-2">y_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb16-3">fit_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ajustar_ols(x_c, y_c)</span>
<span id="cb16-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Curva ajustada con una recta: β̂0 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit_c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  β̂1 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit_c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb16-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MSE (recta sobre curva) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit_c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mse"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb16-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MSE de la nube lineal (etapa 4) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(mse_sk, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  ← no son comparables: y distinta"</span>)</span>
<span id="cb16-7"></span>
<span id="cb16-8">graficar_curva_vs_recta(</span>
<span id="cb16-9">    x_c, y_c, fit_c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>], fit_c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>],</span>
<span id="cb16-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OLS no avisa: ajusta una recta a una parábola"</span>,</span>
<span id="cb16-11">)</span>
<span id="cb16-12">graficar_residuos(fit_c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yhat"</span>], fit_c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"e"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"El diagnóstico: residuos en U (linealidad rota)"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Curva ajustada con una recta: β̂0 = -9.327   β̂1 = 4.47
MSE (recta sobre curva) = 10.297
MSE de la nube lineal (etapa 4) = 1.23   ← no son comparables: y distinta</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/11-regresion-lineal/index_files/figure-html/cell-10-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/11-regresion-lineal/index_files/figure-html/cell-10-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>El contraste (primera mitad).</strong> Un <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> positivo y un MSE finito no certifican linealidad. El gráfico de residuos es parte del modelo, no un adorno. En IA: un lineal sobre una relación umbral o saturada produce el mismo U (o un embudo) y un coeficiente que “parece” interpretable.</p>
</section>
<section id="etapa-8-el-contraste-que-importa-cuarteto-de-anscombe" class="level3">
<h3 class="anchored" data-anchor-id="etapa-8-el-contraste-que-importa-cuarteto-de-anscombe">Etapa 8: El contraste que importa — cuarteto de Anscombe</h3>
<p>Cuatro conjuntos. Mismos <img src="https://latex.codecogs.com/png.latex?n=11">, casi la misma <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0%5Capprox%203">, <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1%5Capprox%200.5"> y el mismo MSE. Cuatro geometrías. Los números son los de Anscombe (1973).</p>
<div id="e8-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:00.808163Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:00.807864Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:01.522803Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:01.521904Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">anscombe <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb18-2">    (</span>
<span id="cb18-3">        np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">10.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]),</span>
<span id="cb18-4">        np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.04</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.95</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.58</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.81</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.33</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.96</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.24</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.26</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">10.84</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.82</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.68</span>]),</span>
<span id="cb18-5">    ),</span>
<span id="cb18-6">    (</span>
<span id="cb18-7">        np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">10.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]),</span>
<span id="cb18-8">        np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.14</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.14</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.74</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.77</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.26</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.10</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.13</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.10</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.13</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.26</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.74</span>]),</span>
<span id="cb18-9">    ),</span>
<span id="cb18-10">    (</span>
<span id="cb18-11">        np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">10.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]),</span>
<span id="cb18-12">        np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.46</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.77</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">12.74</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.11</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.81</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.84</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.08</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.39</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.15</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.42</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.73</span>]),</span>
<span id="cb18-13">    ),</span>
<span id="cb18-14">    (</span>
<span id="cb18-15">        np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">19</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>]),</span>
<span id="cb18-16">        np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.58</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.76</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.71</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.84</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.47</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.04</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.25</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">12.50</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.56</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.91</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.89</span>]),</span>
<span id="cb18-17">    ),</span>
<span id="cb18-18">]</span>
<span id="cb18-19">fits_a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [ajustar_ols(x_a, y_a) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> x_a, y_a <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> anscombe]</span>
<span id="cb18-20">tab <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb18-21">    {</span>
<span id="cb18-22">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"conjunto"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"I"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"II"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"III"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IV"</span>],</span>
<span id="cb18-23">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>: [f[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> f <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> fits_a],</span>
<span id="cb18-24">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>: [f[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> f <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> fits_a],</span>
<span id="cb18-25">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MSE"</span>: [f[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mse"</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> f <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> fits_a],</span>
<span id="cb18-26">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R2"</span>: [r2_score(y_a, f[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yhat"</span>]) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (x_a, y_a), f <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(anscombe, fits_a)],</span>
<span id="cb18-27">    }</span>
<span id="cb18-28">)</span>
<span id="cb18-29"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(tab.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb18-30"></span>
<span id="cb18-31">graficar_anscombe(</span>
<span id="cb18-32">    anscombe, fits_a,</span>
<span id="cb18-33">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Misma pendiente, mismo MSE, cuatro historias. El diagrama no es opcional"</span>,</span>
<span id="cb18-34">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>conjunto  beta0  beta1   MSE    R2
       I  3.000    0.5 1.251 0.667
      II  3.001    0.5 1.252 0.666
     III  3.002    0.5 1.251 0.666
      IV  3.002    0.5 1.249 0.667</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/11-regresion-lineal/index_files/figure-html/cell-11-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>El contraste.</strong> I es una recta ruidosa. II es una curva: la pendiente es un promedio que no existe en ningún tramo. III es una recta más un punto que <strong>inclina</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> (OLS eleva al cuadrado). IV tiene <img src="https://latex.codecogs.com/png.latex?x"> casi constante: un solo <img src="https://latex.codecogs.com/png.latex?x=19"> <strong>apalanca</strong> la pendiente —sin ese punto no hay recta que estimar.</p>
<p>Reportar <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1=0.5"> sin decir <em>cuál</em> de las cuatro nubes es una forma de mentir con el resumen correcto.</p>
</section>
<section id="etapa-9-un-punto-extremo-inclina-la-recta" class="level3">
<h3 class="anchored" data-anchor-id="etapa-9-un-punto-extremo-inclina-la-recta">Etapa 9: Un punto extremo inclina la recta</h3>
<p>Se parte de la nube lineal de la etapa 1 y se añade un punto <img src="https://latex.codecogs.com/png.latex?(x,y)=(18,%5C,4)">: <img src="https://latex.codecogs.com/png.latex?x"> lejos de <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x">, <img src="https://latex.codecogs.com/png.latex?y"> bajo. Se comparan pendientes.</p>
<div id="e9-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:01.524756Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:01.524580Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:01.838932Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:01.838186Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">x_ext <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.append(x, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">18.0</span>)</span>
<span id="cb20-2">y_ext <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.append(y, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>)</span>
<span id="cb20-3">fit_ext <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ajustar_ols(x_ext, y_ext)</span>
<span id="cb20-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sin el punto:  β̂1 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  MSE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mse"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb20-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Con el punto:  β̂1 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit_ext[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  MSE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit_ext[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mse"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb20-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Δβ̂1 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(fit_ext[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> fit[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb20-7"></span>
<span id="cb20-8">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>), sharey<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb20-9"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax, xx, yy, ft, tit <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [</span>
<span id="cb20-10">    (axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], x, y, fit, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n = 80, sin el extremo"</span>),</span>
<span id="cb20-11">    (axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], x_ext, y_ext, fit_ext, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n = 81, un x lejano e y bajo"</span>),</span>
<span id="cb20-12">]:</span>
<span id="cb20-13">    ax.scatter(xx, yy, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">22</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>)</span>
<span id="cb20-14">    xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(xx.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), xx.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>)</span>
<span id="cb20-15">    ax.plot(xs, ft[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta0"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> ft[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta1"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xs, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>)</span>
<span id="cb20-16">    ax.set_title(tit, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb20-17">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>)</span>
<span id="cb20-18">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>)</span>
<span id="cb20-19">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].scatter([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>], [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>], s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">70</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"punto añadido"</span>)</span>
<span id="cb20-20">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb20-21">plt.tight_layout()</span>
<span id="cb20-22">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Sin el punto:  β̂1 = 1.862   MSE = 1.23
Con el punto:  β̂1 = 1.243   MSE = 10.372
Δβ̂1 = -0.619</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/11-regresion-lineal/index_files/figure-html/cell-12-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> Un solo par <img src="https://latex.codecogs.com/png.latex?(x,y)"> lejos en <img src="https://latex.codecogs.com/png.latex?x"> tiene <strong>apalancamiento</strong>: mueve <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> más que un punto cerca de <img src="https://latex.codecogs.com/png.latex?%5Cbar%20x">. No se borra por reflejo (puede ser un fallo real del sistema). Se <strong>reporta</strong> y se ajusta también sin él, para ver cuánto depende la historia de esa fila.</p>
</section>
<section id="etapa-10-caso-latencia-frente-a-tamaño-de-lote" class="level3">
<h3 class="anchored" data-anchor-id="etapa-10-caso-latencia-frente-a-tamaño-de-lote">Etapa 10: Caso — latencia frente a tamaño de lote</h3>
<p>Un servicio de inferencia. <img src="https://latex.codecogs.com/png.latex?x"> = tamaño de lote (1 a 32). <img src="https://latex.codecogs.com/png.latex?y"> = latencia en ms. Diseño:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7Blatencia%7D=18+2.6%5Ccdot%5Ctext%7Blote%7D+%5Cvarepsilon,%5Cqquad%20%5Cvarepsilon%5Csim%5Cmathcal%20N(0,%5C,6%5E2).%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?n=100">. Se ajusta con scikit-learn y se lee <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> en ms por unidad de lote.</p>
<div id="e10-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:01.840948Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:01.840690Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:02.342622Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:02.341278Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1">n_lat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb22-2">lote <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.integers(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">33</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_lat).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb22-3">latencia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.6</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> lote <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.0</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_lat)</span>
<span id="cb22-4"></span>
<span id="cb22-5">mod_lat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression()</span>
<span id="cb22-6">mod_lat.fit(lote.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), latencia)</span>
<span id="cb22-7">yhat_lat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mod_lat.predict(lote.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb22-8">e_lat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> latencia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> yhat_lat</span>
<span id="cb22-9">mse_lat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mean_squared_error(latencia, yhat_lat)</span>
<span id="cb22-10">rmse_lat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.sqrt(mse_lat))</span>
<span id="cb22-11"></span>
<span id="cb22-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"β̂0 (ms, lote=0) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(mod_lat.intercept_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb22-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"β̂1 (ms por +1 de lote) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(mod_lat.coef_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (diseño 2.6)"</span>)</span>
<span id="cb22-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MSE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(mse_lat, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  RMSE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse_lat, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ms  (σ diseño = 6)"</span>)</span>
<span id="cb22-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R² ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(r2_score(latencia, yhat_lat), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb22-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb22-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicción en lote 8: "</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(mod_lat.predict([[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>]])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ms"</span>)</span>
<span id="cb22-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicción en lote 32:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(mod_lat.predict([[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">32</span>]])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ms"</span>)</span>
<span id="cb22-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"No extrapolar a lote 256: está fuera del rango observado."</span>)</span>
<span id="cb22-20"></span>
<span id="cb22-21">graficar_recta(</span>
<span id="cb22-22">    lote, latencia, mod_lat.intercept_, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(mod_lat.coef_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]),</span>
<span id="cb22-23">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Latencia frente a tamaño de lote: recta OLS"</span>,</span>
<span id="cb22-24">    xlabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tamaño de lote"</span>,</span>
<span id="cb22-25">    ylabel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"latencia (ms)"</span>,</span>
<span id="cb22-26">)</span>
<span id="cb22-27">graficar_residuos(yhat_lat, e_lat, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Residuos del servicio: ¿banda o patrón?"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>β̂0 (ms, lote=0) = 19.274
β̂1 (ms por +1 de lote) = 2.516   (diseño 2.6)
MSE = 35.311   RMSE = 5.942 ms  (σ diseño = 6)
R² = 0.939

Predicción en lote 8:  39.4 ms
Predicción en lote 32: 99.78 ms
No extrapolar a lote 256: está fuera del rango observado.</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/11-regresion-lineal/index_files/figure-html/cell-13-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/11-regresion-lineal/index_files/figure-html/cell-13-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Traducción.</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1%5Capprox%202.6"> ms por unidad de lote es una <strong>asociación</strong> en el rango 1–32. El intercepto (~18 ms) se parece a una latencia fija (carga del modelo, red), pero lote <img src="https://latex.codecogs.com/png.latex?0"> no se midió: es ancla, no experimento. El RMSE ~6 ms es el ruido de diseño; un modelo más flexible no debería “ganar” por debajo de eso sin inventar estructura.</p>
</section>
<section id="caso-aplicado-reportar-una-recta" class="level3">
<h3 class="anchored" data-anchor-id="caso-aplicado-reportar-una-recta">Caso aplicado: reportar una recta</h3>
<p>Plantilla mínima:</p>
<ol type="1">
<li><strong>Respuesta y explicativa.</strong> <img src="https://latex.codecogs.com/png.latex?y">, <img src="https://latex.codecogs.com/png.latex?x">, unidades, rango de <img src="https://latex.codecogs.com/png.latex?x">.</li>
<li><strong>Modelo y ajuste.</strong> Lineal simple, OLS, <img src="https://latex.codecogs.com/png.latex?n">.</li>
<li><strong>Coeficientes.</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0">, <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> en unidades, con la frase de asociación.</li>
<li><strong>Error.</strong> MSE y RMSE.</li>
<li><strong>Diagnóstico.</strong> Residuos: ¿banda, U, embudo, un punto que apalanca?</li>
<li><strong>Límite.</strong> Causalidad, extrapolación, una sola <img src="https://latex.codecogs.com/png.latex?x">.</li>
</ol>
<p>Se aplica a la etapa 10.</p>
<p><strong>Los seis pasos, aplicados</strong></p>
<ol type="1">
<li><strong>Variables.</strong> <img src="https://latex.codecogs.com/png.latex?y"> = latencia de inferencia (ms). <img src="https://latex.codecogs.com/png.latex?x"> = tamaño de lote (1 a 32). <img src="https://latex.codecogs.com/png.latex?n=100">.</li>
<li><strong>Modelo.</strong> <img src="https://latex.codecogs.com/png.latex?y=%5Cbeta_0+%5Cbeta_1%20x+%5Cvarepsilon">, OLS con <code>LinearRegression</code>.</li>
<li><strong>Coeficientes.</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> ≈ 2.6 ms por +1 de lote (el print de la etapa 10). <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0"> es la predicción en lote 0, no observado.</li>
<li><strong>Error.</strong> RMSE del orden de 6 ms, coherente con el ruido del diseño.</li>
<li><strong>Diagnóstico.</strong> Si los residuos son banda horizontal, la recta es una descripción honesta <em>en este rango</em>. (Ver figura de la etapa 10.)</li>
<li><strong>Límite.</strong> No se afirma que <em>subir</em> el lote <em>cause</em> +2.6 ms (puede haber colas, GPU, otro tráfico). No se predice lote 256. Una sola <em>feature</em>.</li>
</ol>
<blockquote class="blockquote">
<p>En <img src="https://latex.codecogs.com/png.latex?n=100"> requests, la latencia media se asocia a <img src="https://latex.codecogs.com/png.latex?+%5C,%5Chat%5Cbeta_1"> ms por cada unidad de lote (OLS). RMSE ≈ 6 ms. Se usa la recta para interpolar entre lotes 1 y 32, no para decidir un cambio de infraestructura sin un experimento. Limitación: una <img src="https://latex.codecogs.com/png.latex?x">, ruido gaussiano de diseño, sin cola p95.</p>
</blockquote>
</section>
<section id="errores-que-conviene-nombrar" class="level3">
<h3 class="anchored" data-anchor-id="errores-que-conviene-nombrar">Errores que conviene nombrar</h3>
<ol type="1">
<li><strong>Leer <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> como efecto causal</strong> sin diseño que lo sostenga.</li>
<li><strong>Extrapolar</strong> a <img src="https://latex.codecogs.com/png.latex?x=0"> o más allá del rango (el intercepto, el lote 256).</li>
<li><strong>Reportar MSE o <img src="https://latex.codecogs.com/png.latex?R%5E2"> sin el scatter</strong> (Anscombe).</li>
<li><strong>Ignorar residuos en U o en embudo.</strong> La recta se calcula igual; el modelo está mal especificado.</li>
<li><strong>Confundir MSE (<img src="https://latex.codecogs.com/png.latex?/n">) con <img src="https://latex.codecogs.com/png.latex?s%5E2"> (<img src="https://latex.codecogs.com/png.latex?/(n-2)">).</strong></li>
<li><strong>Borrar el atípico por costumbre.</strong> Se informa el ajuste con y sin él.</li>
<li><strong>Tratar <img src="https://latex.codecogs.com/png.latex?R%5E2"> alto como “el modelo es bueno”.</strong> <img src="https://latex.codecogs.com/png.latex?R%5E2"> no ve sesgo de forma ni utilidad de la predicción fuera de muestra.</li>
</ol>
</section>
<section id="idea-clave" class="level3">
<h3 class="anchored" data-anchor-id="idea-clave">Idea clave</h3>
<p><strong>OLS responde a una pregunta: qué recta deja la menor suma de cuadrados.</strong> No responde a si la nube era una recta, ni a si mover <img src="https://latex.codecogs.com/png.latex?x"> moverá <img src="https://latex.codecogs.com/png.latex?y">. Eso lo dicen el diagrama, los residuos y el diseño del dato.</p>
</section>
<section id="síntesis" class="level3">
<h3 class="anchored" data-anchor-id="síntesis">Síntesis</h3>
<p>Se escribió <img src="https://latex.codecogs.com/png.latex?y=%5Cbeta_0+%5Cbeta_1%20x+%5Cvarepsilon">, se minimizó <img src="https://latex.codecogs.com/png.latex?S"> a mano y con scikit-learn, se separó MSE de <img src="https://latex.codecogs.com/png.latex?s%5E2"> y se leyó la pendiente en unidades. Los residuos validaron el caso lineal y delataron la parábola. Anscombe y el punto de alto apalancamiento mostraron que el mismo resumen numérico no fija la historia. El servicio de inferencia aplicó la plantilla: <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> en ms/lote, RMSE, rango, y la negativa a causalidad automática.</p>
</section>
</section>
<section id="guía-rápida-qué-fórmula-usar" class="level2">
<h2 class="anchored" data-anchor-id="guía-rápida-qué-fórmula-usar">6. Guía rápida: ¿qué fórmula usar?</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Situación</th>
<th>Qué usar</th>
<th>Por qué</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Una <img src="https://latex.codecogs.com/png.latex?x">, una <img src="https://latex.codecogs.com/png.latex?y"> numérica, forma de recta</td>
<td><img src="https://latex.codecogs.com/png.latex?y=%5Cbeta_0+%5Cbeta_1%20x+%5Cvarepsilon"></td>
<td>Modelo lineal simple</td>
</tr>
<tr class="even">
<td>Elegir la recta</td>
<td>OLS: fórmulas o <code>LinearRegression</code></td>
<td>Minimiza <img src="https://latex.codecogs.com/png.latex?%5Csum%20e_i%5E2"></td>
</tr>
<tr class="odd">
<td>Error de ajuste en <img src="https://latex.codecogs.com/png.latex?y%5E2"></td>
<td>MSE <img src="https://latex.codecogs.com/png.latex?=n%5E%7B-1%7D%5Csum%20e_i%5E2"></td>
<td>Pérdida <img src="https://latex.codecogs.com/png.latex?L_2"></td>
</tr>
<tr class="even">
<td>Error en unidades de <img src="https://latex.codecogs.com/png.latex?y"></td>
<td>RMSE <img src="https://latex.codecogs.com/png.latex?=%5Csqrt%7B%5Cmathrm%7BMSE%7D%7D"></td>
<td>Comparable con <img src="https://latex.codecogs.com/png.latex?%5Csigma"> y con <img src="https://latex.codecogs.com/png.latex?y"></td>
</tr>
<tr class="odd">
<td>¿La nube es recta?</td>
<td>Residuos vs <img src="https://latex.codecogs.com/png.latex?%5Chat%20y"></td>
<td>U / embudo / atípico</td>
</tr>
<tr class="even">
<td>¿Cuánto se asocia <img src="https://latex.codecogs.com/png.latex?y"> a +1 de <img src="https://latex.codecogs.com/png.latex?x">?</td>
<td><img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"></td>
<td>Asociación, no causa</td>
</tr>
<tr class="odd">
<td>Cuatro nubes, mismos <img src="https://latex.codecogs.com/png.latex?%5Cbeta"></td>
<td>Diagrama (Anscombe)</td>
<td>El resumen no basta</td>
</tr>
</tbody>
</table>
<p><strong>Regla de comunicación:</strong> unidades de <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1">, rango de <img src="https://latex.codecogs.com/png.latex?x">, RMSE y una frase sobre residuos.</p>
</section>
<section id="guía-práctica-para-reportar-una-recta" class="level2">
<h2 class="anchored" data-anchor-id="guía-práctica-para-reportar-una-recta">7. Guía práctica para reportar una recta</h2>
<section id="paso-1-y-x-y-rango" class="level3">
<h3 class="anchored" data-anchor-id="paso-1-y-x-y-rango">Paso 1: <img src="https://latex.codecogs.com/png.latex?y">, <img src="https://latex.codecogs.com/png.latex?x"> y rango</h3>
<p>Respuesta, explicativa, unidades, <img src="https://latex.codecogs.com/png.latex?n">, mínimo y máximo de <img src="https://latex.codecogs.com/png.latex?x">.</p>
</section>
<section id="paso-2-ajuste" class="level3">
<h3 class="anchored" data-anchor-id="paso-2-ajuste">Paso 2: ajuste</h3>
<p>OLS, <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_0">, <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1">.</p>
</section>
<section id="paso-3-error-y-diagnóstico" class="level3">
<h3 class="anchored" data-anchor-id="paso-3-error-y-diagnóstico">Paso 3: error y diagnóstico</h3>
<p>MSE, RMSE, residuos (banda / U / embudo / apalancamiento).</p>
</section>
<section id="paso-4-frase-de-asociación" class="level3">
<h3 class="anchored" data-anchor-id="paso-4-frase-de-asociación">Paso 4: frase de asociación</h3>
<p>“+1 en <img src="https://latex.codecogs.com/png.latex?x"> se asocia a <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> en <img src="https://latex.codecogs.com/png.latex?y">, en este rango.”</p>
</section>
<section id="paso-5-redactar" class="level3">
<h3 class="anchored" data-anchor-id="paso-5-redactar">Paso 5: redactar</h3>
<blockquote class="blockquote">
<p>“En <code>[población]</code>, <img src="https://latex.codecogs.com/png.latex?n="><code>[...]</code>, se ajustó <img src="https://latex.codecogs.com/png.latex?y=%5Cbeta_0+%5Cbeta_1%20x+%5Cvarepsilon"> por OLS. <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1="><code>[...]</code> <code>[unidades de y]</code> por <code>[unidad de x]</code>. RMSE=<code>[...]</code>. Residuos: <code>[banda / U / embudo]</code>. Se interpreta como asociación en <img src="https://latex.codecogs.com/png.latex?x%5Cin"><code>[rango]</code>, no como efecto causal. Limitación: <code>[una x / atípico / extrapolación]</code>.”</p>
</blockquote>
<p>El caso de latencia (etapa 10) ya llenó esta plantilla.</p>
</section>
</section>
<section id="puente-hacia-las-siguientes-sesiones" class="level2">
<h2 class="anchored" data-anchor-id="puente-hacia-las-siguientes-sesiones">8. Puente hacia las siguientes sesiones</h2>
<p>La recta predice un número. La <strong>clasificación</strong> predice una clase: la pérdida deja de ser MSE y pasan a importar umbrales y costos de error. La <strong>validación</strong> dirá que el MSE de esta muestra es optimista: hay que medirlo fuera de las filas que ajustaron <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta">. Varias <img src="https://latex.codecogs.com/png.latex?x"> a la vez son la misma pérdida <img src="https://latex.codecogs.com/png.latex?L_2"> en un plano; los supuestos y los residuos no se jubilan.</p>
</section>
<section id="cierre" class="level2">
<h2 class="anchored" data-anchor-id="cierre">9. Cierre</h2>
<p>Este notebook deja el modelo numérico más corto:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?y=%5Cbeta_0+%5Cbeta_1%20x+%5Cvarepsilon"> y los supuestos que lo hacen honesto,</li>
<li>mínimos cuadrados a mano y con scikit-learn,</li>
<li>MSE, RMSE y <img src="https://latex.codecogs.com/png.latex?s%5E2">,</li>
<li>interpretación de coeficientes sin causalidad automática,</li>
<li>residuos, curva mal especificada, apalancamiento y Anscombe,</li>
<li>un servicio de inferencia reportado en ms por lote.</li>
</ul>
<p><strong>Resultado esperado:</strong> el estudiante puede ajustar una recta, leer <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_1"> en unidades, calcular el MSE y negarse a publicar la pendiente sin el diagrama de la nube y de los residuos.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>regresion-lineal</category>
  <category>scikit-learn</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/basico/11-regresion-lineal/</guid>
  <pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Estadística para IA — 12. Clasificación y métricas de evaluación</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/basico/12-clasificacion-metricas-evaluacion/</link>
  <description><![CDATA[ 




<section id="sesión-12-clasificación-y-métricas-de-evaluación" class="level1">
<h1>Sesión 12 — Clasificación y Métricas de Evaluación</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado es Científico de Datos, Arquitecto de IA, Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), consultor y docente universitario, trabaja en la intersección entre Data Science, Inteligencia Artificial, Big Data e IoT, transformando problemas reales en soluciones aplicadas.</p>
<p>De la teoría a la práctica, un problema a la vez.</p>
</section>
<section id="un-99-de-aciertos-puede-ser-un-modelo-inútil" class="level2">
<h2 class="anchored" data-anchor-id="un-99-de-aciertos-puede-ser-un-modelo-inútil">Un 99% de aciertos puede ser un modelo inútil</h2>
<p>Clasificar no es “acertar filas”. Es decidir, con un umbral, qué casos merecen la etiqueta positiva —fraude, enfermedad, <em>spam</em>— sabiendo que <strong>los dos errores no pesan igual</strong> y que la clase que importa suele ser la rara. Un clasificador que nunca alerta acierta el 97% si solo el 3% es positivo. Ese 97% no es un modelo: es la <strong>frecuencia base</strong>.</p>
<p>Este notebook construye el lenguaje para <strong>leer</strong> un clasificador: <strong>matriz de confusión</strong>, <strong>exactitud</strong> (<em>accuracy</em>), <strong>precisión</strong>, <strong>recall</strong> (sensibilidad), <strong>F1</strong>, <strong>curva ROC</strong>, <strong>AUC</strong> y los <strong>tipos de desbalance</strong>. El contraste que importa es el mismo de la prueba diagnóstica: <em><img src="https://latex.codecogs.com/png.latex?P(+%5Cmid%20E)"> no es <img src="https://latex.codecogs.com/png.latex?P(E%5Cmid%20+)"></em>. Aquí se llaman recall y precisión.</p>
<p>Contexto: un filtro de <strong>fraude</strong> diseñado (clase positiva <img src="https://latex.codecogs.com/png.latex?%5Capprox%204.6%5C%25"> en prueba) y el conjunto <strong>Breast cancer</strong> de scikit-learn para aplicar el veredicto a un <img src="https://latex.codecogs.com/png.latex?y"> real.</p>
<p>Electiva I — Estadística Aplicada a la Inteligencia Artificial · Módulo 4 · Sesión 12</p>
</section>
<section id="objetivos" class="level2">
<h2 class="anchored" data-anchor-id="objetivos">Objetivos</h2>
<ul>
<li>Plantear la <strong>clasificación binaria</strong> como <img src="https://latex.codecogs.com/png.latex?P(y=1%5Cmid%20x)"> más un <strong>umbral</strong>.</li>
<li>Construir y leer la <strong>matriz de confusión</strong> (VP, FP, FN, VN).</li>
<li>Calcular <strong>exactitud</strong>, <strong>precisión</strong>, <strong>recall</strong> y <strong>F1</strong>, y saber cuándo cada una miente.</li>
<li>No usar la exactitud como veredicto cuando hay <strong>desbalance</strong> o costos asimétricos.</li>
<li>Leer la <strong>curva ROC</strong> y el <strong>AUC</strong>; contrastarlos con la curva precisión–recall.</li>
<li>Elegir el umbral según el <strong>costo</strong> de un falso positivo frente a un falso negativo.</li>
<li>Redactar un veredicto: ¿el clasificador sirve <em>para este uso</em>?</li>
</ul>
<blockquote class="blockquote">
<p>Nota: se recomienda ejecutar las celdas en orden. Las fórmulas usan LaTeX; si no se ven renderizadas, abre el notebook en Jupyter o Colab.</p>
</blockquote>
</section>
<section id="el-clasificador-es-un-umbral-sobre-una-probabilidad" class="level2">
<h2 class="anchored" data-anchor-id="el-clasificador-es-un-umbral-sobre-una-probabilidad">1. El clasificador es un umbral sobre una probabilidad</h2>
<section id="clasificación-binaria" class="level3">
<h3 class="anchored" data-anchor-id="clasificación-binaria">1.1 Clasificación binaria</h3>
<p>Cada fila tiene una etiqueta <img src="https://latex.codecogs.com/png.latex?y%5Cin%5C%7B0,1%5C%7D">. El modelo no “es” 0 o 1: entrega un score <img src="https://latex.codecogs.com/png.latex?s(x)%5Cin%5B0,1%5D"> (o un logit). La etiqueta predicha es</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%20y%20=%20%5Cmathbf%7B1%7D%5C%7Bs(x)%5Cge%20%5Ctau%5C%7D.%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5"> es costumbre, no teorema. Mover <img src="https://latex.codecogs.com/png.latex?%5Ctau"> cambia <strong>todos</strong> los conteos de la matriz. Un modelo y un umbral son un par; reportar métricas sin <img src="https://latex.codecogs.com/png.latex?%5Ctau"> es reportar a medias.</p>
</section>
<section id="matriz-de-confusión" class="level3">
<h3 class="anchored" data-anchor-id="matriz-de-confusión">1.2 Matriz de confusión</h3>
<p>Se compara <img src="https://latex.codecogs.com/png.latex?%5Chat%20y"> con <img src="https://latex.codecogs.com/png.latex?y"> en un conjunto <strong>no usado para ajustar</strong> (si se valida; si no, se está midiendo memoria). Cuatro conteos:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th></th>
<th><img src="https://latex.codecogs.com/png.latex?%5Chat%20y=1"> (alerta)</th>
<th><img src="https://latex.codecogs.com/png.latex?%5Chat%20y=0"></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><img src="https://latex.codecogs.com/png.latex?y=1"></td>
<td><strong>VP</strong> (verdadero positivo)</td>
<td><strong>FN</strong> (falso negativo)</td>
</tr>
<tr class="even">
<td><img src="https://latex.codecogs.com/png.latex?y=0"></td>
<td><strong>FP</strong> (falso positivo)</td>
<td><strong>VN</strong> (verdadero negativo)</td>
</tr>
</tbody>
</table>
<p>scikit-learn, con etiquetas <code>[0, 1]</code>, imprime</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Bbmatrix%7D%20%5Cmathrm%7BVN%7D%20&amp;%20%5Cmathrm%7BFP%7D%20%5C%5C%20%5Cmathrm%7BFN%7D%20&amp;%20%5Cmathrm%7BVP%7D%20%5Cend%7Bbmatrix%7D.%0A"></p>
<p>La esquina que se mira primero no es la diagonal completa: es <strong>quién paga el error</strong>. En fraude, un FN es un cargo que pasó; un FP es un cliente molesto. En cribado médico, un FN es un enfermo no visto.</p>
</section>
<section id="exactitud-accuracy" class="level3">
<h3 class="anchored" data-anchor-id="exactitud-accuracy">1.3 Exactitud (<em>accuracy</em>)</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7Bexactitud%7D=%5Cfrac%7B%5Cmathrm%7BVP%7D+%5Cmathrm%7BVN%7D%7D%7Bn%7D.%0A"></p>
<p>Es la fracción de filas bien etiquetadas. Es una métrica <strong>simétrica</strong>: trata los dos errores igual y trata las dos clases igual. Cuando <img src="https://latex.codecogs.com/png.latex?P(y=1)"> es 0.03, predecir siempre <img src="https://latex.codecogs.com/png.latex?0"> da exactitud <img src="https://latex.codecogs.com/png.latex?0.97">. Ese número no informa sobre el fraude.</p>
<p><strong>Baseline de exactitud:</strong> la frecuencia de la clase mayoritaria. Si el modelo no la supera, las <em>features</em> no están trabajando <em>para esa métrica</em> —y a veces no hay que superarlas, porque la métrica está mal elegida.</p>
</section>
<section id="precisión-recall-y-f1" class="level3">
<h3 class="anchored" data-anchor-id="precisión-recall-y-f1">1.4 Precisión, recall y F1</h3>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7Bprecisi%C3%B3n%7D=%5Cfrac%7B%5Cmathrm%7BVP%7D%7D%7B%5Cmathrm%7BVP%7D+%5Cmathrm%7BFP%7D%7D=P(y=1%5Cmid%20%5Chat%20y=1),%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7Brecall%7D=%5Cfrac%7B%5Cmathrm%7BVP%7D%7D%7B%5Cmathrm%7BVP%7D+%5Cmathrm%7BFN%7D%7D=P(%5Chat%20y=1%5Cmid%20y=1).%0A"></p>
<p>La <strong>precisión</strong> es, entre las alertas, qué fracción era positiva. El <strong>recall</strong> (sensibilidad, exhaustividad) es, entre los positivos reales, qué fracción se alertó.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AF_1=2%5Ccdot%5Cfrac%7B%5Cmathrm%7Bprecisi%C3%B3n%7D%5Ccdot%5Cmathrm%7Brecall%7D%7D%7B%5Cmathrm%7Bprecisi%C3%B3n%7D+%5Cmathrm%7Brecall%7D%7D%0A"></p>
<p>es la media armónica: castiga que una de las dos sea cercana a 0. No incorpora costos. No sustituye elegir <img src="https://latex.codecogs.com/png.latex?%5Ctau">.</p>
<p><strong>Especificidad</strong> <img src="https://latex.codecogs.com/png.latex?=%20%5Cmathrm%7BVN%7D/(%5Cmathrm%7BVN%7D+%5Cmathrm%7BFP%7D)=P(%5Chat%20y=0%5Cmid%20y=0)">. El <strong>FPR</strong> (tasa de falsos positivos) es <img src="https://latex.codecogs.com/png.latex?1"> menos eso: <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BFP%7D/(%5Cmathrm%7BFP%7D+%5Cmathrm%7BVN%7D)">.</p>
</section>
<section id="roc-y-auc" class="level3">
<h3 class="anchored" data-anchor-id="roc-y-auc">1.5 ROC y AUC</h3>
<p>Se barre <img src="https://latex.codecogs.com/png.latex?%5Ctau"> de <img src="https://latex.codecogs.com/png.latex?1"> a <img src="https://latex.codecogs.com/png.latex?0">. En cada umbral se anota</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7BTPR%7D=%5Cmathrm%7Brecall%7D,%5Cqquad%20%5Cmathrm%7BFPR%7D=%5Cfrac%7B%5Cmathrm%7BFP%7D%7D%7B%5Cmathrm%7BFP%7D+%5Cmathrm%7BVN%7D%7D.%0A"></p>
<p>La <strong>curva ROC</strong> es TPR frente a FPR. El <strong>AUC</strong> (<em>area under the curve</em>) es el área bajo esa curva: probabilidad de que un positivo al azar tenga <em>score</em> mayor que un negativo al azar. AUC <img src="https://latex.codecogs.com/png.latex?=0.5"> es el clasificador aleatorio; <img src="https://latex.codecogs.com/png.latex?1"> es separación perfecta.</p>
<p>El AUC <strong>no elige umbral</strong>. Un AUC de 0.92 puede convivir con precisión 0.08 en el <img src="https://latex.codecogs.com/png.latex?%5Ctau"> de operación si la clase es rara: el ranking es bueno y la canasta de alertas sigue llena de negativos.</p>
<p>Cuando hay desbalance extremo, la curva <strong>precisión–recall</strong> (PR) y su área (AP) suelen ser más honestas: el eje <img src="https://latex.codecogs.com/png.latex?y"> es precisamente <img src="https://latex.codecogs.com/png.latex?P(y=1%5Cmid%20%5Chat%20y=1)">, que es lo que el negocio ve.</p>
</section>
<section id="tipos-de-desbalance" class="level3">
<h3 class="anchored" data-anchor-id="tipos-de-desbalance">1.6 Tipos de desbalance</h3>
<p>No hay un solo “desbalance”:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Tipo</th>
<th>Qué ocurre</th>
<th>Qué miente</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>De clase</strong></td>
<td><img src="https://latex.codecogs.com/png.latex?P(y=1)%5Cll%200.5"> (fraude, rareza clínica)</td>
<td>Exactitud; a veces el AUC</td>
</tr>
<tr class="even">
<td><strong>De costo</strong></td>
<td>FN y FP no valen lo mismo</td>
<td><img src="https://latex.codecogs.com/png.latex?F_1"> y <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5"></td>
</tr>
<tr class="odd">
<td><strong>De prevalencia</strong></td>
<td>El 3% del train no es el 3% de producción</td>
<td>Precisión (cambia con la frecuencia base)</td>
</tr>
</tbody>
</table>
<p>La precisión <strong>depende de la prevalencia</strong>. El recall, no (si el score se calibra igual). Por eso un modelo “preciso” en un banco de prueba con 20% de positivos se derrumba cuando en producción hay 2%. Es el mismo fenómeno de la prueba diagnóstica: bajar <img src="https://latex.codecogs.com/png.latex?P(E)"> baja <img src="https://latex.codecogs.com/png.latex?P(E%5Cmid%20+)">.</p>
</section>
<section id="protocolo-el-clasificador-es-aceptable" class="level3">
<h3 class="anchored" data-anchor-id="protocolo-el-clasificador-es-aceptable">1.7 Protocolo: ¿el clasificador es aceptable?</h3>
<ol type="1">
<li><strong>¿Cuál es <img src="https://latex.codecogs.com/png.latex?P(y=1)"></strong> en el conjunto que se reporta?</li>
<li><strong>¿Qué cuesta un FP y un FN</strong> en este uso?</li>
<li><strong>¿La exactitud gana a la clase mayoritaria?</strong> Si esa es la única cifra, no hay veredicto.</li>
<li><strong>Precisión, recall, <img src="https://latex.codecogs.com/png.latex?F_1"></strong> en el <img src="https://latex.codecogs.com/png.latex?%5Ctau"> de operación, no solo el “óptimo” de un notebook.</li>
<li><strong>ROC y, si hay rareza, PR.</strong> El AUC no se cita solo.</li>
<li><strong>¿El umbral se eligió con la prueba?</strong> Si sí, la cifra ya no es independiente.</li>
</ol>
<table class="caption-top table">
<colgroup>
<col style="width: 50%">
<col style="width: 50%">
</colgroup>
<thead>
<tr class="header">
<th>Pregunta</th>
<th>Métrica</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>¿Aciertos globales?</td>
<td>Exactitud (solo si clases y costos son simétricos)</td>
</tr>
<tr class="even">
<td>¿Las alertas son confiables?</td>
<td>Precisión</td>
</tr>
<tr class="odd">
<td>¿Se escapan pocos positivos?</td>
<td>Recall</td>
</tr>
<tr class="even">
<td>¿Un solo número de compromiso?</td>
<td><img src="https://latex.codecogs.com/png.latex?F_1"> (sin costos)</td>
</tr>
<tr class="odd">
<td>¿El ranking separa?</td>
<td>AUC-ROC</td>
</tr>
<tr class="even">
<td>¿La canasta de alertas, con rareza?</td>
<td>Curva PR / AP</td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="por-qué-importa-en-ia-y-machine-learning" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-importa-en-ia-y-machine-learning">2. Por qué importa en IA y Machine Learning</h2>
<p>El <code>predict</code> de scikit-learn usa <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5">. El negocio casi nunca vive ahí.</p>
<ul>
<li>Un detector de fraude con recall 0.15 “deja pasar” el 85% de los casos; la exactitud puede seguir por encima de 0.96.</li>
<li>Un filtro de <em>spam</em> con precisión 0.40 mete correo legítimo en cuarentena: el costo es reputación, no un <img src="https://latex.codecogs.com/png.latex?F_1">.</li>
<li>Calibrar <img src="https://latex.codecogs.com/png.latex?s(x)"> (que “0.8” signifique 80 de cada 100) es otra pregunta; aquí se evalúa el <strong>corte</strong> y el <strong>ranking</strong>.</li>
<li>Elegir <img src="https://latex.codecogs.com/png.latex?%5Ctau"> mirando la prueba y citar esa misma prueba es la fuga de siempre, ahora en el umbral.</li>
</ul>
<p><strong>Idea central:</strong> la métrica correcta es la que refleja el <strong>error que duele</strong>. La exactitud refleja el error que <em>abunda</em>.</p>
</section>
<section id="flujo-recomendado-de-trabajo" class="level2">
<h2 class="anchored" data-anchor-id="flujo-recomendado-de-trabajo">3. Flujo recomendado de trabajo</h2>
<ol type="1">
<li><strong>Declarar</strong> la clase positiva, la prevalencia y el costo relativo FN/FP.</li>
<li><strong>Reservar prueba.</strong> Ajustar el modelo en entrenamiento. El umbral se elige en desarrollo (o con costos), no recorriendo la prueba.</li>
<li><strong>Matriz de confusión</strong> en prueba, en el <img src="https://latex.codecogs.com/png.latex?%5Ctau"> de operación.</li>
<li><strong>Exactitud contra el baseline mayoritario.</strong> Precisión, recall, <img src="https://latex.codecogs.com/png.latex?F_1">.</li>
<li><strong>ROC y PR.</strong> No vender solo el AUC.</li>
<li><strong>Veredicto</strong> para un uso: “sirve para priorizar revisión”, “no sirve para bloqueo automático”, etc.</li>
</ol>
<p><strong>Criterio general:</strong> un clasificador sin prevalencia, sin matriz y sin umbral declarado no se puede aceptar. Solo se puede aplaudir un porcentaje.</p>
</section>
<section id="preparar-el-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparar-el-entorno">4. Preparar el entorno</h2>
<div id="entorno-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:24.638950Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:24.638499Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:26.820131Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:26.819560Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb1-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Python:"</span>, sys.version.split()[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.datasets <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_classification, load_breast_cancer</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LogisticRegression</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.dummy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> DummyClassifier</span>
<span id="cb1-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split</span>
<span id="cb1-11"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> StandardScaler</span>
<span id="cb1-12"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.pipeline <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Pipeline</span>
<span id="cb1-13"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> (</span>
<span id="cb1-14">    confusion_matrix,</span>
<span id="cb1-15">    accuracy_score,</span>
<span id="cb1-16">    precision_score,</span>
<span id="cb1-17">    recall_score,</span>
<span id="cb1-18">    f1_score,</span>
<span id="cb1-19">    roc_curve,</span>
<span id="cb1-20">    roc_auc_score,</span>
<span id="cb1-21">    precision_recall_curve,</span>
<span id="cb1-22">    average_precision_score,</span>
<span id="cb1-23">    classification_report,</span>
<span id="cb1-24">)</span>
<span id="cb1-25"></span>
<span id="cb1-26">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-27"></span>
<span id="cb1-28">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"figure.figsize"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-29">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"axes.grid"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb1-30">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grid.alpha"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span></span>
<span id="cb1-31"></span>
<span id="cb1-32"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Entorno listo: numpy, pandas, matplotlib, sklearn."</span>)</span>
<span id="cb1-33"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sklearn:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">__import__</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sklearn"</span>).__version__)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Python: 3.13.9
Entorno listo: numpy, pandas, matplotlib, sklearn.
sklearn: 1.8.0</code></pre>
</div>
</div>
<section id="funciones-de-métricas-y-gráficos-una-sola-vez" class="level3">
<h3 class="anchored" data-anchor-id="funciones-de-métricas-y-gráficos-una-sola-vez">Funciones de métricas y gráficos (una sola vez)</h3>
<div id="viz-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:26.823210Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:26.822124Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:26.833127Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:26.832441Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> conteos(y_true, y_pred):</span>
<span id="cb3-2">    vn, fp, fn, vp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> confusion_matrix(y_true, y_pred, labels<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]).ravel()</span>
<span id="cb3-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"VN"</span>: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(vn), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"FP"</span>: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(fp), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"FN"</span>: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(fn), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"VP"</span>: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(vp)}</span>
<span id="cb3-4"></span>
<span id="cb3-5"></span>
<span id="cb3-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> ficha_clf(y_true, y_pred, etiqueta, y_score<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>):</span>
<span id="cb3-7">    prev <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.mean(y_true))</span>
<span id="cb3-8">    fila <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-9">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"modelo"</span>: etiqueta,</span>
<span id="cb3-10">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prevalencia"</span>: prev,</span>
<span id="cb3-11">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"exactitud"</span>: accuracy_score(y_true, y_pred),</span>
<span id="cb3-12">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"precisión"</span>: precision_score(y_true, y_pred, zero_division<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb3-13">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"recall"</span>: recall_score(y_true, y_pred, zero_division<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb3-14">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"F1"</span>: f1_score(y_true, y_pred, zero_division<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb3-15">    }</span>
<span id="cb3-16">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> y_score <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>:</span>
<span id="cb3-17">        fila[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AUC"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> roc_auc_score(y_true, y_score)</span>
<span id="cb3-18">        fila[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AP"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> average_precision_score(y_true, y_score)</span>
<span id="cb3-19">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> fila</span>
<span id="cb3-20"></span>
<span id="cb3-21"></span>
<span id="cb3-22"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_matriz(y_true, y_pred, titulo):</span>
<span id="cb3-23">    M <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> confusion_matrix(y_true, y_pred, labels<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb3-24">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>))</span>
<span id="cb3-25">    im <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ax.imshow(M, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Blues"</span>)</span>
<span id="cb3-26">    ax.set_xticks([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ŷ = 0"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ŷ = 1"</span>])</span>
<span id="cb3-27">    ax.set_yticks([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y = 0"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y = 1"</span>])</span>
<span id="cb3-28">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (i, j), val <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> np.ndenumerate(M):</span>
<span id="cb3-29">        ax.text(j, i, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>(val), ha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>, va<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.1"</span>)</span>
<span id="cb3-30">    ax.set_title(titulo)</span>
<span id="cb3-31">    fig.colorbar(im, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ax, fraction<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.046</span>)</span>
<span id="cb3-32">    plt.tight_layout()</span>
<span id="cb3-33">    plt.show()</span>
<span id="cb3-34">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> M</span>
<span id="cb3-35"></span>
<span id="cb3-36"></span>
<span id="cb3-37"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_roc_pr(y_true, y_score, titulo):</span>
<span id="cb3-38">    fpr, tpr, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> roc_curve(y_true, y_score)</span>
<span id="cb3-39">    p, r, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> precision_recall_curve(y_true, y_score)</span>
<span id="cb3-40">    auc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> roc_auc_score(y_true, y_score)</span>
<span id="cb3-41">    ap <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> average_precision_score(y_true, y_score)</span>
<span id="cb3-42">    prev <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.mean(y_true))</span>
<span id="cb3-43">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.9</span>))</span>
<span id="cb3-44">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(fpr, tpr, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"AUC = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>auc<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-45">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.5"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"azar"</span>)</span>
<span id="cb3-46">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"FPR"</span>)</span>
<span id="cb3-47">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TPR (recall)"</span>)</span>
<span id="cb3-48">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ROC"</span>)</span>
<span id="cb3-49">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-50">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(r, p, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"AP = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>ap<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-51">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].axhline(prev, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.5"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"baseline PR = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>prev<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-52">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"recall"</span>)</span>
<span id="cb3-53">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"precisión"</span>)</span>
<span id="cb3-54">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Precisión–recall"</span>)</span>
<span id="cb3-55">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylim(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb3-56">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-57">    fig.suptitle(titulo, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.02</span>)</span>
<span id="cb3-58">    plt.tight_layout()</span>
<span id="cb3-59">    plt.show()</span>
<span id="cb3-60"></span>
<span id="cb3-61"></span>
<span id="cb3-62"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_umbral(y_true, y_score, titulo):</span>
<span id="cb3-63">    taus <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">19</span>)</span>
<span id="cb3-64">    filas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb3-65">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> t <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> taus:</span>
<span id="cb3-66">        yp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (y_score <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> t).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)</span>
<span id="cb3-67">        filas.append(</span>
<span id="cb3-68">            {</span>
<span id="cb3-69">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"τ"</span>: t,</span>
<span id="cb3-70">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"precisión"</span>: precision_score(y_true, yp, zero_division<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb3-71">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"recall"</span>: recall_score(y_true, yp, zero_division<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb3-72">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"F1"</span>: f1_score(y_true, yp, zero_division<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb3-73">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"exactitud"</span>: accuracy_score(y_true, yp),</span>
<span id="cb3-74">            }</span>
<span id="cb3-75">        )</span>
<span id="cb3-76">    df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(filas)</span>
<span id="cb3-77">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>))</span>
<span id="cb3-78">    ax.plot(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"τ"</span>], df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"precisión"</span>], marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"precisión"</span>)</span>
<span id="cb3-79">    ax.plot(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"τ"</span>], df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"recall"</span>], marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"s"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"recall"</span>)</span>
<span id="cb3-80">    ax.plot(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"τ"</span>], df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"F1"</span>], marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"F1"</span>)</span>
<span id="cb3-81">    ax.axvline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.4"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">":"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"τ = 0.5"</span>)</span>
<span id="cb3-82">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"umbral τ"</span>)</span>
<span id="cb3-83">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"métrica"</span>)</span>
<span id="cb3-84">    ax.set_title(titulo)</span>
<span id="cb3-85">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-86">    plt.tight_layout()</span>
<span id="cb3-87">    plt.show()</span>
<span id="cb3-88">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> df</span></code></pre></div></div>
</div>
</section>
</section>
<section id="desarrollo-por-etapas" class="level2">
<h2 class="anchored" data-anchor-id="desarrollo-por-etapas">5. Desarrollo por etapas</h2>
<p>Primero un fraude <strong>diseñado</strong> con prevalencia <img src="https://latex.codecogs.com/png.latex?%5Capprox%204.6%5C%25">: ahí la exactitud se derrumba como argumento. Después, Breast cancer: prevalencia más alta, y el veredicto cambia de forma.</p>
<section id="etapa-1-el-dato-y-la-frecuencia-base" class="level3">
<h3 class="anchored" data-anchor-id="etapa-1-el-dato-y-la-frecuencia-base">Etapa 1: El dato y la frecuencia base</h3>
<p><img src="https://latex.codecogs.com/png.latex?n=4000"> filas, <img src="https://latex.codecogs.com/png.latex?8"> <em>features</em>, clase positiva (fraude) alrededor del <img src="https://latex.codecogs.com/png.latex?3%5C%25">. Se reserva <img src="https://latex.codecogs.com/png.latex?30%5C%25"> de prueba. El primer número que se escribe no es un modelo: es <img src="https://latex.codecogs.com/png.latex?P(y=1)">.</p>
<div id="e1-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:26.835188Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:26.834998Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:26.846920Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:26.846326Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">X, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_classification(</span>
<span id="cb4-2">    n_samples<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4000</span>,</span>
<span id="cb4-3">    n_features<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>,</span>
<span id="cb4-4">    n_informative<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb4-5">    n_redundant<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb4-6">    n_clusters_per_class<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb4-7">    weights<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.97</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.03</span>],</span>
<span id="cb4-8">    class_sep<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.62</span>,</span>
<span id="cb4-9">    flip_y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.03</span>,</span>
<span id="cb4-10">    random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>,</span>
<span id="cb4-11">)</span>
<span id="cb4-12">X_tr, X_te, y_tr, y_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(</span>
<span id="cb4-13">    X, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>, stratify<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y</span>
<span id="cb4-14">)</span>
<span id="cb4-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n train ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_tr), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  n test ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_te))</span>
<span id="cb4-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(y=1) train ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y_tr.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  P(y=1) test ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y_te.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb4-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Positivos en test ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(y_te.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"de"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_te))</span>
<span id="cb4-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb4-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Baseline de exactitud (siempre ŷ=0) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y_te.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>n train = 2800   n test = 1200
P(y=1) train = 0.0454   P(y=1) test = 0.0458
Positivos en test = 55 de 1200

Baseline de exactitud (siempre ŷ=0) = 0.9542</code></pre>
</div>
</div>
<p><strong>Cómo leer esto.</strong> Hay 55 positivos en test (el print manda). Cualquier métrica de la clase positiva se calcula con <strong>decenas</strong> de filas, no con miles. La exactitud, en cambio, se calcula con 1200: por eso se ve “estable” y miente.</p>
<p><strong>Veredicto parcial.</strong> Ya existe un clasificador: “nadie es fraude”. Su exactitud es <img src="https://latex.codecogs.com/png.latex?1-%5Cpi">. Ese es el piso que hay que <strong>dejar de citar</strong> como éxito.</p>
</section>
<section id="etapa-2-el-espejismo-de-la-exactitud" class="level3">
<h3 class="anchored" data-anchor-id="etapa-2-el-espejismo-de-la-exactitud">Etapa 2: El espejismo de la exactitud</h3>
<p><code>DummyClassifier(strategy="most_frequent")</code> predice siempre la clase mayoritaria. No usa <img src="https://latex.codecogs.com/png.latex?x">. Su exactitud en prueba es, por diseño, <img src="https://latex.codecogs.com/png.latex?%5Capprox%200.954"> (el print de la etapa 1).</p>
<div id="e2-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:26.848908Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:26.848661Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:26.970260Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:26.969785Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">dummy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DummyClassifier(strategy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"most_frequent"</span>)</span>
<span id="cb6-2">dummy.fit(X_tr, y_tr)</span>
<span id="cb6-3">yp_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> dummy.predict(X_te)</span>
<span id="cb6-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame([ficha_clf(y_te, yp_d, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dummy mayoritaria"</span>, y_score<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>np.zeros(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_te)))]).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb6-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb6-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Conteos:"</span>, conteos(y_te, yp_d))</span>
<span id="cb6-7">graficar_matriz(y_te, yp_d, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Dummy: VN masivo, VP = 0. Exactitud alta, recall 0"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>           modelo  prevalencia  exactitud  precisión  recall  F1  AUC     AP
dummy mayoritaria       0.0458     0.9542        0.0     0.0 0.0  0.5 0.0458

Conteos: {'VN': 1145, 'FP': 0, 'FN': 55, 'VP': 0}</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/12-clasificacion-metricas-evaluacion/index_files/figure-html/cell-5-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display" data-execution_count="4">
<pre><code>array([[1145,    0],
       [  55,    0]])</code></pre>
</div>
</div>
<p><strong>Cómo leer la matriz.</strong> Casi toda la masa está en VN. VP <img src="https://latex.codecogs.com/png.latex?=0">, FN <img src="https://latex.codecogs.com/png.latex?="> todos los fraudes, FP <img src="https://latex.codecogs.com/png.latex?=0">. Precisión <img src="https://latex.codecogs.com/png.latex?0"> (no hubo alerta), recall <img src="https://latex.codecogs.com/png.latex?0">, <img src="https://latex.codecogs.com/png.latex?F_1=0">. Exactitud <img src="https://latex.codecogs.com/png.latex?%5Capprox%200.954">.</p>
<p><strong>Qué no se concluye.</strong> Que “no hay señal en <img src="https://latex.codecogs.com/png.latex?x">”. El dummy <strong>no miró</strong> <img src="https://latex.codecogs.com/png.latex?x">. Se concluye que la exactitud, sola, <strong>no distingue</strong> a este dummy de un detector útil.</p>
<p><strong>Pregunta de análisis.</strong> Si un informe solo trae “accuracy 95.4%”, ¿qué pregunta haces antes de felicitar al equipo?</p>
</section>
<section id="etapa-3-un-modelo-que-sí-usa-x-logística-con-scikit-learn" class="level3">
<h3 class="anchored" data-anchor-id="etapa-3-un-modelo-que-sí-usa-x-logística-con-scikit-learn">Etapa 3: Un modelo que sí usa <img src="https://latex.codecogs.com/png.latex?x"> — logística con scikit-learn</h3>
<p><code>LogisticRegression</code> + estandarización. Umbral por defecto <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5">. Se compara con el dummy <strong>en la misma prueba</strong>.</p>
<div id="e3-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:26.971715Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:26.971550Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:27.086055Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:27.085532Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1">clf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline(</span>
<span id="cb9-2">    [</span>
<span id="cb9-3">        (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"esc"</span>, StandardScaler()),</span>
<span id="cb9-4">        (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"log"</span>, LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>, class_weight<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>)),</span>
<span id="cb9-5">    ]</span>
<span id="cb9-6">)</span>
<span id="cb9-7">clf.fit(X_tr, y_tr)</span>
<span id="cb9-8">yp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> clf.predict(X_te)</span>
<span id="cb9-9">ys <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> clf.predict_proba(X_te)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb9-10"></span>
<span id="cb9-11">tab <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb9-12">    [</span>
<span id="cb9-13">        ficha_clf(y_te, yp_d, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dummy mayoritaria"</span>, y_score<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>np.zeros(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_te))),</span>
<span id="cb9-14">        ficha_clf(y_te, yp, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"logística τ=0.5"</span>, ys),</span>
<span id="cb9-15">    ]</span>
<span id="cb9-16">)</span>
<span id="cb9-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(tab.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb9-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb9-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Conteos logística:"</span>, conteos(y_te, yp))</span>
<span id="cb9-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb9-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(classification_report(y_te, yp, digits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, zero_division<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span>
<span id="cb9-22">graficar_matriz(y_te, yp, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Logística, τ=0.5: aparecen VP, y también FP"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>           modelo  prevalencia  exactitud  precisión  recall    F1   AUC    AP
dummy mayoritaria        0.046      0.954        0.0   0.000 0.000 0.500 0.046
  logística τ=0.5        0.046      0.964        1.0   0.218 0.358 0.735 0.420

Conteos logística: {'VN': 1145, 'FP': 0, 'FN': 43, 'VP': 12}

              precision    recall  f1-score   support

           0      0.964     1.000     0.982      1145
           1      1.000     0.218     0.358        55

    accuracy                          0.964      1200
   macro avg      0.982     0.609     0.670      1200
weighted avg      0.965     0.964     0.953      1200
</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/12-clasificacion-metricas-evaluacion/index_files/figure-html/cell-6-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display" data-execution_count="5">
<pre><code>array([[1145,    0],
       [  43,   12]])</code></pre>
</div>
</div>
<p><strong>Cómo leer la comparación.</strong> La exactitud <strong>no es el juez</strong>. Puede quedar por debajo del dummy (el modelo se atreve a alertar y fabrica FP) o por encima (como a veces ocurre si separa bien). El dummy tiene VP <img src="https://latex.codecogs.com/png.latex?=0">. La logística, no. Se compara <strong>recall y precisión</strong>, no el 96%.</p>
<p>Mira, en este orden: <strong>recall</strong> (¿cuántos fraudes pescó?), <strong>precisión</strong> (¿qué tan sucia es la lista?), <strong>exactitud</strong> (al final, si acaso).</p>
<p><strong>Qué no se concluye.</strong> Que <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5"> sea el corte de operación. La etapa 6 lo mueve.</p>
<p><strong>Veredicto parcial.</strong> Si la logística no gana al dummy en <em>recall</em> o en <img src="https://latex.codecogs.com/png.latex?F_1">, <img src="https://latex.codecogs.com/png.latex?x"> no está separando. Si gana ahí y pierde una décima de exactitud, <strong>se prefiere la logística</strong> para este uso.</p>
</section>
<section id="etapa-4-las-cuatro-celdas-en-palabras" class="level3">
<h3 class="anchored" data-anchor-id="etapa-4-las-cuatro-celdas-en-palabras">Etapa 4: Las cuatro celdas, en palabras</h3>
<p>Se toman los conteos de la logística y se traducen. Sin esta frase, la matriz es decoración.</p>
<div id="e4-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:27.087682Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:27.087506Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:27.092897Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:27.092475Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> conteos(y_te, yp)</span>
<span id="cb12-2">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_te)</span>
<span id="cb12-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"De </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> transacciones de prueba:"</span>)</span>
<span id="cb12-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'VP'</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> fraudes bien alertados (VP)"</span>)</span>
<span id="cb12-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'FN'</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> fraudes que pasaron (FN)  ← costo de 'dejar pasar'"</span>)</span>
<span id="cb12-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'FP'</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> legítimas alertadas (FP)  ← costo de 'molestar'"</span>)</span>
<span id="cb12-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'VN'</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> legítimas en paz (VN)"</span>)</span>
<span id="cb12-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb12-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"precisión = VP / (VP+FP) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"VP"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"VP"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"FP"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb12-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"recall    = VP / (VP+FN) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"VP"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"VP"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"FN"</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb12-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"exactitud = (VP+VN) / n  ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>((c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"VP"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> c[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"VN"</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>De 1200 transacciones de prueba:
  12 fraudes bien alertados (VP)
  43 fraudes que pasaron (FN)  ← costo de 'dejar pasar'
  0 legítimas alertadas (FP)  ← costo de 'molestar'
  1145 legítimas en paz (VN)

precisión = VP / (VP+FP) = 1.0
recall    = VP / (VP+FN) = 0.218
exactitud = (VP+VN) / n  = 0.964</code></pre>
</div>
</div>
<p><strong>Cómo leer las frases.</strong> “Hay <img src="https://latex.codecogs.com/png.latex?a"> fraudes bien alertados y <img src="https://latex.codecogs.com/png.latex?b"> que se escaparon” es el recall en humano. “De cada 10 alertas, <img src="https://latex.codecogs.com/png.latex?c"> eran fraude” es la precisión. El comité de producto entiende esas dos oraciones. No entiende “<img src="https://latex.codecogs.com/png.latex?F_1=0.41">” si no las ha oído antes.</p>
<p><strong>Pregunta de análisis.</strong> Si cada FN cuesta 20 veces un FP, ¿miras primero el recall o la precisión?</p>
</section>
<section id="etapa-5-el-mismo-modelo-dos-usos-dos-veredictos" class="level3">
<h3 class="anchored" data-anchor-id="etapa-5-el-mismo-modelo-dos-usos-dos-veredictos">Etapa 5: El mismo modelo, dos usos, dos veredictos</h3>
<p>No se reentrena. Se <strong>lee</strong> la misma matriz con dos costos.</p>
<ul>
<li><strong>Uso A — bloqueo automático.</strong> Un FP cobra cara (cliente bloqueado). Se exige precisión alta; se tolera perder fraude.</li>
<li><strong>Uso B — cola de revisión.</strong> Un FN cobra cara (fraude no visto). Se exige recall alto; se acepta una cola sucia.</li>
</ul>
<div id="e5-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:27.094326Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:27.094161Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:27.103421Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:27.102720Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Misma matriz, dos lecturas (τ = 0.5)"</span>)</span>
<span id="cb14-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.Series(c).to_string())</span>
<span id="cb14-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb14-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Uso A (bloqueo):  precisión ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(precision_score(y_te, yp, zero_division<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb14-5">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  → 0 FP: lista limpia. El hueco no es suciedad; son los FN que se escapan."</span>)</span>
<span id="cb14-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Uso B (revisión): recall    ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(recall_score(y_te, yp, zero_division<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb14-7">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  → ¿qué fracción del fraude llega a la cola?"</span>)</span>
<span id="cb14-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb14-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"El F1 ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(f1_score(y_te, yp, zero_division<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb14-10">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"promedia las dos y no sabe cuál uso es el de hoy."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Misma matriz, dos lecturas (τ = 0.5)
VN    1145
FP       0
FN      43
VP      12

Uso A (bloqueo):  precisión = 1.0   → 0 FP: lista limpia. El hueco no es suciedad; son los FN que se escapan.
Uso B (revisión): recall    = 0.218   → ¿qué fracción del fraude llega a la cola?

El F1 = 0.358 promedia las dos y no sabe cuál uso es el de hoy.</code></pre>
</div>
</div>
<p><strong>Cómo leer el desdoble.</strong> El modelo no cambió. El <strong>veredicto</strong> sí. “¿Es bueno?” sin el uso es la pregunta mal hecha de siempre. <img src="https://latex.codecogs.com/png.latex?F_1"> es un compromiso ciego: útil para <em>ordenar</em> modelos en un ranking, insuficiente para <em>desplegar</em>.</p>
<p><strong>Veredicto parcial.</strong> A <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5"> casi nunca se firman los dos usos a la vez. Hace falta mover el umbral (etapa 6) o declarar uno solo.</p>
</section>
<section id="etapa-6-mover-tau-precisión-y-recall-no-se-maximizan-juntos" class="level3">
<h3 class="anchored" data-anchor-id="etapa-6-mover-tau-precisión-y-recall-no-se-maximizan-juntos">Etapa 6: Mover <img src="https://latex.codecogs.com/png.latex?%5Ctau"> — precisión y recall no se maximizan juntos</h3>
<p>Se barre el umbral. Subir <img src="https://latex.codecogs.com/png.latex?%5Ctau"> exige más certeza para alertar: <strong>sube</strong> la precisión y <strong>baja</strong> el recall. Bajar <img src="https://latex.codecogs.com/png.latex?%5Ctau"> hace lo contrario.</p>
<div id="e6-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:27.105008Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:27.104835Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:27.272428Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:27.271949Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">df_tau <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> graficar_umbral(y_te, ys, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Fraude: al subir τ, la lista se limpia y se escapan más casos"</span>)</span>
<span id="cb16-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(df_tau.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb16-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb16-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Máximo F1 en esta parrilla: τ ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(df_tau.loc[df_tau[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"F1"</span>].idxmax(), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"τ"</span>]))</span>
<span id="cb16-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ese τ máximo-F1 se eligió MIRANDO la prueba: en un protocolo estricto no se publica como operación."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/12-clasificacion-metricas-evaluacion/index_files/figure-html/cell-9-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>   τ  precisión  recall    F1  exactitud
0.05      0.141   0.564 0.225      0.822
0.10      0.316   0.455 0.373      0.930
0.15      0.444   0.364 0.400      0.950
0.20      0.667   0.364 0.471      0.962
0.25      0.810   0.309 0.447      0.965
0.30      0.824   0.255 0.389      0.963
0.35      0.867   0.236 0.371      0.963
0.40      0.923   0.218 0.353      0.963
0.45      0.923   0.218 0.353      0.963
0.50      1.000   0.218 0.358      0.964
0.55      1.000   0.200 0.333      0.963
0.60      1.000   0.182 0.308      0.962
0.65      1.000   0.182 0.308      0.962
0.70      1.000   0.182 0.308      0.962
0.75      1.000   0.145 0.254      0.961
0.80      1.000   0.145 0.254      0.961
0.85      1.000   0.145 0.254      0.961
0.90      1.000   0.055 0.103      0.957
0.95      1.000   0.055 0.103      0.957

Máximo F1 en esta parrilla: τ = 0.2
Ese τ máximo-F1 se eligió MIRANDO la prueba: en un protocolo estricto no se publica como operación.</code></pre>
</div>
</div>
<p><strong>Cómo leer la parrilla.</strong> Cada fila es un clasificador distinto (mismo <img src="https://latex.codecogs.com/png.latex?s(x)">, otro corte). La exactitud apenas se mueve: está dominada por los VN. Precisión y recall se cruzan. El <img src="https://latex.codecogs.com/png.latex?%5Ctau"> que maximiza <img src="https://latex.codecogs.com/png.latex?F_1"> <strong>en esta prueba</strong> ya usó <img src="https://latex.codecogs.com/png.latex?y"> de test: si se cita, hay fuga de umbral. En trabajo real ese máximo se busca en desarrollo.</p>
<p><strong>Qué no se concluye.</strong> Que exista un <img src="https://latex.codecogs.com/png.latex?%5Ctau"> “correcto”. Existe un <img src="https://latex.codecogs.com/png.latex?%5Ctau"> para un costo. Si FN vale 20·FP, se baja <img src="https://latex.codecogs.com/png.latex?%5Ctau"> aunque el <img src="https://latex.codecogs.com/png.latex?F_1"> empeore.</p>
<p><strong>Veredicto parcial.</strong> Reportar métricas implica reportar <img src="https://latex.codecogs.com/png.latex?%5Ctau">. “Logística, <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5">” y “logística, <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.20">” no son el mismo producto.</p>
</section>
<section id="etapa-7-roc-y-auc-el-ranking-no-el-corte" class="level3">
<h3 class="anchored" data-anchor-id="etapa-7-roc-y-auc-el-ranking-no-el-corte">Etapa 7: ROC y AUC — el ranking, no el corte</h3>
<p>La ROC resume <em>todos</em> los umbrales. El AUC dice si los fraudes tienden a tener <img src="https://latex.codecogs.com/png.latex?s(x)"> mayor que las legítimas.</p>
<div id="e7-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:27.273945Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:27.273789Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:27.453279Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:27.452823Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AUC-ROC ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(roc_auc_score(y_te, ys), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb18-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AP (área bajo PR) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(average_precision_score(y_te, ys), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb18-3">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"   baseline PR = prevalencia ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y_te.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb18-4">graficar_roc_pr(y_te, ys, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mismo score: ROC alta no implica precisión alta"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>AUC-ROC = 0.735
AP (área bajo PR) = 0.42    baseline PR = prevalencia = 0.046</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/12-clasificacion-metricas-evaluacion/index_files/figure-html/cell-10-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Cómo leer las dos curvas.</strong> La ROC puede verse “buena” (lejos de la diagonal) mientras la PR vive cerca de una precisión mediocre: hay pocos positivos, y cualquier FPR no nulo <strong>inunda</strong> la canasta de alertas (muchos negativos <img src="https://latex.codecogs.com/png.latex?%5Ctimes"> un FPR chico <img src="https://latex.codecogs.com/png.latex?="> muchos FP).</p>
<p>El AP se compara con la <strong>prevalencia</strong>, no con <img src="https://latex.codecogs.com/png.latex?0.5">. Un AP de <img src="https://latex.codecogs.com/png.latex?0.25"> con <img src="https://latex.codecogs.com/png.latex?%5Cpi=0.03"> es una mejora grande; un AUC de <img src="https://latex.codecogs.com/png.latex?0.80"> no dice cuán sucia es la lista en operación.</p>
<p><strong>Qué no se concluye.</strong> Que AUC <img src="https://latex.codecogs.com/png.latex?%3E0.9"> autorice bloqueo automático. El AUC no conoce <img src="https://latex.codecogs.com/png.latex?%5Ctau"> ni el costo.</p>
<p><strong>Veredicto parcial.</strong> Se citan <strong>las dos</strong> curvas cuando <img src="https://latex.codecogs.com/png.latex?%5Cpi"> es chico. Solo ROC es el retrato de estudio; PR es la foto del mostrador.</p>
</section>
<section id="etapa-8-desbalance-de-clase-class_weightbalanced" class="level3">
<h3 class="anchored" data-anchor-id="etapa-8-desbalance-de-clase-class_weightbalanced">Etapa 8: Desbalance de clase — <code>class_weight="balanced"</code></h3>
<p>La logística sin pesos trata cada fila igual: como hay 30 negativos por positivo, el ajuste se acomoda a acertar negativos. <code>class_weight="balanced"</code> pondera al revés de la frecuencia. Cambia <img src="https://latex.codecogs.com/png.latex?s(x)"> y, a <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5">, suele <strong>subir recall y bajar precisión</strong>.</p>
<div id="e8-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:27.454917Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:27.454728Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:27.482100Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:27.481639Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">clf_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline(</span>
<span id="cb20-2">    [</span>
<span id="cb20-3">        (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"esc"</span>, StandardScaler()),</span>
<span id="cb20-4">        (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"log"</span>, LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>, class_weight<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"balanced"</span>)),</span>
<span id="cb20-5">    ]</span>
<span id="cb20-6">)</span>
<span id="cb20-7">clf_b.fit(X_tr, y_tr)</span>
<span id="cb20-8">yp_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> clf_b.predict(X_te)</span>
<span id="cb20-9">ys_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> clf_b.predict_proba(X_te)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb20-10"></span>
<span id="cb20-11">tab_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb20-12">    [</span>
<span id="cb20-13">        ficha_clf(y_te, yp, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"logística (sin pesos) τ=0.5"</span>, ys),</span>
<span id="cb20-14">        ficha_clf(y_te, yp_b, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"logística balanced τ=0.5"</span>, ys_b),</span>
<span id="cb20-15">    ]</span>
<span id="cb20-16">)</span>
<span id="cb20-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(tab_b.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb20-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb20-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Conteos sin pesos:"</span>, conteos(y_te, yp))</span>
<span id="cb20-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Conteos balanced: "</span>, conteos(y_te, yp_b))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>                     modelo  prevalencia  exactitud  precisión  recall    F1   AUC    AP
logística (sin pesos) τ=0.5        0.046      0.964      1.000   0.218 0.358 0.735 0.420
   logística balanced τ=0.5        0.046      0.803      0.134   0.600 0.219 0.744 0.373

Conteos sin pesos: {'VN': 1145, 'FP': 0, 'FN': 43, 'VP': 12}
Conteos balanced:  {'VN': 931, 'FP': 214, 'FN': 22, 'VP': 33}</code></pre>
</div>
</div>
<p><strong>Cómo leer el cambio.</strong> No es “un modelo mejor”: es <strong>otro punto</strong> del compromiso. Balanced empuja a encontrar positivos. El AUC a veces se mueve poco (el ranking no cambia tanto); precisión y recall en <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5"> sí. Eso confirma que el umbral y los pesos son palancas de <em>operación</em>, no milagros de ajuste.</p>
<p><strong>Veredicto parcial.</strong> Elegir <code>balanced</code> es elegir un uso (cola de revisión), no una medalla. Se compara en la métrica del uso, no en exactitud.</p>
</section>
<section id="etapa-9-desbalance-de-prevalencia-la-precisión-se-mueve-sola" class="level3">
<h3 class="anchored" data-anchor-id="etapa-9-desbalance-de-prevalencia-la-precisión-se-mueve-sola">Etapa 9: Desbalance de prevalencia — la precisión se mueve sola</h3>
<p>Se <strong>submuestrea</strong> la prueba para fabricar una prevalencia del 15% (mismo modelo, mismo <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5">, mismos pesos originales). El recall debería parecerse; la precisión <strong>sube</strong> porque hay más positivos en la canasta.</p>
<div id="e9-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:27.483553Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:27.483388Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:27.500308Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:27.499840Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1">rng_loc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb22-2">pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(y_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb22-3">neg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(y_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb22-4">n_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(pos)</span>
<span id="cb22-5">n_neg_objetivo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(n_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.15</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.15</span>)</span>
<span id="cb22-6">neg_s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng_loc.choice(neg, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(n_neg_objetivo, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(neg)), replace<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb22-7">idx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.concatenate([pos, neg_s])</span>
<span id="cb22-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Prevalencia original test ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y_te.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  n ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_te))</span>
<span id="cb22-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Prevalencia recortada     ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y_te[idx].mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  n ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(idx))</span>
<span id="cb22-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb22-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(</span>
<span id="cb22-12">    pd.DataFrame(</span>
<span id="cb22-13">        [</span>
<span id="cb22-14">            ficha_clf(y_te, yp, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"π ≈ 0.05, τ=0.5"</span>, ys),</span>
<span id="cb22-15">            ficha_clf(y_te[idx], yp[idx], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"π ≈ 0.15, τ=0.5"</span>, ys[idx]),</span>
<span id="cb22-16">        ]</span>
<span id="cb22-17">    ).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb22-18">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Prevalencia original test = 0.046   n = 1200
Prevalencia recortada     = 0.15   n = 366

         modelo  prevalencia  exactitud  precisión  recall    F1   AUC    AP
π ≈ 0.05, τ=0.5        0.046      0.964        1.0   0.218 0.358 0.735 0.420
π ≈ 0.15, τ=0.5        0.150      0.883        1.0   0.218 0.358 0.737 0.569</code></pre>
</div>
</div>
<p><strong>Cómo leer las dos filas.</strong> El recall se mantiene en el mismo orden (depende de <img src="https://latex.codecogs.com/png.latex?P(%5Chat%20y=1%5Cmid%20y=1)">, no de <img src="https://latex.codecogs.com/png.latex?%5Cpi">). La precisión <strong>tiende</strong> a subir al inflar <img src="https://latex.codecogs.com/png.latex?%5Cpi"> (Bayes: más positivos en la canasta). Si hay poquísimos FP, el cambio puede ser chico en <em>esta</em> semilla; el AP y el baseline de la curva PR sí se mueven. Un proveedor que mide precisión en un conjunto <strong>enriquecido</strong> (muchos fraudes a propósito) vende un número que <strong>no</strong> se verá en producción.</p>
<p><strong>Veredicto parcial.</strong> Toda precisión se publica con su <strong>prevalencia</strong>. Sin <img src="https://latex.codecogs.com/png.latex?%5Cpi">, el 80% no se puede traducir.</p>
</section>
<section id="etapa-10-caso-real-breast-cancer-wisconsin" class="level3">
<h3 class="anchored" data-anchor-id="etapa-10-caso-real-breast-cancer-wisconsin">Etapa 10: Caso real — Breast cancer (Wisconsin)</h3>
<p><img src="https://latex.codecogs.com/png.latex?n=569">, <img src="https://latex.codecogs.com/png.latex?p=30"> atributos del núcleo celular. En <code>load_breast_cancer</code> la etiqueta 0 es <em>malignant</em> y la 1 es <em>benign</em>: <strong>se invierte</strong> <img src="https://latex.codecogs.com/png.latex?y"> para que <img src="https://latex.codecogs.com/png.latex?y=1"> sea maligno. Prevalencia ~37%: <strong>no</strong> es el fraude al 4.6%. El mismo aparato debe dar <em>otro</em> veredicto, no el mismo párrafo recortado.</p>
<p>Partición estratificada 30% prueba. Logística estandarizada, <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5">. Matriz, métricas, ROC/PR, umbrales.</p>
<div id="e10-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:27.501843Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:27.501678Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:27.987475Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:27.986911Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1">bc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> load_breast_cancer()</span>
<span id="cb24-2">Xb, yb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> bc.data, bc.target</span>
<span id="cb24-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"clases (orden sklearn):"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(bc.target_names), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  conteos [0, 1] ="</span>, np.bincount(yb))</span>
<span id="cb24-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"En load_breast_cancer: 0 = malignant, 1 = benign."</span>)</span>
<span id="cb24-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Para el oficio clínico la clase positiva debe ser el maligno. Se invierte y."</span>)</span>
<span id="cb24-6">y_mal <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (yb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)</span>
<span id="cb24-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P(maligno) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y_mal.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  n ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_mal), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  p ="</span>, Xb.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb24-8"></span>
<span id="cb24-9">Xb_tr, Xb_te, yb_tr, yb_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(</span>
<span id="cb24-10">    Xb, y_mal, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>, stratify<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y_mal</span>
<span id="cb24-11">)</span>
<span id="cb24-12">clf_bc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline(</span>
<span id="cb24-13">    [(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"esc"</span>, StandardScaler()), (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"log"</span>, LogisticRegression(max_iter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>))]</span>
<span id="cb24-14">)</span>
<span id="cb24-15">clf_bc.fit(Xb_tr, yb_tr)</span>
<span id="cb24-16">yp_bc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> clf_bc.predict(Xb_te)</span>
<span id="cb24-17">ys_bc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> clf_bc.predict_proba(Xb_te)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb24-18">yp_maj <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DummyClassifier(strategy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"most_frequent"</span>).fit(Xb_tr, yb_tr).predict(Xb_te)</span>
<span id="cb24-19"></span>
<span id="cb24-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb24-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(</span>
<span id="cb24-22">    pd.DataFrame(</span>
<span id="cb24-23">        [</span>
<span id="cb24-24">            ficha_clf(yb_te, yp_maj, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dummy mayoritaria"</span>, y_score<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>np.zeros(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(yb_te))),</span>
<span id="cb24-25">            ficha_clf(yb_te, yp_bc, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"logística τ=0.5"</span>, ys_bc),</span>
<span id="cb24-26">        ]</span>
<span id="cb24-27">    ).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb24-28">)</span>
<span id="cb24-29"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb24-30"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Conteos:"</span>, conteos(yb_te, yp_bc))</span>
<span id="cb24-31"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(classification_report(yb_te, yp_bc, target_names<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"benigno"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"maligno"</span>], digits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb24-32">graficar_matriz(yb_te, yp_bc, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Breast cancer, τ=0.5 (positivo = maligno)"</span>)</span>
<span id="cb24-33">graficar_roc_pr(yb_te, ys_bc, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Breast cancer: prevalencia ~0.37, ROC y PR se parecen más"</span>)</span>
<span id="cb24-34">_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> graficar_umbral(yb_te, ys_bc, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Breast cancer: el cruce precisión/recall no está forzado a 0.03"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>clases (orden sklearn): [np.str_('malignant'), np.str_('benign')]   conteos [0, 1] = [212 357]
En load_breast_cancer: 0 = malignant, 1 = benign.
Para el oficio clínico la clase positiva debe ser el maligno. Se invierte y.
P(maligno) = 0.373   n = 569   p = 30

           modelo  prevalencia  exactitud  precisión  recall   F1   AUC    AP
dummy mayoritaria        0.374      0.626      0.000   0.000 0.00 0.500 0.374
  logística τ=0.5        0.374      0.971      0.984   0.938 0.96 0.998 0.996

Conteos: {'VN': 106, 'FP': 1, 'FN': 4, 'VP': 60}
              precision    recall  f1-score   support

     benigno      0.964     0.991     0.977       107
     maligno      0.984     0.938     0.960        64

    accuracy                          0.971       171
   macro avg      0.974     0.964     0.968       171
weighted avg      0.971     0.971     0.971       171
</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/12-clasificacion-metricas-evaluacion/index_files/figure-html/cell-13-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/12-clasificacion-metricas-evaluacion/index_files/figure-html/cell-13-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/12-clasificacion-metricas-evaluacion/index_files/figure-html/cell-13-output-4.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Cómo leer Breast cancer frente al fraude.</strong></p>
<ol type="1">
<li><strong>Prevalencia ~0.37.</strong> El dummy mayoritario ya no vive en 0.95. La exactitud vuelve a ser informativa <em>como complemento</em>, no como única cifra.</li>
<li><strong>FN es un maligno no alertado.</strong> En cribado se suele bajar <img src="https://latex.codecogs.com/png.latex?%5Ctau"> para subir recall, a costa de FP (biopsias de más). El veredicto no es el <img src="https://latex.codecogs.com/png.latex?F_1"> máximo.</li>
<li><strong>ROC y PR se acercan</strong> porque <img src="https://latex.codecogs.com/png.latex?%5Cpi"> no es extrema. Aun así se publican las dos.</li>
<li><strong><img src="https://latex.codecogs.com/png.latex?n_%7B%5Cmathrm%7Btest%7D%7D%5Capprox%20170">.</strong> Un recall de 0.95 son conteos chicos: un FN más mueve la cifra. No vender milímetros.</li>
</ol>
<p><strong>Preguntas de análisis.</strong></p>
<ul>
<li>¿El AUC alto autoriza a omitir la matriz? (No.)</li>
<li>Si el hospital acepta como mucho 2 FN en este test, ¿qué <img src="https://latex.codecogs.com/png.latex?%5Ctau"> de la parrilla lo cumple y a cuántos FP?</li>
<li>¿Elegirías <img src="https://latex.codecogs.com/png.latex?%5Ctau"> en esta prueba para el informe final?</li>
</ul>
</section>
<section id="caso-aplicado-reportar-un-clasificador" class="level3">
<h3 class="anchored" data-anchor-id="caso-aplicado-reportar-un-clasificador">Caso aplicado: reportar un clasificador</h3>
<p>Plantilla:</p>
<ol type="1">
<li><strong>Uso y clase positiva.</strong> Qué se alerta y qué cuesta FN vs FP.</li>
<li><strong>Prevalencia</strong> en el conjunto citado.</li>
<li><strong>Protocolo.</strong> Train/test, <img src="https://latex.codecogs.com/png.latex?%5Ctau">, si el umbral se eligió fuera de la prueba.</li>
<li><strong>Matriz</strong> y las cuatro frases (VP, FN, FP, VN).</li>
<li><strong>Métricas.</strong> Exactitud <em>junto</em> al baseline mayoritario; precisión, recall, <img src="https://latex.codecogs.com/png.latex?F_1">; AUC y AP.</li>
<li><strong>Decisión.</strong> Aceptar para un uso, rechazar para otro. Límite.</li>
</ol>
<p><strong>Los seis pasos, aplicados al fraude (etapas 1–8)</strong></p>
<ol type="1">
<li><strong>Uso.</strong> Alerta de transacción anómala. FN = fraude no visto; FP = revisión o bloqueo injusto. Dos usos posibles (bloqueo vs cola).</li>
<li><strong>Prevalencia.</strong> <img src="https://latex.codecogs.com/png.latex?%5Cpi%5Capprox%200.046"> en prueba (print etapa 1).</li>
<li><strong>Protocolo.</strong> Logística estandarizada, test 30% estratificado, <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5"> por defecto (no es el de operación).</li>
<li><strong>Matriz.</strong> Conteos de la etapa 3–4: traducir a “<img src="https://latex.codecogs.com/png.latex?a"> fraudes pescados, <img src="https://latex.codecogs.com/png.latex?b"> escapados, <img src="https://latex.codecogs.com/png.latex?c"> falsas alertas”.</li>
<li><strong>Métricas.</strong> Exactitud <img src="https://latex.codecogs.com/png.latex?%5Capprox%200.954"> <em>igualable por el dummy</em>; por eso se citan precisión, recall, <img src="https://latex.codecogs.com/png.latex?F_1">, AUC y AP (AP contra <img src="https://latex.codecogs.com/png.latex?%5Cpi">, no contra 0.5).</li>
<li><strong>Decisión.</strong> <em>A <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5"> la precisión es <img src="https://latex.codecogs.com/png.latex?1.0"> (0 FP: la lista no está sucia) y el recall es <img src="https://latex.codecogs.com/png.latex?0.218"> (43 FN). Se pueden bloquear esas 12 alertas sin molestar inocentes; el sistema no cubre el fraude. Sirve como priorizador de un puñado de casos, no como único control.</em> El dummy se rechaza pese a su exactitud.</li>
</ol>
<blockquote class="blockquote">
<p>En un test con prevalencia 4.6%, la logística a <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5"> supera al dummy en recall y <img src="https://latex.codecogs.com/png.latex?F_1">; la exactitud se cita solo contra el baseline mayoritario, no como veredicto. El AUC describe el ranking; la curva PR describe el compromiso cobertura–suciedad si se baja <img src="https://latex.codecogs.com/png.latex?%5Ctau">. A <img src="https://latex.codecogs.com/png.latex?0.5"> no hay suciedad: hay <strong>agujeros</strong>. Se recomienda revisar las pocas alertas y no tratar el modelo como único control: la mayoría del fraude no dispara. Limitación: datos sintéticos, un split, umbral no calibrado a un costo en dinero.</p>
</blockquote>
<p><strong>Breast cancer (etapa 10)</strong> se llena igual, con otra conclusión típica: prevalencia alta, FN clínico caro, exactitud ya no es farsa, y el debate pasa al <strong>umbral de cribado</strong>, no a “¿hay señal?”.</p>
</section>
<section id="errores-que-conviene-nombrar" class="level3">
<h3 class="anchored" data-anchor-id="errores-que-conviene-nombrar">Errores que conviene nombrar</h3>
<ol type="1">
<li><strong>Citar solo exactitud</strong> con clase rara o costos asimétricos.</li>
<li><strong>Olvidar la prevalencia</strong> al publicar precisión.</li>
<li><strong>Tratar <img src="https://latex.codecogs.com/png.latex?%5Ctau=0.5"> como parte del modelo</strong> y no como una decisión.</li>
<li><strong>Elegir <img src="https://latex.codecogs.com/png.latex?%5Ctau"> en la prueba</strong> y vender esas métricas.</li>
<li><strong>AUC alto = modelo desplegable.</strong> El AUC no es la cola de alertas.</li>
<li><strong><img src="https://latex.codecogs.com/png.latex?F_1"> como función de costo.</strong> No conoce FN vs FP en dinero.</li>
<li><strong>Invertir el positivo</strong> (benigno como <img src="https://latex.codecogs.com/png.latex?1">) y reportar un recall clínico al revés.</li>
<li><strong>Comparar precisión entre conjuntos con <img src="https://latex.codecogs.com/png.latex?%5Cpi"> distinta</strong> como si fuera calidad del modelo.</li>
</ol>
</section>
<section id="idea-clave" class="level3">
<h3 class="anchored" data-anchor-id="idea-clave">Idea clave</h3>
<p><strong>La métrica es una pregunta, no una medalla.</strong> Exactitud pregunta “¿cuántas filas?”. Precisión pregunta “¿la alerta es limpia?”. Recall pregunta “¿se escapó el caso que importaba?”. El clasificador aceptable es el que responde la pregunta del <em>uso</em>, no el que gana el porcentaje más redondo.</p>
</section>
<section id="síntesis" class="level3">
<h3 class="anchored" data-anchor-id="síntesis">Síntesis</h3>
<p>Se partió de un dummy con exactitud 95.4% y recall 0. La logística usó <img src="https://latex.codecogs.com/png.latex?x"> y se leyó la matriz en frases. El mismo corte sirvió para un uso y no para el otro. Mover <img src="https://latex.codecogs.com/png.latex?%5Ctau"> dibujó el compromiso. ROC y PR no contaron la misma historia bajo rareza. Los pesos y la prevalencia movieron la precisión sin “mejorar el fenómeno”. Breast cancer mostró el aparato cuando <img src="https://latex.codecogs.com/png.latex?%5Cpi"> ya no es extrema. El objeto que queda es un <strong>veredicto con matriz, <img src="https://latex.codecogs.com/png.latex?%5Cpi">, <img src="https://latex.codecogs.com/png.latex?%5Ctau"> y uso</strong>, no un accuracy.</p>
</section>
</section>
<section id="guía-rápida-qué-métrica-usar" class="level2">
<h2 class="anchored" data-anchor-id="guía-rápida-qué-métrica-usar">6. Guía rápida: ¿qué métrica usar?</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Situación</th>
<th>Qué usar</th>
<th>Por qué</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Clases y costos simétricos</td>
<td>Exactitud + matriz</td>
<td>El 97% ya no es trampa</td>
</tr>
<tr class="even">
<td>“¿La alerta es confiable?”</td>
<td>Precisión</td>
<td><img src="https://latex.codecogs.com/png.latex?P(y=1%5Cmid%20%5Chat%20y=1)"></td>
</tr>
<tr class="odd">
<td>“¿Se nos escapa el positivo?”</td>
<td>Recall</td>
<td><img src="https://latex.codecogs.com/png.latex?P(%5Chat%20y=1%5Cmid%20y=1)"></td>
</tr>
<tr class="even">
<td>Ranking de modelos, sin costos</td>
<td><img src="https://latex.codecogs.com/png.latex?F_1"></td>
<td>Castiga el extremo 0</td>
</tr>
<tr class="odd">
<td>¿Separan los scores?</td>
<td>AUC-ROC</td>
<td>Independiente de <img src="https://latex.codecogs.com/png.latex?%5Ctau"></td>
</tr>
<tr class="even">
<td>Clase rara, calidad de la cola</td>
<td>Curva PR / AP</td>
<td>El eje es la precisión</td>
</tr>
<tr class="odd">
<td>Elegir corte</td>
<td>Barrido de <img src="https://latex.codecogs.com/png.latex?%5Ctau"> + costo</td>
<td><img src="https://latex.codecogs.com/png.latex?0.5"> no es ley</td>
</tr>
<tr class="even">
<td>¿Hay señal alguna?</td>
<td>Dummy mayoritario</td>
<td>Piso de exactitud y de PR</td>
</tr>
</tbody>
</table>
<p><strong>Regla de comunicación:</strong> clase positiva, <img src="https://latex.codecogs.com/png.latex?%5Cpi">, <img src="https://latex.codecogs.com/png.latex?%5Ctau">, matriz, precisión, recall, y el uso para el que se acepta.</p>
</section>
<section id="guía-práctica-para-reportar-un-clasificador" class="level2">
<h2 class="anchored" data-anchor-id="guía-práctica-para-reportar-un-clasificador">7. Guía práctica para reportar un clasificador</h2>
<section id="paso-1-uso-positivo-costos" class="level3">
<h3 class="anchored" data-anchor-id="paso-1-uso-positivo-costos">Paso 1: uso, positivo, costos</h3>
<p>Qué se alerta; qué vale un FN frente a un FP.</p>
</section>
<section id="paso-2-pi-n-tau" class="level3">
<h3 class="anchored" data-anchor-id="paso-2-pi-n-tau">Paso 2: <img src="https://latex.codecogs.com/png.latex?%5Cpi">, <img src="https://latex.codecogs.com/png.latex?n">, <img src="https://latex.codecogs.com/png.latex?%5Ctau"></h3>
<p>Prevalencia del conjunto citado, tamaño, umbral.</p>
</section>
<section id="paso-3-matriz-y-métricas" class="level3">
<h3 class="anchored" data-anchor-id="paso-3-matriz-y-métricas">Paso 3: matriz y métricas</h3>
<p>Cuatro conteos; exactitud vs dummy; precisión, recall, <img src="https://latex.codecogs.com/png.latex?F_1">; AUC y AP.</p>
</section>
<section id="paso-4-redactar" class="level3">
<h3 class="anchored" data-anchor-id="paso-4-redactar">Paso 4: redactar</h3>
<blockquote class="blockquote">
<p>“Para <code>[uso]</code>, positivo = <code>[...]</code>, <img src="https://latex.codecogs.com/png.latex?%5Cpi="><code>[...]</code> en TEST (<img src="https://latex.codecogs.com/png.latex?n="><code>[...]</code>). Modelo <code>[...]</code>, <img src="https://latex.codecogs.com/png.latex?%5Ctau="><code>[...]</code>. Matriz: VP=<code>[...]</code>, FN=<code>[...]</code>, FP=<code>[...]</code>, VN=<code>[...]</code>. Exactitud=<code>[...]</code> (dummy=<code>[...]</code>). Precisión=<code>[...]</code>, recall=<code>[...]</code>, <img src="https://latex.codecogs.com/png.latex?F_1="><code>[...]</code>. AUC=<code>[...]</code>, AP=<code>[...]</code>. <strong>Veredicto:</strong> <code>[aceptar para… / rechazar para…]</code>. Limitación: <code>[split / τ elegido en test / π distinta en producción]</code>.”</p>
</blockquote>
<p>El fraude (etapas 1–8) y Breast cancer (etapa 10) ya llenaron esta plantilla.</p>
</section>
</section>
<section id="puente-hacia-las-siguientes-sesiones" class="level2">
<h2 class="anchored" data-anchor-id="puente-hacia-las-siguientes-sesiones">8. Puente hacia las siguientes sesiones</h2>
<p>Las métricas de esta sesión son la pérdida <img src="https://latex.codecogs.com/png.latex?L"> de un problema de <strong>clase</strong>. La validación (particiones, pliegues, no elegir <img src="https://latex.codecogs.com/png.latex?%5Ctau"> en la prueba) es el protocolo que las hace honestas: un <img src="https://latex.codecogs.com/png.latex?F_1"> de entrenamiento no vale más que un RMSE de entrenamiento. El proyecto integrador pedirá las dos cosas a la vez: un modelo y un <strong>párrafo que se atreva a rechazarlo</strong> para un uso aunque el accuracy luzca.</p>
</section>
<section id="cierre" class="level2">
<h2 class="anchored" data-anchor-id="cierre">9. Cierre</h2>
<p>Este notebook deja el criterio para no aplaudir un porcentaje:</p>
<ul>
<li>clasificación como score + umbral,</li>
<li>matriz de confusión en palabras,</li>
<li>exactitud y su baseline mayoritario,</li>
<li>precisión, recall, <img src="https://latex.codecogs.com/png.latex?F_1">,</li>
<li>ROC/AUC y la curva PR bajo rareza,</li>
<li>tres desbalances (clase, costo, prevalencia),</li>
<li>dos casos (fraude sintético, Breast cancer) con veredicto por <em>uso</em>.</li>
</ul>
<p><strong>Resultado esperado:</strong> el estudiante mira una matriz y un 95%, pregunta <img src="https://latex.codecogs.com/png.latex?%5Cpi"> y <img src="https://latex.codecogs.com/png.latex?%5Ctau">, y decide si el clasificador sirve para bloquear, para revisar o para ninguna de las dos.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>clasificacion</category>
  <category>metricas</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/basico/12-clasificacion-metricas-evaluacion/</guid>
  <pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Estadística para IA — 13. Validación y desempeño del modelo</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/</link>
  <description><![CDATA[ 




<section id="sesión-13-validación-y-desempeño-del-modelo" class="level1">
<h1>Sesión 13 — Validación y Desempeño del Modelo</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado es Científico de Datos, Arquitecto de IA, Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), consultor y docente universitario, trabaja en la intersección entre Data Science, Inteligencia Artificial, Big Data e IoT, transformando problemas reales en soluciones aplicadas.</p>
<p>De la teoría a la práctica, un problema a la vez.</p>
</section>
<section id="un-número-de-entrenamiento-no-es-un-modelo" class="level2">
<h2 class="anchored" data-anchor-id="un-número-de-entrenamiento-no-es-un-modelo">Un número de entrenamiento no es un modelo</h2>
<p>Ajustar es fácil. <strong>Decidir</strong> si el ajuste sirve es el oficio. Un RMSE de 0.04 en las mismas filas que entrenaron el modelo no afirma nada sobre el siguiente lote de usuarios. Puede ser memoria. Puede ser un modelo demasiado rígido. Puede ser un split afortunado. Puede ser que se usó el conjunto de prueba para elegir el grado y ya no es prueba.</p>
<p>Este notebook construye el aparato para <strong>medir fuera de la muestra</strong> y, sobre todo, para <strong>leer</strong> lo que sale: <strong>sobreajuste</strong>, <strong>subajuste</strong>, <strong>sesgo y varianza</strong>, <strong>train/test</strong>, <strong>validación cruzada</strong> y <strong>bootstrap</strong>. El contraste que importa es operativo: <em>el modelo que “gana” en entrenamiento es a menudo el que pierde en producción</em>. El producto de la sesión no es una librería; es un <strong>veredicto</strong> con evidencia.</p>
<p>Contexto: una curva diseñada (seno + tendencia) donde se ve el sobreajuste, y el conjunto <strong>Diabetes</strong> de scikit-learn para aplicar el protocolo a un <img src="https://latex.codecogs.com/png.latex?y"> real.</p>
<p>Electiva I — Estadística Aplicada a la Inteligencia Artificial · Módulo 4 · Sesión 13</p>
</section>
<section id="objetivos" class="level2">
<h2 class="anchored" data-anchor-id="objetivos">Objetivos</h2>
<ul>
<li>Distinguir <strong>error de entrenamiento</strong>, <strong>error de prueba</strong> y <strong>error de generalización</strong>.</li>
<li>Reconocer <strong>sobreajuste</strong> y <strong>subajuste</strong> en números <em>y</em> en la gráfica.</li>
<li>Explicar el <strong>compromiso sesgo–varianza</strong> sin convertirlo en una etiqueta vacía.</li>
<li>Partir en <strong>entrenamiento / prueba</strong> y no reutilizar la prueba para elegir el modelo.</li>
<li>Implementar <strong>validación cruzada</strong> (<img src="https://latex.codecogs.com/png.latex?k"> bloques) a mano y con scikit-learn, y leer la <em>dispersión entre pliegues</em>, no solo la media.</li>
<li>Usar <strong>bootstrap</strong> para un intervalo de la métrica, no para “inventar más datos”.</li>
<li>Aplicar un <strong>protocolo de veredicto</strong>: ¿mejor que el baseline? ¿hueco train–test? ¿error en unidades del problema? ¿estable? ¿hubo fuga?</li>
</ul>
<blockquote class="blockquote">
<p>Nota: se recomienda ejecutar las celdas en orden. Las fórmulas usan LaTeX; si no se ven renderizadas, abre el notebook en Jupyter o Colab.</p>
</blockquote>
</section>
<section id="qué-se-está-midiendo-cuando-se-dice-el-modelo-es-bueno" class="level2">
<h2 class="anchored" data-anchor-id="qué-se-está-midiendo-cuando-se-dice-el-modelo-es-bueno">1. Qué se está midiendo cuando se dice “el modelo es bueno”</h2>
<section id="tres-errores-que-no-son-el-mismo" class="level3">
<h3 class="anchored" data-anchor-id="tres-errores-que-no-son-el-mismo">1.1 Tres errores que no son el mismo</h3>
<p>Sea <img src="https://latex.codecogs.com/png.latex?L"> una pérdida (aquí, casi siempre el error cuadrático). Hay tres promedios distintos:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Nombre</th>
<th>Sobre qué filas</th>
<th>Qué afirma</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Error de entrenamiento</strong></td>
<td>Las que usó el ajuste</td>
<td>Cómo de bien <em>memorizó</em> o <em>resumió</em> esta muestra</td>
</tr>
<tr class="even">
<td><strong>Error de prueba</strong></td>
<td>Filas <strong>no</strong> usadas para ajustar <em>ni</em> para elegir complejidad</td>
<td>Estimación honesta de <img src="https://latex.codecogs.com/png.latex?L"> en datos de la misma población</td>
</tr>
<tr class="odd">
<td><strong>Error de generalización</strong></td>
<td>La población (no se observa)</td>
<td>El número que en verdad importa; se <em>estima</em>, no se ve</td>
</tr>
</tbody>
</table>
<p>El error de entrenamiento es un estadístico de las mismas observaciones que definieron <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ctheta">. Está <strong>sesgado hacia abajo</strong>. Tratarlo como desempeño es el error profesional más frecuente del curso.</p>
</section>
<section id="sobreajuste-y-subajuste" class="level3">
<h3 class="anchored" data-anchor-id="sobreajuste-y-subajuste">1.2 Sobreajuste y subajuste</h3>
<p><strong>Sobreajuste</strong> (<em>overfitting</em>): el modelo es tan flexible que captura ruido de la muestra. El error de entrenamiento baja; el de prueba sube. La curva “pasa por los puntos” y oscila entre ellos.</p>
<p><strong>Subajuste</strong> (<em>underfitting</em>): el modelo es demasiado rígido (una recta sobre un seno). Entrenamiento y prueba quedan <strong>altos y parecidos</strong>. No hay milagro de más datos que convierta una recta en un seno, salvo que se cambie la clase de modelo.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 20%">
<col style="width: 20%">
<col style="width: 20%">
<col style="width: 20%">
<col style="width: 20%">
</colgroup>
<thead>
<tr class="header">
<th>Diagnóstico</th>
<th>Train</th>
<th>Test</th>
<th>Hueco train–test</th>
<th>Lectura</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Subajuste</td>
<td>Alto</td>
<td>Alto</td>
<td>Chico</td>
<td>El modelo no puede representar <img src="https://latex.codecogs.com/png.latex?f"></td>
</tr>
<tr class="even">
<td>Ajuste razonable</td>
<td>Bajo o medio</td>
<td>Cercano al train</td>
<td>Chico</td>
<td>Candidato a veredicto</td>
</tr>
<tr class="odd">
<td>Sobreajuste</td>
<td>Muy bajo</td>
<td>Alto</td>
<td>Grande</td>
<td>Memoria, no regularidad</td>
</tr>
<tr class="even">
<td>Split ruidoso</td>
<td>Cualquiera</td>
<td>Cualquiera</td>
<td>Inestable entre semillas</td>
<td><img src="https://latex.codecogs.com/png.latex?n"> de prueba chico; no decidir aún</td>
</tr>
</tbody>
</table>
<p>“Alto” y “bajo” <strong>no son absolutos</strong>: se miden contra un <strong>baseline</strong> (predecir la media de <img src="https://latex.codecogs.com/png.latex?y">) y contra las <strong>unidades</strong> del problema (¿6 ms de RMSE es grave en latencia de 120 ms?).</p>
</section>
<section id="sesgo-y-varianza" class="level3">
<h3 class="anchored" data-anchor-id="sesgo-y-varianza">1.3 Sesgo y varianza</h3>
<p>Se imagina el experimento repetido: muchas muestras del mismo tamaño, cada una produce un <img src="https://latex.codecogs.com/png.latex?%5Chat%20f">.</p>
<ul>
<li><strong>Sesgo:</strong> <img src="https://latex.codecogs.com/png.latex?E%5B%5Chat%20f(x)%5D-f(x)">. El modelo simple se equivoca <em>siempre en la misma dirección</em>. Es subajuste sistemático.</li>
<li><strong>Varianza:</strong> cuánto <strong>cambia</strong> <img src="https://latex.codecogs.com/png.latex?%5Chat%20f"> cuando cambia la muestra. El polinomio de grado 18 dibuja un abanico: cada muestra, otra montaña rusa.</li>
</ul>
<p>El error de generalización esperado se descompone (para pérdida <img src="https://latex.codecogs.com/png.latex?L_2">, en lo esencial) en</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cunderbrace%7B%5Cmathrm%7Bsesgo%7D%5E2%7D_%7B%5Ctext%7Brigidez%7D%7D+%5Cunderbrace%7B%5Cmathrm%7Bvarianza%7D%7D_%7B%5Ctext%7Binestabilidad%7D%7D+%5Cunderbrace%7B%5Csigma%5E2%7D_%7B%5Ctext%7Bruido%20irreducible%7D%7D.%0A"></p>
<p>Bajar el sesgo (más flexibilidad) <strong>sube</strong> la varianza. No se “elimina” el compromiso: se elige un punto. La validación es el instrumento para verlo con números, no con fe.</p>
<p>El <img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2"> no se vence con un modelo más grande. Si el laboratorio inyectó ruido de desviación 0.25, un RMSE de prueba de 0.05 es, casi seguro, sobreajuste o una prueba demasiado chica.</p>
</section>
<section id="train-test" class="level3">
<h3 class="anchored" data-anchor-id="train-test">1.4 Train / test</h3>
<p>Se reserva una fracción (típicamente 20–30%) que <strong>no entra</strong> al ajuste. El resto entrena. La métrica de prueba es la primera cifra honesta.</p>
<p>Condiciones para que siga siendo honesta:</p>
<ol type="1">
<li>Las filas de prueba no se usaron para <strong>elegir</strong> el grado, el umbral ni las <em>features</em>.</li>
<li>Prueba y entrenamiento son <strong>la misma población</strong> (no un mes distinto sin decirlo).</li>
<li><img src="https://latex.codecogs.com/png.latex?n"> de prueba no es ridículo: un RMSE con 12 filas tiembla.</li>
</ol>
<p>Si se prueba un grado 1, luego 2, …, luego 20 y se <strong>elige el que ganó en test</strong>, esa cifra de test ya es un error de entrenamiento disfrazado. Eso se llama <strong>fuga de información</strong> (el investigador filtró la prueba hacia la decisión).</p>
</section>
<section id="validación-cruzada" class="level3">
<h3 class="anchored" data-anchor-id="validación-cruzada">1.5 Validación cruzada</h3>
<p>Con <img src="https://latex.codecogs.com/png.latex?n"> chico, un solo corte desperdicia datos y produce un test nervioso. La <strong>validación cruzada en <img src="https://latex.codecogs.com/png.latex?k"> pliegues</strong> (<em><img src="https://latex.codecogs.com/png.latex?k">-fold</em>):</p>
<ol type="1">
<li>Parte en <img src="https://latex.codecogs.com/png.latex?k"> bloques (p.&nbsp;ej. <img src="https://latex.codecogs.com/png.latex?k=5"> o <img src="https://latex.codecogs.com/png.latex?10">).</li>
<li>Entrena en <img src="https://latex.codecogs.com/png.latex?k-1">, evalúa en el que queda.</li>
<li>Rota, <img src="https://latex.codecogs.com/png.latex?k"> veces.</li>
<li>Reporta <strong>media y desviación</strong> de las <img src="https://latex.codecogs.com/png.latex?k"> métricas.</li>
</ol>
<p>La desviación entre pliegues es parte del resultado. Una media de RMSE <img src="https://latex.codecogs.com/png.latex?=8.1"> con pliegues <img src="https://latex.codecogs.com/png.latex?%5C%7B4,%5C,7,%5C,8,%5C,18,%5C,6%5C%7D"> no es “8.1”: es “no sabemos aún; un bloque se fue a 18”.</p>
<p>Elegir hiperparámetros (el grado del polinomio) se hace <strong>con CV en el conjunto de entrenamiento</strong>. El test final se toca <strong>una vez</strong>, al final.</p>
</section>
<section id="bootstrap" class="level3">
<h3 class="anchored" data-anchor-id="bootstrap">1.6 Bootstrap</h3>
<p>El <strong>bootstrap</strong> remuestrea <em>con reemplazo</em> la muestra (o las filas de prueba) muchas veces y recalcula el estadístico. Produce una <strong>distribución empírica</strong> del RMSE (o de <img src="https://latex.codecogs.com/png.latex?R%5E2">): un histograma y un intervalo, p.&nbsp;ej. los percentiles 2.5 y 97.5.</p>
<p>No crea observaciones nuevas del fenómeno. No sustituye un test no visto. Estima <strong>qué tan precisa es la métrica</strong> dada esta muestra. Un modelo con RMSE 7.0 y bootstrap <img src="https://latex.codecogs.com/png.latex?(6.6,%5C,7.5)"> es un número estable; otro con 7.0 y <img src="https://latex.codecogs.com/png.latex?(3.1,%5C,14.8)"> no autoriza un despliegue.</p>
</section>
<section id="protocolo-el-modelo-es-aceptable" class="level3">
<h3 class="anchored" data-anchor-id="protocolo-el-modelo-es-aceptable">1.7 Protocolo: ¿el modelo es aceptable?</h3>
<p>Seis preguntas, en este orden. Si alguna falla, el veredicto no es “sí” aunque el <img src="https://latex.codecogs.com/png.latex?R%5E2"> de train sea 0.99.</p>
<ol type="1">
<li><strong>¿Respecto a qué?</strong> ¿Gana al baseline (media de <img src="https://latex.codecogs.com/png.latex?y">, modelo actual en producción, regla de negocio)?</li>
<li><strong>¿En qué conjunto?</strong> El número que se cita es de <strong>prueba</strong> o de <strong>CV</strong>, no de entrenamiento.</li>
<li><strong>¿El hueco train–test es razonable?</strong> Un train 0.99 y un test 0.40 es sobreajuste, no un “buen modelo con mala suerte”.</li>
<li><strong>¿El error en unidades del problema es tolerable?</strong> RMSE 12 ms en latencia de 80 ms no es el mismo juicio que RMSE 12 en una escala de 0 a 10 000.</li>
<li><strong>¿Es estable?</strong> Dispersión de pliegues, intervalo bootstrap, otro <code>random_state</code>.</li>
<li><strong>¿Hubo fuga?</strong> ¿Se eligió el modelo mirando la prueba?</li>
</ol>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Pregunta</th>
<th>Herramienta</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>¿Memorizó la muestra?</td>
<td>Train vs test / residuos del test</td>
</tr>
<tr class="even">
<td>¿Es demasiado rígido?</td>
<td>Train y test altos; gráfico del ajuste</td>
</tr>
<tr class="odd">
<td>¿El split miente?</td>
<td>Varios splits o <img src="https://latex.codecogs.com/png.latex?k">-fold</td>
</tr>
<tr class="even">
<td>¿Qué complejidad elegir?</td>
<td>CV <em>dentro</em> del train</td>
</tr>
<tr class="odd">
<td>¿Cuánto tiembla la métrica?</td>
<td>Bootstrap o <img src="https://latex.codecogs.com/png.latex?%5Csigma"> de pliegues</td>
</tr>
<tr class="even">
<td>¿Se despliega?</td>
<td>Las seis preguntas, no un <img src="https://latex.codecogs.com/png.latex?p"> ni un <img src="https://latex.codecogs.com/png.latex?R%5E2"></td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="por-qué-importa-en-ia-y-machine-learning" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-importa-en-ia-y-machine-learning">2. Por qué importa en IA y Machine Learning</h2>
<p>Entrenar hasta <img src="https://latex.codecogs.com/png.latex?R%5E2=1"> en el notebook es un botón. El costo está en <strong>creerse</strong> ese botón.</p>
<ul>
<li>Un ranking de modelos hecho sobre el conjunto de prueba <strong>elige al que más se adaptó a esas filas</strong>. En la siguiente semana deja de ganar.</li>
<li>Las redes y los polinomios de grado alto son máquinas de varianza: sin validación, el sobreajuste es el estado por defecto.</li>
<li>En producto, “el modelo es bueno” es una <strong>decisión de riesgo</strong>: falso despliegue (tipo I de negocio) frente a matar un modelo útil por un split miserable (tipo II).</li>
<li>El baseline obliga a la humildad: si el lineal no gana a predecir la media, no hay <em>feature</em> que esté trabajando.</li>
</ul>
<p><strong>Idea central:</strong> validar no es imprimir <code>score</code>. Es <strong>argumentar</strong>, con conjuntos distintos y con incertidumbre, que el error será aceptable <em>la próxima vez</em>.</p>
</section>
<section id="flujo-recomendado-de-los-números-al-veredicto" class="level2">
<h2 class="anchored" data-anchor-id="flujo-recomendado-de-los-números-al-veredicto">3. Flujo recomendado — de los números al veredicto</h2>
<ol type="1">
<li><strong>Fijar la pérdida y el baseline.</strong> RMSE (o la métrica del negocio) y el predictor ingenuo.</li>
<li><strong>Reservar una prueba</strong> y no tocarla. El resto es entrenamiento.</li>
<li><strong>Ajustar candidatos solo en entrenamiento.</strong> Complejidad distinta (grados, regularización).</li>
<li><strong>Elegir con CV</strong> (media <em>y</em> dispersión de pliegues).</li>
<li><strong>Medir una vez en prueba.</strong> Ese es el número que se cita.</li>
<li><strong>Cuantificar temblor</strong> (bootstrap o <img src="https://latex.codecogs.com/png.latex?%5Csigma"> de CV) y <strong>traducir a unidades</strong>.</li>
<li><strong>Veredicto</strong> con las seis preguntas. Escribir límites (población, rango de <img src="https://latex.codecogs.com/png.latex?x">, <img src="https://latex.codecogs.com/png.latex?n">).</li>
</ol>
<p><strong>Criterio general:</strong> un modelo sin baseline, sin conjunto no visto y sin intervalo de la métrica no se puede aceptar. Solo se puede <em>creer</em>.</p>
</section>
<section id="preparar-el-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparar-el-entorno">4. Preparar el entorno</h2>
<div id="entorno-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:29.867966Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:29.867559Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:32.052055Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:32.051501Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb1-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Python:"</span>, sys.version.split()[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LinearRegression</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.dummy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> DummyRegressor</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PolynomialFeatures, StandardScaler</span>
<span id="cb1-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.pipeline <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Pipeline</span>
<span id="cb1-11"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split, KFold, cross_val_score, learning_curve</span>
<span id="cb1-12"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> mean_squared_error, r2_score</span>
<span id="cb1-13"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.datasets <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> load_diabetes</span>
<span id="cb1-14"></span>
<span id="cb1-15">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-16"></span>
<span id="cb1-17">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"figure.figsize"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-18">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"axes.grid"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb1-19">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grid.alpha"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span></span>
<span id="cb1-20"></span>
<span id="cb1-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Entorno listo: numpy, pandas, matplotlib, sklearn."</span>)</span>
<span id="cb1-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sklearn:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">__import__</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sklearn"</span>).__version__)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Python: 3.13.9
Entorno listo: numpy, pandas, matplotlib, sklearn.
sklearn: 1.8.0</code></pre>
</div>
</div>
<section id="funciones-de-ajuste-métricas-y-gráficos-una-sola-vez" class="level3">
<h3 class="anchored" data-anchor-id="funciones-de-ajuste-métricas-y-gráficos-una-sola-vez">Funciones de ajuste, métricas y gráficos (una sola vez)</h3>
<div id="viz-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:32.054064Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:32.053745Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:32.063899Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:32.063331Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> rmse(y_true, y_pred):</span>
<span id="cb3-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.sqrt(mean_squared_error(y_true, y_pred)))</span>
<span id="cb3-3"></span>
<span id="cb3-4"></span>
<span id="cb3-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> ficha(y_true, y_pred, etiqueta):</span>
<span id="cb3-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb3-7">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"modelo"</span>: etiqueta,</span>
<span id="cb3-8">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE"</span>: rmse(y_true, y_pred),</span>
<span id="cb3-9">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MSE"</span>: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(mean_squared_error(y_true, y_pred)),</span>
<span id="cb3-10">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R2"</span>: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(r2_score(y_true, y_pred)),</span>
<span id="cb3-11">    }</span>
<span id="cb3-12"></span>
<span id="cb3-13"></span>
<span id="cb3-14"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> pipe_poli(grado):</span>
<span id="cb3-15">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Pipeline(</span>
<span id="cb3-16">        [</span>
<span id="cb3-17">            (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"esc"</span>, StandardScaler()),</span>
<span id="cb3-18">            (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"poli"</span>, PolynomialFeatures(grado, include_bias<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)),</span>
<span id="cb3-19">            (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lin"</span>, LinearRegression(fit_intercept<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)),</span>
<span id="cb3-20">        ]</span>
<span id="cb3-21">    )</span>
<span id="cb3-22"></span>
<span id="cb3-23"></span>
<span id="cb3-24"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> generar_curva(n, sigma<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.28</span>, seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>):</span>
<span id="cb3-25">    r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(seed)</span>
<span id="cb3-26">    x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sort(r.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n))</span>
<span id="cb3-27">    f <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sin(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x</span>
<span id="cb3-28">    y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> f <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> r.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, sigma, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb3-29">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> x, y, f</span>
<span id="cb3-30"></span>
<span id="cb3-31"></span>
<span id="cb3-32"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_ajustes(x, y, f, modelos, titulo):</span>
<span id="cb3-33">    xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>)</span>
<span id="cb3-34">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.5</span>))</span>
<span id="cb3-35">    ax.scatter(x, y, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">22</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.65</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"muestra"</span>, zorder<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb3-36">    ax.plot(xs, np.sin(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xs) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xs, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.25"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"f real (laboratorio)"</span>)</span>
<span id="cb3-37">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nombre, m <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> modelos.items():</span>
<span id="cb3-38">        ax.plot(xs, m.predict(xs.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)), label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>nombre, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb3-39">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>)</span>
<span id="cb3-40">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>)</span>
<span id="cb3-41">    ax.set_title(titulo)</span>
<span id="cb3-42">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"upper left"</span>)</span>
<span id="cb3-43">    plt.tight_layout()</span>
<span id="cb3-44">    plt.show()</span>
<span id="cb3-45"></span>
<span id="cb3-46"></span>
<span id="cb3-47"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_barras_train_test(filas, titulo):</span>
<span id="cb3-48">    df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(filas)</span>
<span id="cb3-49">    x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(df))</span>
<span id="cb3-50">    w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.38</span></span>
<span id="cb3-51">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>))</span>
<span id="cb3-52">    ax.bar(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE_train"</span>], w, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"entrenamiento"</span>)</span>
<span id="cb3-53">    ax.bar(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE_test"</span>], w, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prueba"</span>)</span>
<span id="cb3-54">    ax.set_xticks(x, df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"modelo"</span>])</span>
<span id="cb3-55">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE"</span>)</span>
<span id="cb3-56">    ax.set_title(titulo)</span>
<span id="cb3-57">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-58">    plt.tight_layout()</span>
<span id="cb3-59">    plt.show()</span>
<span id="cb3-60"></span>
<span id="cb3-61"></span>
<span id="cb3-62"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_abanico(xs, curvas, f_xs, titulo, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>):</span>
<span id="cb3-63">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.3</span>))</span>
<span id="cb3-64">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> c <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> curvas:</span>
<span id="cb3-65">        ax.plot(xs, c, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb3-66">    ax.plot(xs, f_xs, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.15"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"f real"</span>)</span>
<span id="cb3-67">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>)</span>
<span id="cb3-68">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ŷ"</span>)</span>
<span id="cb3-69">    ax.set_title(titulo)</span>
<span id="cb3-70">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-71">    plt.tight_layout()</span>
<span id="cb3-72">    plt.show()</span>
<span id="cb3-73"></span>
<span id="cb3-74"></span>
<span id="cb3-75"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_cv_grados(grados, medias, desv, titulo):</span>
<span id="cb3-76">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.2</span>))</span>
<span id="cb3-77">    ax.errorbar(grados, medias, yerr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>desv, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>, capsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb3-78">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grado del polinomio"</span>)</span>
<span id="cb3-79">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE de validación cruzada"</span>)</span>
<span id="cb3-80">    ax.set_title(titulo)</span>
<span id="cb3-81">    plt.tight_layout()</span>
<span id="cb3-82">    plt.show()</span>
<span id="cb3-83"></span>
<span id="cb3-84"></span>
<span id="cb3-85"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_hist_bootstrap(valores, puntual, titulo):</span>
<span id="cb3-86">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.1</span>))</span>
<span id="cb3-87">    ax.hist(valores, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.85</span>)</span>
<span id="cb3-88">    ax.axvline(puntual, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"RMSE prueba = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>puntual<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-89">    lo, hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.percentile(valores, [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">97.5</span>])</span>
<span id="cb3-90">    ax.axvline(lo, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">":"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"IC 95% bootstrap [</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>lo<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>hi<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">]"</span>)</span>
<span id="cb3-91">    ax.axvline(hi, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">":"</span>)</span>
<span id="cb3-92">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE"</span>)</span>
<span id="cb3-93">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"frecuencia"</span>)</span>
<span id="cb3-94">    ax.set_title(titulo)</span>
<span id="cb3-95">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-96">    plt.tight_layout()</span>
<span id="cb3-97">    plt.show()</span>
<span id="cb3-98">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> lo, hi</span></code></pre></div></div>
</div>
</section>
</section>
<section id="desarrollo-por-etapas" class="level2">
<h2 class="anchored" data-anchor-id="desarrollo-por-etapas">5. Desarrollo por etapas</h2>
<p>Primero una curva con <img src="https://latex.codecogs.com/png.latex?f"> conocida: se <em>ve</em> el sobreajuste. Cada tabla se lee con el protocolo. Al final, Diabetes: <img src="https://latex.codecogs.com/png.latex?f"> ya no se conoce y hay que <strong>decidir</strong>.</p>
<section id="etapa-1-sin-baseline-no-hay-bueno" class="level3">
<h3 class="anchored" data-anchor-id="etapa-1-sin-baseline-no-hay-bueno">Etapa 1: Sin baseline no hay “bueno”</h3>
<p>Se genera <img src="https://latex.codecogs.com/png.latex?n=70"> puntos</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ay=%5Csin(1.2x)+0.12x+%5Cvarepsilon,%5Cqquad%20%5Cvarepsilon%5Csim%5Cmathcal%20N(0,0.28%5E2),%5Cquad%20x%5Cin%5B0,8%5D.%0A"></p>
<p>El predictor más corto: <strong>ignorar <img src="https://latex.codecogs.com/png.latex?x"></strong> y devolver <img src="https://latex.codecogs.com/png.latex?%5Cbar%20y"> del entrenamiento (<code>DummyRegressor</code>). Todo modelo que se tome en serio debe <strong>ganar</strong> a este número en prueba. Si no gana, las <em>features</em> no están trabajando o el split es un accidente.</p>
<div id="e1-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:32.065527Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:32.065344Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:32.076860Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:32.076231Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">x, y, f <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> generar_curva(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">70</span>, seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb4-2">x_tr, x_te, y_tr, y_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(x, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb4-3"></span>
<span id="cb4-4">dummy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DummyRegressor(strategy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>)</span>
<span id="cb4-5">dummy.fit(x_tr.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), y_tr)</span>
<span id="cb4-6"></span>
<span id="cb4-7">base_tr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ficha(y_tr, dummy.predict(x_tr.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"baseline (media) / train"</span>)</span>
<span id="cb4-8">base_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ficha(y_te, dummy.predict(x_te.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"baseline (media) / test"</span>)</span>
<span id="cb4-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame([base_tr, base_te]).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb4-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb4-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"σ del laboratorio = 0.28. El baseline no usa x: su RMSE de prueba es, más o menos, la DE de y."</span>)</span>
<span id="cb4-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"DE de y (toda la muestra) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>                  modelo  RMSE   MSE   R2
baseline (media) / train 0.838 0.703  0.0
 baseline (media) / test 0.804 0.647 -0.0

σ del laboratorio = 0.28. El baseline no usa x: su RMSE de prueba es, más o menos, la DE de y.
DE de y (toda la muestra) = 0.832</code></pre>
</div>
</div>
<p><strong>Cómo leer esta tabla.</strong> El <img src="https://latex.codecogs.com/png.latex?R%5E2"> del baseline en entrenamiento es <img src="https://latex.codecogs.com/png.latex?0"> por construcción (predecir la media). En prueba puede ser negativo: significa <em>peor que predecir la media de la prueba</em>. Eso no es un bug; es la métrica diciendo “esta regla no generaliza ni el centro”.</p>
<p><strong>Qué no se concluye.</strong> Todavía no hay modelo. Hay un <strong>piso de referencia</strong>. A partir de aquí, “bueno” quiere decir <em>mejor que esta fila, en prueba, por un margen que importe</em>.</p>
<p><strong>Veredicto parcial.</strong> El baseline está listo. Quien reporte un modelo sin esta fila no puede afirmar mejora.</p>
</section>
<section id="etapa-2-el-espejismo-del-error-de-entrenamiento" class="level3">
<h3 class="anchored" data-anchor-id="etapa-2-el-espejismo-del-error-de-entrenamiento">Etapa 2: El espejismo del error de entrenamiento</h3>
<p>Se ajustan tres polinomios <strong>solo</strong> en entrenamiento: grado 1 (rígido), grado 4 (flexible y razonable para un seno suave), grado 16 (muy flexible). Se imprime <strong>únicamente</strong> el RMSE de entrenamiento. Es el número que tienta a desplegar.</p>
<div id="e2-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:32.079124Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:32.078825Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:32.094954Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:32.093960Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">grados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>]</span>
<span id="cb6-2">modelos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {}</span>
<span id="cb6-3">solo_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb6-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> grados:</span>
<span id="cb6-5">    m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_poli(g)</span>
<span id="cb6-6">    m.fit(x_tr.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), y_tr)</span>
<span id="cb6-7">    modelos[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"grado </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>g<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> m</span>
<span id="cb6-8">    solo_train.append(ficha(y_tr, m.predict(x_tr.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)), <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"grado </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>g<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>))</span>
<span id="cb6-9"></span>
<span id="cb6-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame(solo_train).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb6-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb6-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Si el criterio fuera 'el train más bajo gana', el ganador es el grado 16."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>  modelo  RMSE   MSE    R2
 grado 1 0.742 0.550 0.217
 grado 4 0.289 0.084 0.881
grado 16 0.159 0.025 0.964

Si el criterio fuera 'el train más bajo gana', el ganador es el grado 16.</code></pre>
</div>
</div>
<p><strong>Cómo leer esta tabla.</strong> El grado 16 <em>tiene</em> que ganar en train: tiene coeficientes de sobra para pasar cerca de cada punto. El grado 1 <em>tiene</em> que perder: una recta no es un seno.</p>
<p><strong>Qué no se concluye.</strong> Que el 16 sea el mejor modelo. Todavía no se miró ninguna fila no usada. Esta tabla, sola, es publicidad.</p>
<p><strong>Pregunta de análisis.</strong> Si solo leyeras la columna RMSE de train, ¿qué modelo elegirías? Anótalo. La etapa 3 existe para contradecirte.</p>
</section>
<section id="etapa-3-el-primer-número-honesto-la-prueba" class="level3">
<h3 class="anchored" data-anchor-id="etapa-3-el-primer-número-honesto-la-prueba">Etapa 3: El primer número honesto — la prueba</h3>
<p>Las mismas tres rectas/curvas, evaluadas en el <strong>35% que no entrenó</strong>.</p>
<div id="e3-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:32.096536Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:32.096364Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:32.562761Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:32.561724Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">filas_tt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb8-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> grados:</span>
<span id="cb8-3">    m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modelos[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"grado </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>g<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>]</span>
<span id="cb8-4">    filas_tt.append(</span>
<span id="cb8-5">        {</span>
<span id="cb8-6">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"modelo"</span>: <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"grado </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>g<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>,</span>
<span id="cb8-7">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE_train"</span>: rmse(y_tr, m.predict(x_tr.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))),</span>
<span id="cb8-8">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE_test"</span>: rmse(y_te, m.predict(x_te.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))),</span>
<span id="cb8-9">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R2_train"</span>: r2_score(y_tr, m.predict(x_tr.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))),</span>
<span id="cb8-10">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R2_test"</span>: r2_score(y_te, m.predict(x_te.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))),</span>
<span id="cb8-11">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hueco"</span>: rmse(y_te, m.predict(x_te.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> rmse(y_tr, m.predict(x_tr.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))),</span>
<span id="cb8-12">        }</span>
<span id="cb8-13">    )</span>
<span id="cb8-14">filas_tt.append(</span>
<span id="cb8-15">    {</span>
<span id="cb8-16">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"modelo"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"baseline"</span>,</span>
<span id="cb8-17">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE_train"</span>: base_tr[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE"</span>],</span>
<span id="cb8-18">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE_test"</span>: base_te[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE"</span>],</span>
<span id="cb8-19">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R2_train"</span>: base_tr[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R2"</span>],</span>
<span id="cb8-20">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R2_test"</span>: base_te[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R2"</span>],</span>
<span id="cb8-21">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hueco"</span>: base_te[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> base_tr[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE"</span>],</span>
<span id="cb8-22">    }</span>
<span id="cb8-23">)</span>
<span id="cb8-24">tab_tt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(filas_tt)</span>
<span id="cb8-25"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(tab_tt.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb8-26"></span>
<span id="cb8-27">graficar_barras_train_test(filas_tt, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"El ganador de entrenamiento no es el ganador de prueba"</span>)</span>
<span id="cb8-28">graficar_ajustes(x_tr, y_tr, f, modelos, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ajustes sobre el entrenamiento (la prueba no se dibuja aquí)"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>  modelo  RMSE_train  RMSE_test  R2_train  R2_test  hueco
 grado 1       0.742      0.831     0.217   -0.069  0.090
 grado 4       0.289      0.294     0.881    0.867  0.004
grado 16       0.159      0.363     0.964    0.797  0.203
baseline       0.838      0.804     0.000   -0.000 -0.034</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/index_files/figure-html/cell-6-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/index_files/figure-html/cell-6-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Cómo leer esta tabla.</strong> Tres columnas deciden, no una:</p>
<ol type="1">
<li><strong>RMSE_test vs baseline.</strong> Si no gana, se descarta.</li>
<li><strong>Hueco train–test.</strong> Grande y test peor <img src="https://latex.codecogs.com/png.latex?%5CRightarrow"> sobreajuste. Ambos altos y hueco chico <img src="https://latex.codecogs.com/png.latex?%5CRightarrow"> subajuste.</li>
<li><strong>Proximidad a <img src="https://latex.codecogs.com/png.latex?%5Csigma=0.28">.</strong> Un test <em>mucho</em> menor que el ruido del laboratorio es sospechoso (poca prueba, o se evaluó mal).</li>
</ol>
<p><strong>Qué no se concluye aún.</strong> Que el grado 4 sea “el” modelo de la población: es <em>un</em> split. La etapa 6 muestra que ese RMSE_test se mueve al cambiar la semilla.</p>
<p><strong>Veredicto parcial.</strong> El grado 16 <strong>se rechaza</strong> por el hueco train–test (aquí RMSE 0.16 frente a 0.36) aunque el <img src="https://latex.codecogs.com/png.latex?R%5E2"> de prueba aún se vea alto: memorizó el train. El grado 1 gana al baseline por poco o queda corto: <strong>subajuste</strong>. El grado 4 es el candidato. Todavía no se despliega: falta estabilidad.</p>
</section>
<section id="etapa-4-ver-el-diagnóstico-no-solo-la-tabla" class="level3">
<h3 class="anchored" data-anchor-id="etapa-4-ver-el-diagnóstico-no-solo-la-tabla">Etapa 4: Ver el diagnóstico, no solo la tabla</h3>
<p>El gráfico de la etapa 3 ya muestra las tres curvas sobre el train. Aquí se fuerza la lectura geométrica: <em>dónde</em> falla cada uno. Un veredicto que no puede señalar el gráfico es un veredicto de catálogo.</p>
<div id="e4-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:32.564684Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:32.564402Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:32.913539Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:32.912645Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>)</span>
<span id="cb10-2">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">11.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.6</span>), sharey<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb10-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax, g, tit <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(</span>
<span id="cb10-4">    axes,</span>
<span id="cb10-5">    [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>],</span>
<span id="cb10-6">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado 1 — rígido"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado 4 — sigue a f"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado 16 — memoriza"</span>],</span>
<span id="cb10-7">):</span>
<span id="cb10-8">    ax.scatter(x_tr, y_tr, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"train"</span>)</span>
<span id="cb10-9">    ax.scatter(x_te, y_te, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.85</span>, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"s"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"test"</span>)</span>
<span id="cb10-10">    ax.plot(xs, np.sin(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xs) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xs, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>)</span>
<span id="cb10-11">    ax.plot(xs, modelos[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"grado </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>g<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>].predict(xs.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>)</span>
<span id="cb10-12">    ax.set_title(tit, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb10-13">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>)</span>
<span id="cb10-14">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>)</span>
<span id="cb10-15">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"upper left"</span>)</span>
<span id="cb10-16">plt.tight_layout()</span>
<span id="cb10-17">plt.show()</span>
<span id="cb10-18"></span>
<span id="cb10-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Puntos cuadrados = prueba. Si la curva los deja fuera y persigue a los redondos, hay sobreajuste."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/index_files/figure-html/cell-7-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Puntos cuadrados = prueba. Si la curva los deja fuera y persigue a los redondos, hay sobreajuste.</code></pre>
</div>
</div>
<p><strong>Cómo leer las tres viñetas.</strong></p>
<ul>
<li><strong>Izquierda:</strong> la recta corta el seno. Train y test se equivocan <em>en las mismas zonas</em> (crestas y valles). Sesgo.</li>
<li><strong>Centro:</strong> la curva sigue a <img src="https://latex.codecogs.com/png.latex?f"> sin perseguir cada residuo. Los cuadrados (test) no quedan sistemáticamente fuera.</li>
<li><strong>Derecha:</strong> interpola el train y <strong>oscila</strong>. Los cuadrados caen donde la oscilación inventó un valle que <img src="https://latex.codecogs.com/png.latex?f"> no tiene. Varianza.</li>
</ul>
<p><strong>Pregunta de análisis.</strong> Si te dieran solo el panel derecho y el <img src="https://latex.codecogs.com/png.latex?R%5E2"> de train, ¿firmarías el modelo? ¿Qué evidencia te falta?</p>
</section>
<section id="etapa-5-sesgo-y-varianza-se-ven-al-repetir-la-muestra" class="level3">
<h3 class="anchored" data-anchor-id="etapa-5-sesgo-y-varianza-se-ven-al-repetir-la-muestra">Etapa 5: Sesgo y varianza se <em>ven</em> al repetir la muestra</h3>
<p>Se generan <img src="https://latex.codecogs.com/png.latex?60"> muestras de <img src="https://latex.codecogs.com/png.latex?n=28"> (chico a propósito). En cada una se ajusta grado 1 y <strong>grado 16</strong> (el mismo flexible de las etapas 2–4). Se dibujan las <img src="https://latex.codecogs.com/png.latex?60"> curvas. Las predicciones del 16 se recortan a <img src="https://latex.codecogs.com/png.latex?%5B-3,5%5D">: con <img src="https://latex.codecogs.com/png.latex?n"> chico el polinomio se dispara; el recorte evita un eje en millones y deja ver el abanico. El laboratorio conoce <img src="https://latex.codecogs.com/png.latex?f">.</p>
<div id="e5-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:32.915983Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:32.915689Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:33.879609Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:33.878797Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">160</span>)</span>
<span id="cb12-2">f_xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sin(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xs) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> xs</span>
<span id="cb12-3">curvas_1, curvas_hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [], []</span>
<span id="cb12-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>):</span>
<span id="cb12-5">    xi, yi, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> generar_curva(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">28</span>, seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> i)</span>
<span id="cb12-6">    m1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_poli(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>).fit(xi.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), yi)</span>
<span id="cb12-7">    m_hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_poli(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>).fit(xi.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), yi)</span>
<span id="cb12-8">    curvas_1.append(m1.predict(xs.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)))</span>
<span id="cb12-9">    curvas_hi.append(np.clip(m_hi.predict(xs.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)), <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb12-10"></span>
<span id="cb12-11">graficar_abanico(xs, curvas_1, f_xs, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado 1: poco abanico, lejos de f (sesgo)"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span>)</span>
<span id="cb12-12">graficar_abanico(xs, curvas_hi, f_xs, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado 16: cada muestra, otra curva (varianza; n=28; recorte [-3, 5])"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>)</span>
<span id="cb12-13"></span>
<span id="cb12-14">sesgo2_1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean((np.mean(curvas_1, axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> f_xs) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb12-15">var_1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean(np.var(curvas_1, axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span>
<span id="cb12-16">sesgo2_hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean((np.mean(curvas_hi, axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> f_xs) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb12-17">var_hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean(np.var(curvas_hi, axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span>
<span id="cb12-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado 1:    sesgo² medio ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(sesgo2_1, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  varianza media ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(var_1, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb12-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado 16:   sesgo² medio ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(sesgo2_hi, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  varianza media ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(var_hi, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb12-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"El 16 se pega más a f en promedio (sesgo baja) y se desordena entre muestras (varianza sube)."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/index_files/figure-html/cell-8-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/index_files/figure-html/cell-8-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Grado 1:    sesgo² medio = 0.447   varianza media = 0.029
Grado 16:   sesgo² medio = 0.024   varianza media = 2.01
El 16 se pega más a f en promedio (sesgo baja) y se desordena entre muestras (varianza sube).</code></pre>
</div>
</div>
<p><strong>Cómo leer los abanicos.</strong> El de la izquierda es una cinta estrecha que <strong>no cubre</strong> las crestas de <img src="https://latex.codecogs.com/png.latex?f">: se equivoca siempre igual. El de la derecha cubre <img src="https://latex.codecogs.com/png.latex?f"> <em>a veces</em> y se dispara en los extremos: cada muestra manda. Eso <em>es</em> el compromiso.</p>
<p><strong>Qué no se concluye.</strong> Que “hay que quedarse en el medio” por estética. El punto se elige con CV (etapa 8), no con el dibujo solo. El dibujo enseña <em>por qué</em> el CV va a preferir un grado moderado cuando <img src="https://latex.codecogs.com/png.latex?n"> es chico.</p>
<p><strong>Veredicto parcial.</strong> Flexibilidad no es calidad. Calidad es sesgo y varianza <em>conjuntos</em> más <img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2">.</p>
</section>
<section id="etapa-6-un-solo-traintest-tiembla" class="level3">
<h3 class="anchored" data-anchor-id="etapa-6-un-solo-traintest-tiembla">Etapa 6: Un solo train/test tiembla</h3>
<p>El RMSE de prueba del grado 4, con <strong>25 cortes distintos</strong> (misma <img src="https://latex.codecogs.com/png.latex?n">, otras filas). Si el veredicto cambia de un corte a otro, <strong>un</strong> <code>train_test_split</code> no basta.</p>
<div id="e6-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:33.883418Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:33.883077Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:34.186632Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:34.185847Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">rmses_split <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb14-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> seed <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>):</span>
<span id="cb14-3">    xa, xb, ya, yb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(x, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>seed)</span>
<span id="cb14-4">    m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_poli(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>).fit(xa.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), ya)</span>
<span id="cb14-5">    rmses_split.append(rmse(yb, m.predict(xb.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))))</span>
<span id="cb14-6">rmses_split <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(rmses_split)</span>
<span id="cb14-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE test (grado 4) en 25 splits"</span>)</span>
<span id="cb14-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  media ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmses_split.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  DE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmses_split.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb14-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  min  ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmses_split.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  max ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmses_split.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb14-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  rango ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmses_split.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> rmses_split.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb14-11"></span>
<span id="cb14-12">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.8</span>))</span>
<span id="cb14-13">ax.plot(rmses_split, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"none"</span>)</span>
<span id="cb14-14">ax.axhline(rmses_split.mean(), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"media entre splits"</span>)</span>
<span id="cb14-15">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"semilla del split"</span>)</span>
<span id="cb14-16">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE de prueba"</span>)</span>
<span id="cb14-17">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"El mismo modelo, 25 pruebas distintas: el número se mueve"</span>)</span>
<span id="cb14-18">ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb14-19">plt.tight_layout()</span>
<span id="cb14-20">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>RMSE test (grado 4) en 25 splits
  media = 0.358   DE = 0.116
  min  = 0.261   max = 0.809
  rango = 0.548</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/index_files/figure-html/cell-9-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Cómo leer el gráfico.</strong> Cada punto es un “RMSE de test” publicable si uno se queda con una semilla. La vertical entre el mínimo y el máximo es <strong>incertidumbre del protocolo</strong>, no del fenómeno. Con <img src="https://latex.codecogs.com/png.latex?n"> de prueba ~25, esa banda es ancha.</p>
<p><strong>Qué no se concluye.</strong> Que train/test “no sirve”. Sirve como <em>una</em> medición. No sirve como <em>la</em> medición si de ella depende un despliegue.</p>
<p><strong>Veredicto parcial.</strong> Hace falta agregar pliegues (CV) o declarar un intervalo. El punto suelto de la etapa 3 queda degradado a “orden de magnitud”.</p>
</section>
<section id="etapa-7-validación-cruzada-a-mano-y-con-scikit-learn" class="level3">
<h3 class="anchored" data-anchor-id="etapa-7-validación-cruzada-a-mano-y-con-scikit-learn">Etapa 7: Validación cruzada a mano y con scikit-learn</h3>
<p><img src="https://latex.codecogs.com/png.latex?k=5">. En cada pliegue se entrena en 4/5 y se mide RMSE en 1/5. Se implementa el bucle; después se contrasta con <code>cross_val_score</code>. Las dos vías deben coincidir (misma partición).</p>
<div id="e7-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:34.189045Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:34.188790Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:34.299452Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:34.298699Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> rmse_kfold(grado, X, y, k<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>):</span>
<span id="cb16-2">    kf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KFold(n_splits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>seed)</span>
<span id="cb16-3">    puntos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb16-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> tr, te <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> kf.split(X):</span>
<span id="cb16-5">        m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_poli(grado).fit(X[tr], y[tr])</span>
<span id="cb16-6">        puntos.append(rmse(y[te], m.predict(X[te])))</span>
<span id="cb16-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.array(puntos)</span>
<span id="cb16-8"></span>
<span id="cb16-9"></span>
<span id="cb16-10">X_all <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> x.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb16-11">manual <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {g: rmse_kfold(g, X_all, y, k<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> grados}</span>
<span id="cb16-12"></span>
<span id="cb16-13">kf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KFold(n_splits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb16-14">sk <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {}</span>
<span id="cb16-15"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> grados:</span>
<span id="cb16-16">    scores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>cross_val_score(</span>
<span id="cb16-17">        pipe_poli(g), X_all, y, cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>kf, scoring<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"neg_root_mean_squared_error"</span></span>
<span id="cb16-18">    )</span>
<span id="cb16-19">    sk[g] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> scores</span>
<span id="cb16-20"></span>
<span id="cb16-21">filas_cv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb16-22"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> grados:</span>
<span id="cb16-23">    filas_cv.append(</span>
<span id="cb16-24">        {</span>
<span id="cb16-25">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grado"</span>: g,</span>
<span id="cb16-26">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE_pliegues (mano)"</span>: np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(manual[g], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb16-27">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"media_mano"</span>: manual[g].mean(),</span>
<span id="cb16-28">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"DE_mano"</span>: manual[g].std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb16-29">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"media_sklearn"</span>: sk[g].mean(),</span>
<span id="cb16-30">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"¿coinciden?"</span>: np.allclose(manual[g], sk[g]),</span>
<span id="cb16-31">        }</span>
<span id="cb16-32">    )</span>
<span id="cb16-33"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame(filas_cv).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb16-34"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb16-35"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Pliegues grado 4:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(manual[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb16-36"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Pliegues grado 16:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(manual[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> grado                RMSE_pliegues (mano)  media_mano  DE_mano  media_sklearn  ¿coinciden?
     1   [1.02, 0.648, 0.752, 0.63, 0.841]    0.778185 0.159720       0.778185         True
     4 [0.362, 0.411, 0.313, 0.311, 0.222]    0.323681 0.070233       0.323681         True
    16 [0.303, 0.606, 0.212, 0.164, 0.221]    0.301532 0.177645       0.301532         True

Pliegues grado 4: [0.362 0.411 0.313 0.311 0.222]
Pliegues grado 16: [0.303 0.606 0.212 0.164 0.221]</code></pre>
</div>
</div>
<p><strong>Cómo leer los pliegues.</strong> La <strong>media</strong> ordena candidatos. La <strong>DE</strong> (y el peor pliegue) dice si esa media es una cifra o un promedio de accidentes. La <strong>media</strong> del 16 puede quedar <em>parecida o incluso mejor</em> que la del 4 (el print manda). Eso no autoriza al 16: la DE es mayor y un pliegue se dispara. Se rechaza por <strong>inestabilidad</strong>, no porque la media pierda.</p>
<p><strong>Qué no se concluye.</strong> Que <img src="https://latex.codecogs.com/png.latex?k=5"> sea sagrado. <img src="https://latex.codecogs.com/png.latex?k=10"> usa más train en cada ronda y produce pliegues más chicos (más ruidosos). <img src="https://latex.codecogs.com/png.latex?k=n"> (leave-one-out) es otro extremo. Aquí <img src="https://latex.codecogs.com/png.latex?k=5"> es el compromiso de trabajo.</p>
<p><strong>Veredicto parcial.</strong> Reportar solo <code>cross_val_score(...).mean()</code> es recortar la evidencia. La lista de pliegues entra al párrafo.</p>
</section>
<section id="etapa-8-elegir-la-complejidad-dentro-del-entrenamiento" class="level3">
<h3 class="anchored" data-anchor-id="etapa-8-elegir-la-complejidad-dentro-del-entrenamiento">Etapa 8: Elegir la complejidad <em>dentro</em> del entrenamiento</h3>
<p>Se reserva un test final (30%) y <strong>no se toca</strong>. Sobre el 70% restante se recorre el grado <img src="https://latex.codecogs.com/png.latex?1,%5Cldots,12"> con CV <img src="https://latex.codecogs.com/png.latex?k=5">. Se elige el grado de menor RMSE-CV. <em>Después</em> se mide una vez en el test final.</p>
<div id="e8-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:34.302230Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:34.301923Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:34.643186Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:34.642279Z&quot;}}" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">x_dev, x_final, y_dev, y_final <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(x, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>)</span>
<span id="cb18-2">grilla <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">13</span>))</span>
<span id="cb18-3">medias, desvs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [], []</span>
<span id="cb18-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> grilla:</span>
<span id="cb18-5">    sc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rmse_kfold(g, x_dev.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), y_dev, k<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb18-6">    medias.append(sc.mean())</span>
<span id="cb18-7">    desvs.append(sc.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb18-8">medias, desvs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(medias), np.array(desvs)</span>
<span id="cb18-9">g_star <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> grilla[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmin(medias))]</span>
<span id="cb18-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado elegido por CV (solo conjunto de desarrollo):"</span>, g_star)</span>
<span id="cb18-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grado"</span>: grilla, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE_CV"</span>: medias.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"DE_pliegues"</span>: desvs.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)}).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb18-12"></span>
<span id="cb18-13">m_star <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_poli(g_star).fit(x_dev.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), y_dev)</span>
<span id="cb18-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb18-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE desarrollo (reajuste en todo el 70%) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse(y_dev, m_star.predict(x_dev.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb18-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE TEST FINAL (una vez)               ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse(y_final, m_star.predict(x_final.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb18-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE baseline en test final             ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse(y_final, np.full_like(y_final, y_dev.mean())), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb18-18"></span>
<span id="cb18-19">graficar_cv_grados(grilla, medias, desvs, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CV en el desarrollo: el mínimo no está en el grado más alto"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Grado elegido por CV (solo conjunto de desarrollo): 8
 grado  RMSE_CV  DE_pliegues
     1    0.750        0.081
     2    0.649        0.039
     3    0.660        0.045
     4    0.310        0.083
     5    0.340        0.110
     6    0.241        0.035
     7    0.243        0.035
     8    0.238        0.052
     9    0.241        0.043
    10    0.286        0.060
    11    0.275        0.048
    12    0.391        0.290

RMSE desarrollo (reajuste en todo el 70%) = 0.193
RMSE TEST FINAL (una vez)               = 0.245
RMSE baseline en test final             = 0.943</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/index_files/figure-html/cell-11-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Cómo leer la curva en U (o en J).</strong> A la izquierda, sesgo: el grado 1 no llega a <img src="https://latex.codecogs.com/png.latex?f">. A la derecha, varianza: el CV <em>detecta</em> que los pliegues se rompen. El mínimo es el compromiso <strong>estimado sin mirar el test final</strong>.</p>
<p><strong>Qué no se concluye.</strong> Que ese grado sea el verdadero orden de <img src="https://latex.codecogs.com/png.latex?f">. Es el grado que, con <em>este</em> <img src="https://latex.codecogs.com/png.latex?n"> y <em>este</em> ruido, generaliza mejor según el protocolo. Si <img src="https://latex.codecogs.com/png.latex?n"> crece, el mínimo puede correrse a la derecha (más flexibilidad se vuelve pagable).</p>
<p><strong>Veredicto parcial.</strong> El número que se publica es el <strong>RMSE del test final</strong>, junto al grado y a la curva de CV. El RMSE del 70% reajustado no se publica como desempeño.</p>
</section>
<section id="etapa-9-fuga-elegir-el-grado-mirando-la-prueba" class="level3">
<h3 class="anchored" data-anchor-id="etapa-9-fuga-elegir-el-grado-mirando-la-prueba">Etapa 9: Fuga — elegir el grado mirando la prueba</h3>
<p>Se hace lo prohibido: se recorre el grado <img src="https://latex.codecogs.com/png.latex?1,%5Cldots,12"> y se elige el de <strong>menor RMSE de test</strong>. Luego se evalúa en un tercer conjunto (simula “la semana siguiente”). El grado fugado <em>parece</em> mejor en test y suele <strong>empeorar</strong> fuera.</p>
<div id="e9-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:34.646799Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:34.646559Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:34.701047Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:34.700243Z&quot;}}" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">x_a, x_rest, y_a, y_rest <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(x, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.50</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb20-2">x_b, x_c, y_b, y_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(x_rest, y_rest, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.50</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb20-3"></span>
<span id="cb20-4">rmse_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb20-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> g <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> grilla:</span>
<span id="cb20-6">    m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_poli(g).fit(x_a.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), y_a)</span>
<span id="cb20-7">    rmse_b.append(rmse(y_b, m.predict(x_b.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))))</span>
<span id="cb20-8">g_fuga <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> grilla[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.argmin(rmse_b))]</span>
<span id="cb20-9">g_cv_dev <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> g_star</span>
<span id="cb20-10"></span>
<span id="cb20-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> eval_grado(g, x_tr, y_tr, x_ev, y_ev):</span>
<span id="cb20-12">    m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_poli(g).fit(x_tr.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), y_tr)</span>
<span id="cb20-13">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> rmse(y_ev, m.predict(x_ev.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)))</span>
<span id="cb20-14"></span>
<span id="cb20-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado que 'gana' en el conjunto B (fuga):"</span>, g_fuga, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  RMSE_B ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(rmse_b), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb20-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado que ganó por CV en la etapa 8:     "</span>, g_cv_dev)</span>
<span id="cb20-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb20-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE en C (no visto), grado fugado:     "</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(eval_grado(g_fuga, x_a, y_a, x_c, y_c), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb20-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE en C (no visto), grado por CV:     "</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(eval_grado(g_cv_dev, x_a, y_a, x_c, y_c), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb20-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb20-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"El RMSE_B del fugado no se puede citar: ya se usó para elegir."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Grado que 'gana' en el conjunto B (fuga): 6   RMSE_B = 0.221
Grado que ganó por CV en la etapa 8:      8

RMSE en C (no visto), grado fugado:      0.264
RMSE en C (no visto), grado por CV:      0.257

El RMSE_B del fugado no se puede citar: ya se usó para elegir.</code></pre>
</div>
</div>
<p><strong>Cómo leer el truco.</strong> El investigador que publica RMSE_B del grado fugado está publicando un <strong>mínimo de muchos intentos</strong>. El mínimo de muchos errores de prueba es un estadístico sesgado hacia abajo. El conjunto C —el que no participó en la elección— corrige el cuento.</p>
<p><strong>Qué no se concluye.</strong> Que CV siempre gane a la fuga en una réplica. A veces, por azar, coinciden. El argumento es de <strong>protocolo</strong>: el número de B ya no es independiente de la decisión.</p>
<p><strong>Veredicto parcial.</strong> Si el grado (o el umbral, o las <em>features</em>) se eligió con la prueba, <strong>no hay cifra de prueba</strong>. Hay que volver a reservar un conjunto o declarar el sesgo.</p>
</section>
<section id="etapa-10-bootstrap-cuánto-tiembla-el-rmse-de-prueba" class="level3">
<h3 class="anchored" data-anchor-id="etapa-10-bootstrap-cuánto-tiembla-el-rmse-de-prueba">Etapa 10: Bootstrap — cuánto tiembla el RMSE de prueba</h3>
<p>Modelo: el grado elegido por CV (etapa 8), ya ajustado en el desarrollo. Se remuestrean <strong>las filas de prueba</strong> con reemplazo, <img src="https://latex.codecogs.com/png.latex?B=400"> veces, y se recalcula el RMSE. Intervalo: percentiles 2.5 y 97.5.</p>
<p>Eso responde: <em>si la prueba hubiera sido otra muestra de este tamaño, de esta población, ¿en qué rango cae el RMSE?</em></p>
<div id="e10-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:34.703538Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:34.703274Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:35.143993Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:35.143169Z&quot;}}" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1">yhat_final <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> m_star.predict(x_final.reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb22-2">rmse_puntual <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rmse(y_final, yhat_final)</span>
<span id="cb22-3">B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span></span>
<span id="cb22-4">boot <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb22-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(B):</span>
<span id="cb22-6">    idx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.integers(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_final), size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_final))</span>
<span id="cb22-7">    boot.append(rmse(y_final[idx], yhat_final[idx]))</span>
<span id="cb22-8">boot <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(boot)</span>
<span id="cb22-9">lo_b, hi_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> graficar_hist_bootstrap(</span>
<span id="cb22-10">    boot, rmse_puntual,</span>
<span id="cb22-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bootstrap de las filas de prueba: el RMSE no es un punto, es una banda"</span>,</span>
<span id="cb22-12">)</span>
<span id="cb22-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE puntual (test final) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse_puntual, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb22-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IC 95% bootstrap          = ["</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(lo_b, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(hi_b, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"]"</span>)</span>
<span id="cb22-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Anchura del IC            ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(hi_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> lo_b, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb22-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"σ laboratorio             = 0.28"</span>)</span>
<span id="cb22-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb22-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Si el IC cubre al baseline, la 'victoria' todavía no está clara."</span>)</span>
<span id="cb22-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Baseline en ese test     ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse(y_final, np.full_like(y_final, y_dev.mean())), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/index_files/figure-html/cell-13-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>RMSE puntual (test final) = 0.245
IC 95% bootstrap          = [ 0.197 , 0.298 ]
Anchura del IC            = 0.101
σ laboratorio             = 0.28

Si el IC cubre al baseline, la 'victoria' todavía no está clara.
Baseline en ese test     = 0.943</code></pre>
</div>
</div>
<p><strong>Cómo leer el histograma.</strong> El RMSE puntual es el centro de <em>esta</em> prueba. El IC es la honestidad: con <img src="https://latex.codecogs.com/png.latex?n"> de prueba moderado la banda es ancha. Un despliegue que exige “RMSE <img src="https://latex.codecogs.com/png.latex?%3C0.30">” no se sostiene si el IC es <img src="https://latex.codecogs.com/png.latex?(0.22,%5C,0.41)">.</p>
<p><strong>Qué no es el bootstrap.</strong> No es más dato de usuarios. No reemplaza un test de otro mes. No arregla un sesgo de fuga.</p>
<p><strong>Veredicto parcial.</strong> Se cita: <em>RMSE <img src="https://latex.codecogs.com/png.latex?=%20a"> (IC bootstrap 95% <img src="https://latex.codecogs.com/png.latex?%5Bb,%5C,c%5D">), <img src="https://latex.codecogs.com/png.latex?n_%7B%5Cmathrm%7Btest%7D%7D=m"></em>. Sin la banda, <img src="https://latex.codecogs.com/png.latex?a"> finge más precisión que la que hay.</p>
</section>
<section id="etapa-11-curvas-de-aprendizaje-falta-modelo-o-faltan-filas" class="level3">
<h3 class="anchored" data-anchor-id="etapa-11-curvas-de-aprendizaje-falta-modelo-o-faltan-filas">Etapa 11: Curvas de aprendizaje — ¿falta modelo o faltan filas?</h3>
<p>Se varía el tamaño del entrenamiento y se mira RMSE de train y de validación (CV). Tres lecturas:</p>
<ul>
<li>Train bajo y validación alta, <strong>paralelas</strong> al crecer <img src="https://latex.codecogs.com/png.latex?n">: sobreajuste que <em>más datos</em> pueden cerrar.</li>
<li>Ambas altas y ya juntas: subajuste; más filas no salvan la clase de modelo.</li>
<li>Las dos bajan y se acercan a <img src="https://latex.codecogs.com/png.latex?%5Csigma">: régimen sano.</li>
</ul>
<div id="e11-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:35.146460Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:35.146191Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:35.495180Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:35.494242Z&quot;}}" data-execution_count="13">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> curva_aprendizaje(grado, X, y, seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>):</span>
<span id="cb24-2">    sizes, tr_sc, va_sc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> learning_curve(</span>
<span id="cb24-3">        pipe_poli(grado),</span>
<span id="cb24-4">        X,</span>
<span id="cb24-5">        y,</span>
<span id="cb24-6">        cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>KFold(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>seed),</span>
<span id="cb24-7">        train_sizes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>),</span>
<span id="cb24-8">        scoring<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"neg_root_mean_squared_error"</span>,</span>
<span id="cb24-9">        shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,</span>
<span id="cb24-10">        random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>seed,</span>
<span id="cb24-11">    )</span>
<span id="cb24-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> sizes, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>tr_sc.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>va_sc.mean(axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb24-13"></span>
<span id="cb24-14">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.9</span>), sharey<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb24-15"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ax, g, tit <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [(axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado 1"</span>), (axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grado 16"</span>)]:</span>
<span id="cb24-16">    sizes, tr_m, va_m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> curva_aprendizaje(g, X_all, y)</span>
<span id="cb24-17">    ax.plot(sizes, tr_m, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"entrenamiento"</span>)</span>
<span id="cb24-18">    ax.plot(sizes, va_m, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"s"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"validación (CV)"</span>)</span>
<span id="cb24-19">    ax.axhline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.28</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0.4"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">":"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"σ laboratorio"</span>)</span>
<span id="cb24-20">    ax.set_title(tit)</span>
<span id="cb24-21">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n de entrenamiento"</span>)</span>
<span id="cb24-22">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE"</span>)</span>
<span id="cb24-23">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>)</span>
<span id="cb24-24">plt.tight_layout()</span>
<span id="cb24-25">plt.show()</span>
<span id="cb24-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Izquierda: las dos curvas altas y juntas → más n no arregla el sesgo."</span>)</span>
<span id="cb24-27"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Derecha: train bajo, validación alta → el hueco es varianza; n ayuda, el grado 16 pide demasiado."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/index_files/figure-html/cell-14-output-1.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Izquierda: las dos curvas altas y juntas → más n no arregla el sesgo.
Derecha: train bajo, validación alta → el hueco es varianza; n ayuda, el grado 16 pide demasiado.</code></pre>
</div>
</div>
<p><strong>Cómo leer las curvas.</strong> La pregunta de producto “¿compro más datos o cambio el modelo?” se responde aquí. Si las curvas ya se juntaron <em>arriba</em> del error tolerable, el cuello es el modelo. Si hay un foso entre train y validación que se estrecha con <img src="https://latex.codecogs.com/png.latex?n">, el cuello es el tamaño de muestra.</p>
<p><strong>Veredicto parcial.</strong> Un sobreajuste con <img src="https://latex.codecogs.com/png.latex?n"> minúsculo no condena la clase de modelo; condena el <em>tamaño</em>. Un subajuste con <img src="https://latex.codecogs.com/png.latex?n"> grande sí condena la clase.</p>
</section>
<section id="etapa-12-caso-real-diabetes-scikit-learn" class="level3">
<h3 class="anchored" data-anchor-id="etapa-12-caso-real-diabetes-scikit-learn">Etapa 12: Caso real — Diabetes (scikit-learn)</h3>
<p><img src="https://latex.codecogs.com/png.latex?n=442"> pacientes, <img src="https://latex.codecogs.com/png.latex?p=10"> variables clínicas (ya numéricas), <img src="https://latex.codecogs.com/png.latex?y"> = progresión de la enfermedad a un año (escala continua). <strong>No</strong> se conoce <img src="https://latex.codecogs.com/png.latex?f">. El oficio es el protocolo.</p>
<p>Candidatos, todos con estandarización ajustada <strong>solo en entrenamiento</strong>:</p>
<ul>
<li><strong>Baseline:</strong> media de <img src="https://latex.codecogs.com/png.latex?y">.</li>
<li><strong>Lineal:</strong> <code>LinearRegression</code> en las 10 <em>features</em>.</li>
<li><strong>Polinomio grado 2:</strong> todas las interacciones y cuadrados (muchas columnas: riesgo de varianza).</li>
</ul>
<p>Partición: 25% prueba, una vez. Elección entre lineal y poli-2: CV <img src="https://latex.codecogs.com/png.latex?k=5"> <strong>en el 75%</strong>. Bootstrap del RMSE en la prueba del modelo elegido.</p>
<div id="e12-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:35.496716Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:35.496549Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:35.548164Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:35.547614Z&quot;}}" data-execution_count="14">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb26" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb26-1">diab <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> load_diabetes()</span>
<span id="cb26-2">Xd, yd <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> diab.data, diab.target</span>
<span id="cb26-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n ="</span>, Xd.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  p ="</span>, Xd.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  y: min/mediana/max ="</span>,</span>
<span id="cb26-4">      <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(yd.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>()), <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(np.median(yd)), <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(yd.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()))</span>
<span id="cb26-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Unidades de y: índice de progresión (no son 'puntos porcentuales')."</span>)</span>
<span id="cb26-6"></span>
<span id="cb26-7">Xd_dev, Xd_te, yd_dev, yd_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(Xd, yd, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb26-8"></span>
<span id="cb26-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> pipe_lin():</span>
<span id="cb26-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Pipeline([(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"esc"</span>, StandardScaler()), (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lin"</span>, LinearRegression())])</span>
<span id="cb26-11"></span>
<span id="cb26-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> pipe_poly2():</span>
<span id="cb26-13">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Pipeline(</span>
<span id="cb26-14">        [</span>
<span id="cb26-15">            (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"esc"</span>, StandardScaler()),</span>
<span id="cb26-16">            (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"poli"</span>, PolynomialFeatures(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, include_bias<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)),</span>
<span id="cb26-17">            (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lin"</span>, LinearRegression()),</span>
<span id="cb26-18">        ]</span>
<span id="cb26-19">    )</span>
<span id="cb26-20"></span>
<span id="cb26-21">kf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KFold(n_splits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb26-22"></span>
<span id="cb26-23"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> cv_rmse(estimator, X, y):</span>
<span id="cb26-24">    sc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>cross_val_score(estimator, X, y, cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>kf, scoring<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"neg_root_mean_squared_error"</span>)</span>
<span id="cb26-25">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> sc</span>
<span id="cb26-26"></span>
<span id="cb26-27">cv_lin <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cv_rmse(pipe_lin(), Xd_dev, yd_dev)</span>
<span id="cb26-28">cv_p2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cv_rmse(pipe_poly2(), Xd_dev, yd_dev)</span>
<span id="cb26-29"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb26-30"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CV en desarrollo (no se tocó la prueba)"</span>)</span>
<span id="cb26-31"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  lineal  pliegues ="</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(cv_lin, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  media ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(cv_lin.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  DE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(cv_lin.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb26-32"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  poli-2  pliegues ="</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(cv_p2, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  media ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(cv_p2.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  DE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(cv_p2.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb26-33"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  p del poli-2 (columnas) ="</span>, pipe_poly2().fit(Xd_dev, yd_dev).named_steps[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"poli"</span>].n_output_features_)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>n = 442   p = 10   y: min/mediana/max = 25 140 346
Unidades de y: índice de progresión (no son 'puntos porcentuales').

CV en desarrollo (no se tocó la prueba)
  lineal  pliegues = [57.28 58.26 49.9  57.24 57.91]   media = 56.12   DE = 3.5
  poli-2  pliegues = [70.69 58.28 54.61 72.93 64.66]   media = 64.23   DE = 7.84
  p del poli-2 (columnas) = 65</code></pre>
</div>
</div>
<p><strong>Pausa de análisis (antes de la prueba).</strong> El poli-2 explota <img src="https://latex.codecogs.com/png.latex?p">: decenas de columnas contra ~300 filas de desarrollo. Si su media de CV es <em>peor</em> o su DE es mayor, <strong>no se elige</strong> aunque en train vaya a brillar. El lineal es el candidato por defecto en este régimen.</p>
<p>Siguiente celda: se elige por la media de CV (y se mira la DE). Luego <strong>una</strong> evaluación en prueba, baseline incluido, y bootstrap.</p>
<div id="e12-code2" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:20:35.549665Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:20:35.549487Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:20:36.023523Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:20:36.022675Z&quot;}}" data-execution_count="15">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb28" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb28-1">elegido_nombre <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lineal"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> cv_lin.mean() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> cv_p2.mean() <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"poli-2"</span></span>
<span id="cb28-2">elegido <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_lin() <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> elegido_nombre <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lineal"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> pipe_poly2()</span>
<span id="cb28-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Elegido por CV:"</span>, elegido_nombre, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"(menor RMSE medio en desarrollo)"</span>)</span>
<span id="cb28-4"></span>
<span id="cb28-5">dummy_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DummyRegressor(strategy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>).fit(Xd_dev, yd_dev)</span>
<span id="cb28-6">elegido.fit(Xd_dev, yd_dev)</span>
<span id="cb28-7">p2_ref <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipe_poly2().fit(Xd_dev, yd_dev)</span>
<span id="cb28-8"></span>
<span id="cb28-9">filas_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb28-10">    ficha(yd_dev, dummy_d.predict(Xd_dev), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"baseline / dev"</span>),</span>
<span id="cb28-11">    ficha(yd_te, dummy_d.predict(Xd_te), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"baseline / TEST"</span>),</span>
<span id="cb28-12">    ficha(yd_dev, elegido.predict(Xd_dev), <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>elegido_nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> / dev"</span>),</span>
<span id="cb28-13">    ficha(yd_te, elegido.predict(Xd_te), <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>elegido_nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> / TEST"</span>),</span>
<span id="cb28-14">    ficha(yd_dev, p2_ref.predict(Xd_dev), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"poli-2 / dev (referencia)"</span>),</span>
<span id="cb28-15">    ficha(yd_te, p2_ref.predict(Xd_te), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"poli-2 / TEST (no elegido si CV lo perdió)"</span>),</span>
<span id="cb28-16">]</span>
<span id="cb28-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame(filas_d).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb28-18"></span>
<span id="cb28-19">yhat_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> elegido.predict(Xd_te)</span>
<span id="cb28-20">rmse_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rmse(yd_te, yhat_te)</span>
<span id="cb28-21">boot_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb28-22"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>):</span>
<span id="cb28-23">    idx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.integers(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(yd_te), size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(yd_te))</span>
<span id="cb28-24">    boot_d.append(rmse(yd_te[idx], yhat_te[idx]))</span>
<span id="cb28-25">boot_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(boot_d)</span>
<span id="cb28-26">lo_d, hi_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> graficar_hist_bootstrap(</span>
<span id="cb28-27">    boot_d, rmse_te,</span>
<span id="cb28-28">    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Diabetes — bootstrap del RMSE de prueba (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>elegido_nombre<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)"</span>,</span>
<span id="cb28-29">)</span>
<span id="cb28-30"></span>
<span id="cb28-31"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># residuos de prueba</span></span>
<span id="cb28-32">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.7</span>))</span>
<span id="cb28-33">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].scatter(yhat_te, yd_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> yhat_te, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb28-34">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>)</span>
<span id="cb28-35">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ŷ (prueba)"</span>)</span>
<span id="cb28-36">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"residuo"</span>)</span>
<span id="cb28-37">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Residuos en TEST"</span>)</span>
<span id="cb28-38">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].scatter(yd_te, yhat_te, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb28-39">mn, mx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> yd_te.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), yd_te.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()</span>
<span id="cb28-40">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot([mn, mx], [mn, mx], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>)</span>
<span id="cb28-41">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y (prueba)"</span>)</span>
<span id="cb28-42">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ŷ"</span>)</span>
<span id="cb28-43">axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Calibración grosera: ¿sobre la diagonal?"</span>)</span>
<span id="cb28-44">plt.tight_layout()</span>
<span id="cb28-45">plt.show()</span>
<span id="cb28-46"></span>
<span id="cb28-47"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE TEST"</span>, elegido_nombre, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse_te, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  IC bootstrap 95% ["</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(lo_d, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(hi_d, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"]"</span>)</span>
<span id="cb28-48"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE TEST baseline ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse(yd_te, dummy_d.predict(Xd_te)), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb28-49"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R2 TEST"</span>, elegido_nombre, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(r2_score(yd_te, yhat_te), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb28-50"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"DE de y (desarrollo) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(yd_dev.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  → el baseline vive cerca de ese orden"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Elegido por CV: lineal (menor RMSE medio en desarrollo)
                                    modelo  RMSE     MSE    R2
                            baseline / dev 77.75 6044.62  0.00
                           baseline / TEST 74.88 5607.20 -0.01
                              lineal / dev 53.92 2907.26  0.52
                             lineal / TEST 53.37 2848.31  0.48
                 poli-2 / dev (referencia) 48.87 2388.74  0.60
poli-2 / TEST (no elegido si CV lo perdió) 56.42 3183.76  0.42</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/index_files/figure-html/cell-16-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/index_files/figure-html/cell-16-output-3.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>RMSE TEST lineal = 53.37   IC bootstrap 95% [ 45.79 , 59.99 ]
RMSE TEST baseline = 74.88
R2 TEST lineal = 0.485
DE de y (desarrollo) = 77.86   → el baseline vive cerca de ese orden</code></pre>
</div>
</div>
<p><strong>Cómo leer el caso Diabetes, número por número.</strong></p>
<ol type="1">
<li><p><strong>Escala de <img src="https://latex.codecogs.com/png.latex?y">.</strong> El índice vive, más o menos, entre 25 y 350. Un RMSE de ~55 no es “55% de error”; es ~55 puntos de ese índice. Hay que preguntar al dominio si 55 puntos importan clínicamente. La estadística <strong>no</strong> responde esa frase; la <strong>prepara</strong>.</p></li>
<li><p><strong>Baseline.</strong> El RMSE de predecir la media ronda la desviación de <img src="https://latex.codecogs.com/png.latex?y"> (~70–80). Si el lineal no baja de forma clara <em>en TEST</em>, no hay modelo.</p></li>
<li><p><strong>Hueco dev vs TEST.</strong> Si el lineal tiene RMSE de desarrollo y de prueba cercanos, no hay sobreajuste grosero. Si el poli-2 brilla en desarrollo y empeora en prueba, es el grado 16 de las etapas 2–4, ahora en <img src="https://latex.codecogs.com/png.latex?p"> alto.</p></li>
<li><p><strong>Pliegues.</strong> Una DE de CV de varios puntos sobre una media de ~55 dice que el “55” no es un milímetro. El bootstrap de la prueba debe contar la misma historia (banda ancha).</p></li>
<li><p><strong>Residuos de TEST.</strong> Embudo o curva: el lineal es un <em>baseline útil</em>, no la <img src="https://latex.codecogs.com/png.latex?f"> del fenómeno. Nube alrededor de 0, sin estructura fuerte: el lineal es una descripción honesta <em>dentro de su clase</em>.</p></li>
<li><p><strong><img src="https://latex.codecogs.com/png.latex?R%5E2"> de TEST ~ 0.4–0.5</strong> (orden típico de este conjunto). Traducción: se explica una fracción moderada de la varianza. <strong>No</strong> es un sistema de decisión clínica. <strong>Sí</strong> es evidencia de señal lineal y un suelo para modelos posteriores.</p></li>
</ol>
<p><strong>Qué no se concluye.</strong> Que el lineal “falle” porque <img src="https://latex.codecogs.com/png.latex?R%5E2%3C0.9">. El umbral 0.9 no es de este <img src="https://latex.codecogs.com/png.latex?y">. Que el poli-2 sea superior por tener más parámetros. Que el IC bootstrap autorice un protocolo médico.</p>
<p><strong>Preguntas de análisis (escríbelas antes de mirar el reporte modelo).</strong></p>
<ul>
<li>¿El elegido gana al baseline en TEST por un margen mayor que la anchura del IC?</li>
<li>¿Elegirías poli-2 si solo vieras el RMSE de desarrollo?</li>
<li>Si el peor pliegue de CV es mucho peor que la media, ¿firmas un despliegue?</li>
</ul>
</section>
<section id="caso-aplicado-ficha-de-veredicto" class="level3">
<h3 class="anchored" data-anchor-id="caso-aplicado-ficha-de-veredicto">Caso aplicado: ficha de veredicto</h3>
<p>Plantilla (se llena; no se deja en abstracto):</p>
<ol type="1">
<li><strong>Problema y unidad.</strong> Qué es <img src="https://latex.codecogs.com/png.latex?y">, qué sería un error tolerable.</li>
<li><strong>Baseline.</strong> Número de referencia y conjunto.</li>
<li><strong>Candidatos y protocolo.</strong> Qué se comparó; dónde se eligió (CV en desarrollo, no en test).</li>
<li><strong>Cifra que se cita.</strong> Métrica de <strong>prueba</strong>, <img src="https://latex.codecogs.com/png.latex?n_%7B%5Cmathrm%7Btest%7D%7D">, IC (bootstrap o DE de CV).</li>
<li><strong>Hueco y residuos.</strong> ¿Sobreajuste? ¿Forma mal especificada?</li>
<li><strong>Decisión.</strong> Rechazar / iterar / aceptar con límites. Una frase de límite (población, <img src="https://latex.codecogs.com/png.latex?p">, no clínico, etc.).</li>
</ol>
<p><strong>Los seis pasos, aplicados a Diabetes</strong></p>
<ol type="1">
<li><strong>Problema.</strong> Predecir la progresión a un año (índice continuo). Un error tolerable lo fija el clínico; aquí se usa la escala observada (DE de <img src="https://latex.codecogs.com/png.latex?y"> ≈ 70–80) como ancla.</li>
<li><strong>Baseline.</strong> Media de <img src="https://latex.codecogs.com/png.latex?y"> en desarrollo; RMSE de TEST del <code>DummyRegressor</code> (print de la etapa 12).</li>
<li><strong>Candidatos.</strong> Lineal vs poli-2, ambos con <code>StandardScaler</code>. Elección por RMSE-CV <img src="https://latex.codecogs.com/png.latex?k=5"> en el 75%. La prueba (25%) no eligió.</li>
<li><strong>Cifra.</strong> RMSE de TEST del modelo elegido + IC bootstrap 95% + <img src="https://latex.codecogs.com/png.latex?R%5E2"> de TEST. <img src="https://latex.codecogs.com/png.latex?n_%7B%5Cmathrm%7Btest%7D%7D%5Capprox%20110">.</li>
<li><strong>Hueco.</strong> El lineal suele tener dev y TEST cercanos; el poli-2, si empeora en TEST, se documenta como varianza por <img src="https://latex.codecogs.com/png.latex?p"> inflado. Residuos de TEST: ver figura.</li>
<li><strong>Decisión.</strong> <em>Aceptar como baseline estadístico, no como herramienta clínica.</em> Gana a la media, el hueco no denuncia sobreajuste grosero, el <img src="https://latex.codecogs.com/png.latex?R%5E2"> es moderado y el IC impide vender una precisión milimétrica. Iterar: más <em>features</em> de dominio, otro modelo, otro <img src="https://latex.codecogs.com/png.latex?n"> —no un poli-2 por costumbre.</li>
</ol>
<blockquote class="blockquote">
<p>En <img src="https://latex.codecogs.com/png.latex?n=442"> pacientes (<img src="https://latex.codecogs.com/png.latex?p=10">), un lineal estandarizado se eligió por CV frente a un polinomio de grado 2. El RMSE de prueba es <img src="https://latex.codecogs.com/png.latex?53.4"> con IC bootstrap 95% <img src="https://latex.codecogs.com/png.latex?%5B45.8,%5C,60.0%5D"> (<img src="https://latex.codecogs.com/png.latex?R%5E2=0.485">). Supera al baseline de la media. El <img src="https://latex.codecogs.com/png.latex?R%5E2"> de prueba es moderado: hay señal, no hay modelo de decisión médica. Limitación: una partición, <img src="https://latex.codecogs.com/png.latex?y"> de índice no calibrado a unidades clínicas en este notebook, sin validación temporal.</p>
</blockquote>
<p>Esa última frase es el oficio. El modelo <strong>es aceptable para un fin</strong> (suelo, comparación, enseñanza) y <strong>no es aceptable para otro</strong> (tratar a un paciente). “¿Es bueno?” sin el fin es una pregunta mal hecha.</p>
</section>
<section id="errores-que-conviene-nombrar" class="level3">
<h3 class="anchored" data-anchor-id="errores-que-conviene-nombrar">Errores que conviene nombrar</h3>
<ol type="1">
<li><strong>Publicar el error de entrenamiento</strong> como desempeño.</li>
<li><strong>Elegir el modelo con la prueba</strong> y citar esa misma prueba (fuga).</li>
<li><strong>Declarar ganador</strong> sin baseline.</li>
<li><strong>Ignorar la dispersión</strong> de pliegues o del bootstrap: tratar la media como exacta.</li>
<li><strong>Confundir <img src="https://latex.codecogs.com/png.latex?R%5E2"> alto con utilidad.</strong> El <img src="https://latex.codecogs.com/png.latex?R%5E2"> no conoce el costo de un error de 50 puntos.</li>
<li><strong>Más flexibilidad como plan A</strong> cuando las curvas de aprendizaje ya se juntaron arriba (subajuste).</li>
<li><strong>Más datos como plan A</strong> cuando el modelo es una recta sobre un seno (la clase está mal).</li>
<li><strong>Bootstrap = más <img src="https://latex.codecogs.com/png.latex?n">.</strong> Es remuestreo, no reclutamiento.</li>
</ol>
</section>
<section id="idea-clave" class="level3">
<h3 class="anchored" data-anchor-id="idea-clave">Idea clave</h3>
<p><strong>Un modelo es aceptable solo respecto a un baseline, un conjunto no visto, una unidad de error y un uso.</strong> El resto —<img src="https://latex.codecogs.com/png.latex?R%5E2"> de train, un split afortunado, un grado que ganó en test— es teatro de ajuste.</p>
</section>
<section id="síntesis" class="level3">
<h3 class="anchored" data-anchor-id="síntesis">Síntesis</h3>
<p>Se partió de un baseline y se dejó que el grado 16 ganara en entrenamiento para contradecirlo en prueba. El abanico de 60 muestras hizo visible el sesgo y la varianza. Un split único tembló; la CV juntó pliegues y eligió complejidad <em>sin</em> tocar el test final. La fuga mostró cómo se fabrica un RMSE optimista. El bootstrap convirtió el RMSE en una banda. Las curvas de aprendizaje separaron “faltan filas” de “falla la clase de modelo”. En Diabetes se llenó la ficha: el lineal es un suelo honesto, no un oráculo. El objeto que queda es el <strong>veredicto con evidencia</strong>, no el <code>score_</code>.</p>
</section>
</section>
<section id="guía-rápida-qué-protocolo-usar" class="level2">
<h2 class="anchored" data-anchor-id="guía-rápida-qué-protocolo-usar">6. Guía rápida: ¿qué protocolo usar?</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Situación</th>
<th>Qué usar</th>
<th>Qué mirar</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>¿Hay señal alguna?</td>
<td>Baseline (media / modelo actual)</td>
<td>El candidato debe ganar <em>en prueba</em></td>
</tr>
<tr class="even">
<td>Primera cifra honesta</td>
<td>Train / test, una vez</td>
<td>Hueco y unidades</td>
</tr>
<tr class="odd">
<td><img src="https://latex.codecogs.com/png.latex?n"> chico o split nervioso</td>
<td><img src="https://latex.codecogs.com/png.latex?k">-fold CV</td>
<td>Media <strong>y</strong> DE / peor pliegue</td>
</tr>
<tr class="even">
<td>Elegir grado o hiperparámetro</td>
<td>CV <em>en desarrollo</em></td>
<td>El test no vota</td>
</tr>
<tr class="odd">
<td>¿Cuánto precisa es la cifra?</td>
<td>Bootstrap de la métrica</td>
<td>Anchura del IC</td>
</tr>
<tr class="even">
<td>¿Más datos o otro modelo?</td>
<td>Curvas de aprendizaje</td>
<td>¿Se juntan arriba o hay foso?</td>
</tr>
<tr class="odd">
<td>¿Memorizó?</td>
<td>Train <img src="https://latex.codecogs.com/png.latex?%5Cll"> test</td>
<td>Sobreajuste</td>
</tr>
<tr class="even">
<td>¿No puede aprender <img src="https://latex.codecogs.com/png.latex?f">?</td>
<td>Train ≈ test, ambos altos</td>
<td>Subajuste</td>
</tr>
</tbody>
</table>
<p><strong>Regla de comunicación:</strong> métrica, conjunto (test o CV), <img src="https://latex.codecogs.com/png.latex?n">, intervalo o DE, baseline, y el <strong>uso</strong> para el que se acepta o se rechaza.</p>
</section>
<section id="guía-práctica-para-reportar-un-veredicto" class="level2">
<h2 class="anchored" data-anchor-id="guía-práctica-para-reportar-un-veredicto">7. Guía práctica para reportar un veredicto</h2>
<section id="paso-1-y-unidad-uso" class="level3">
<h3 class="anchored" data-anchor-id="paso-1-y-unidad-uso">Paso 1: <img src="https://latex.codecogs.com/png.latex?y">, unidad, uso</h3>
<p>Qué se predice, qué error sería tolerable, para qué decisión.</p>
</section>
<section id="paso-2-protocolo" class="level3">
<h3 class="anchored" data-anchor-id="paso-2-protocolo">Paso 2: protocolo</h3>
<p>Baseline, partición, dónde se eligió el modelo, <img src="https://latex.codecogs.com/png.latex?k">, <img src="https://latex.codecogs.com/png.latex?B"> del bootstrap.</p>
</section>
<section id="paso-3-cifras" class="level3">
<h3 class="anchored" data-anchor-id="paso-3-cifras">Paso 3: cifras</h3>
<p>Tabla train/dev vs test; pliegues; IC.</p>
</section>
<section id="paso-4-diagnóstico" class="level3">
<h3 class="anchored" data-anchor-id="paso-4-diagnóstico">Paso 4: diagnóstico</h3>
<p>Hueco, residuos de <em>test</em>, curva de aprendizaje si hace falta.</p>
</section>
<section id="paso-5-redactar" class="level3">
<h3 class="anchored" data-anchor-id="paso-5-redactar">Paso 5: redactar</h3>
<blockquote class="blockquote">
<p>“Para <code>[uso]</code>, <img src="https://latex.codecogs.com/png.latex?y="><code>[unidad]</code>. Baseline <code>[...]</code> en TEST = <code>[métrica]</code>. El modelo <code>[...]</code> se eligió por <code>[CV / ...]</code> en desarrollo (<img src="https://latex.codecogs.com/png.latex?n="><code>[...]</code>). En TEST (<img src="https://latex.codecogs.com/png.latex?n="><code>[...]</code>) la métrica es <code>[...]</code> (IC <code>[...]</code>). Hueco train–test: <code>[...]</code>. Residuos: <code>[banda / patrón]</code>. <strong>Veredicto:</strong> <code>[rechazar / iterar / aceptar para este uso]</code>. No se acepta para <code>[uso que el número no sostiene]</code>. Limitación: <code>[split único / p alto / sin validación temporal]</code>.”</p>
</blockquote>
<p>Diabetes (etapa 12) ya llenó esta plantilla.</p>
</section>
</section>
<section id="puente-hacia-las-siguientes-sesiones" class="level2">
<h2 class="anchored" data-anchor-id="puente-hacia-las-siguientes-sesiones">8. Puente hacia las siguientes sesiones</h2>
<p>Validar es el lastre que convierte un ajuste (la recta de la sesión de regresión; un clasificador, si ya se midió precisión y <em>recall</em>) en una <strong>afirmación sobre datos no vistos</strong>. El proyecto integrador pide exactamente esto: no un <code>fit</code> brillante, un <strong>párrafo de veredicto</strong> con baseline, conjunto no visto e incertidumbre. Si la métrica cambia (F1, AUC), el protocolo no cambia: solo la pérdida <img src="https://latex.codecogs.com/png.latex?L">.</p>
</section>
<section id="cierre" class="level2">
<h2 class="anchored" data-anchor-id="cierre">9. Cierre</h2>
<p>Este notebook deja el criterio para no confundir ajuste con modelo:</p>
<ul>
<li>tres errores (train, test, generalización),</li>
<li>sobreajuste y subajuste, leídos en tabla y en figura,</li>
<li>sesgo frente a varianza (abanico de réplicas),</li>
<li>train/test, su temblor y la fuga al elegir con la prueba,</li>
<li>validación cruzada a mano y con scikit-learn,</li>
<li>bootstrap de la métrica,</li>
<li>curvas de aprendizaje,</li>
<li>una ficha de veredicto aplicada a Diabetes.</li>
</ul>
<p><strong>Resultado esperado:</strong> el estudiante puede mirar una tabla train/test, una lista de pliegues y un IC, y <strong>decidir</strong> —aceptar para un uso, iterar o rechazar— sin que un <img src="https://latex.codecogs.com/png.latex?R%5E2"> de entrenamiento le dicte la frase.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>validacion-cruzada</category>
  <category>overfitting</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/basico/13-validacion-desempeno-modelo/</guid>
  <pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Estadística para IA — 14. Proyecto integrador final</title>
  <dc:creator>Wilder Ramírez Delgado</dc:creator>
  <link>https://biitt.com/es/blog/analisis-de-datos/basico/14-proyecto-integrador-final/</link>
  <description><![CDATA[ 




<section id="sesión-14-proyecto-integrador-final" class="level1">
<h1>Sesión 14 — Proyecto Integrador Final</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="TODO_URL_GITHUB"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid figure-img"></a></p>
<figcaption>Open in Colab</figcaption>
</figure>
</div>
<section id="sobre-el-autor" class="level2">
<h2 class="anchored" data-anchor-id="sobre-el-autor">👋 Sobre el autor</h2>
<p>Wilder Ramírez Delgado es Científico de Datos, Arquitecto de IA, Ingeniero Electrónico y Magíster en Analítica de Datos. CEO y fundador de Business Innovation Technology (BIT), consultor y docente universitario, trabaja en la intersección entre Data Science, Inteligencia Artificial, Big Data e IoT, transformando problemas reales en soluciones aplicadas.</p>
<p>De la teoría a la práctica, un problema a la vez.</p>
</section>
<section id="un-cuaderno-que-se-atreve-a-concluir" class="level2">
<h2 class="anchored" data-anchor-id="un-cuaderno-que-se-atreve-a-concluir">Un cuaderno que se atreve a concluir</h2>
<p>Este cierre no introduce una técnica nueva. Recorre, sobre <strong>un solo dataset diseñado</strong>, lo que el curso ya enseñó: leer variables, ver forma y relación, ajustar una recta, no fiarse del error de entrenamiento y <strong>escribir un veredicto</strong>. El producto no es un <code>fit</code> brillante: es un párrafo que dice para qué sirve el modelo y para qué no.</p>
<p>Contexto: una plataforma de práctica. Cada fila es un estudiante. Se predice <code>puntuacion</code> (0–100) a partir de hábitos. Los datos son sintéticos y <strong>diseñados</strong>: hay señal, hay una <em>feature</em> inútil y hay dos hábitos correlacionados a propósito.</p>
<p>Electiva I — Estadística Aplicada a la Inteligencia Artificial · Módulo 4 · Sesión 14</p>
</section>
<section id="objetivos" class="level2">
<h2 class="anchored" data-anchor-id="objetivos">Objetivos</h2>
<ul>
<li>Recorrer un <strong>EDA</strong> mínimo (tipos, centro, dispersión, forma) sin sustituirlo por el modelo.</li>
<li>Leer una <strong>matriz de correlación</strong> sin convertir <img src="https://latex.codecogs.com/png.latex?r"> en causa.</li>
<li>Ajustar un <strong>lineal</strong> con scikit-learn y un <strong>baseline</strong> (media).</li>
<li>Medir en <strong>prueba</strong>, no solo en entrenamiento.</li>
<li>Diagnosticar <strong>residuos</strong>.</li>
<li>Redactar el <strong>veredicto</strong> con unidad, <img src="https://latex.codecogs.com/png.latex?n">, hueco y límite.</li>
</ul>
<blockquote class="blockquote">
<p>Nota: se recomienda ejecutar las celdas en orden. Las fórmulas usan LaTeX; si no se ven renderizadas, abre el notebook en Jupyter o Colab.</p>
</blockquote>
</section>
<section id="el-rol-de-la-estadística-en-este-cierre" class="level2">
<h2 class="anchored" data-anchor-id="el-rol-de-la-estadística-en-este-cierre">1. El rol de la estadística en este cierre</h2>
<p>El curso dejó un orden. Aquí se usa, no se vuelve a derivar.</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Bloque</th>
<th>Qué se hace aquí</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Dato y tipos</td>
<td><code>info</code>, dtypes, qué se puede promediar</td>
</tr>
<tr class="even">
<td>Centro y dispersión</td>
<td>media, mediana, DE de <code>puntuacion</code></td>
</tr>
<tr class="odd">
<td>Forma</td>
<td>histograma de <img src="https://latex.codecogs.com/png.latex?y"> (¿asimetría?)</td>
</tr>
<tr class="even">
<td>Relación</td>
<td>correlación; dos hábitos redundantes</td>
</tr>
<tr class="odd">
<td>Recta</td>
<td>OLS, <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta">, RMSE</td>
</tr>
<tr class="even">
<td>Validación</td>
<td>train/test, baseline, hueco</td>
</tr>
<tr class="odd">
<td>Comunicación</td>
<td>ficha de veredicto</td>
</tr>
</tbody>
</table>
<p><strong>Idea central:</strong> cada número pide un conjunto (toda la muestra, train o test) y una pregunta. Mezclarlos es el fallo que este notebook evita a propósito.</p>
</section>
<section id="por-qué-este-proyecto-importa-en-ia" class="level2">
<h2 class="anchored" data-anchor-id="por-qué-este-proyecto-importa-en-ia">2. Por qué este proyecto importa en IA</h2>
<p>Un pipeline real no es “cargar y <code>fit</code>”. Es decidir si el error en <strong>unidades de <img src="https://latex.codecogs.com/png.latex?y"></strong> justifica un despliegue. Aquí <img src="https://latex.codecogs.com/png.latex?y"> es una puntuación: RMSE 8 no es lo mismo que RMSE 25. El baseline (predecir la media) impide felicitarse por un <img src="https://latex.codecogs.com/png.latex?R%5E2"> de train.</p>
</section>
<section id="flujo-del-proyecto" class="level2">
<h2 class="anchored" data-anchor-id="flujo-del-proyecto">3. Flujo del proyecto</h2>
<ol type="1">
<li>Generar / cargar y <strong>conocer</strong> columnas.</li>
<li>Describir <img src="https://latex.codecogs.com/png.latex?y"> y las <img src="https://latex.codecogs.com/png.latex?x">.</li>
<li>Correlación y scatter de las relaciones diseñadas.</li>
<li>Partir train/test <strong>antes</strong> de elegir el modelo.</li>
<li>Baseline → lineal → RMSE y <img src="https://latex.codecogs.com/png.latex?R%5E2"> en <strong>ambos</strong> conjuntos.</li>
<li>Residuos de <strong>prueba</strong>.</li>
<li>Veredicto escrito.</li>
</ol>
</section>
<section id="preparar-el-entorno" class="level2">
<h2 class="anchored" data-anchor-id="preparar-el-entorno">4. Preparar el entorno</h2>
<div id="entorno-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:18.736611Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:18.736075Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:20.981738Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:20.980804Z&quot;}}" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb1-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Python:"</span>, sys.version.split()[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LinearRegression</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.dummy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> DummyRegressor</span>
<span id="cb1-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> mean_squared_error, r2_score</span>
<span id="cb1-11"></span>
<span id="cb1-12">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-13">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"figure.figsize"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-14">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"axes.grid"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb1-15">plt.rcParams[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grid.alpha"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span></span>
<span id="cb1-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Entorno listo."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Python: 3.13.9
Entorno listo.</code></pre>
</div>
</div>
<section id="funciones-una-sola-vez" class="level3">
<h3 class="anchored" data-anchor-id="funciones-una-sola-vez">Funciones (una sola vez)</h3>
<div id="viz-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:20.984959Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:20.984488Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:20.998951Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:20.997118Z&quot;}}" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> rmse(y_true, y_pred):</span>
<span id="cb3-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.sqrt(mean_squared_error(y_true, y_pred)))</span>
<span id="cb3-3"></span>
<span id="cb3-4"></span>
<span id="cb3-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> ficha(y_true, y_pred, etiqueta):</span>
<span id="cb3-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb3-7">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"conjunto"</span>: etiqueta,</span>
<span id="cb3-8">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE"</span>: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse(y_true, y_pred), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb3-9">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R2"</span>: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(r2_score(y_true, y_pred)), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb3-10">    }</span>
<span id="cb3-11"></span>
<span id="cb3-12"></span>
<span id="cb3-13"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_hist_y(y, titulo):</span>
<span id="cb3-14">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.8</span>))</span>
<span id="cb3-15">    ax.hist(y, bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C0"</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.85</span>)</span>
<span id="cb3-16">    ax.axvline(np.mean(y), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"media = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean(y)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-17">    ax.axvline(np.median(y), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C1"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">":"</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"mediana = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>median(y)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-18">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"puntuación"</span>)</span>
<span id="cb3-19">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"frecuencia"</span>)</span>
<span id="cb3-20">    ax.set_title(titulo)</span>
<span id="cb3-21">    ax.legend(fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-22">    plt.tight_layout()</span>
<span id="cb3-23">    plt.show()</span>
<span id="cb3-24"></span>
<span id="cb3-25"></span>
<span id="cb3-26"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_corr(df, titulo):</span>
<span id="cb3-27">    cols <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(df.columns)</span>
<span id="cb3-28">    R <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.corr()</span>
<span id="cb3-29">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.2</span>))</span>
<span id="cb3-30">    im <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ax.imshow(R, vmin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, vmax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"coolwarm"</span>)</span>
<span id="cb3-31">    ax.set_xticks(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(cols)), cols, rotation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">35</span>, ha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"right"</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-32">    ax.set_yticks(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(cols)), cols, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb3-33">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(cols)):</span>
<span id="cb3-34">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(cols)):</span>
<span id="cb3-35">            ax.text(j, i, <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>R<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>iloc[i, j]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, ha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>, va<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>)</span>
<span id="cb3-36">    fig.colorbar(im, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ax, fraction<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.046</span>)</span>
<span id="cb3-37">    ax.set_title(titulo)</span>
<span id="cb3-38">    plt.tight_layout()</span>
<span id="cb3-39">    plt.show()</span>
<span id="cb3-40"></span>
<span id="cb3-41"></span>
<span id="cb3-42"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> graficar_residuos(yhat, e, titulo):</span>
<span id="cb3-43">    fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.7</span>))</span>
<span id="cb3-44">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].scatter(yhat, e, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb3-45">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>)</span>
<span id="cb3-46">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ŷ prueba"</span>)</span>
<span id="cb3-47">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"residuo"</span>)</span>
<span id="cb3-48">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Residuos vs ajustados (TEST)"</span>)</span>
<span id="cb3-49">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].scatter(yhat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> e, yhat, s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb3-50">    lo, hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (yhat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> e).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), (yhat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> e).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>()</span>
<span id="cb3-51">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot([lo, hi], [lo, hi], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C3"</span>, linestyle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--"</span>)</span>
<span id="cb3-52">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y prueba"</span>)</span>
<span id="cb3-53">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ŷ"</span>)</span>
<span id="cb3-54">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Calibración grosera (TEST)"</span>)</span>
<span id="cb3-55">    fig.suptitle(titulo, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.02</span>)</span>
<span id="cb3-56">    plt.tight_layout()</span>
<span id="cb3-57">    plt.show()</span></code></pre></div></div>
</div>
</section>
</section>
<section id="desarrollo-del-proyecto" class="level2">
<h2 class="anchored" data-anchor-id="desarrollo-del-proyecto">5. Desarrollo del proyecto</h2>
<section id="etapa-1-el-dataset-diseñado" class="level3">
<h3 class="anchored" data-anchor-id="etapa-1-el-dataset-diseñado">Etapa 1: El dataset (diseñado)</h3>
<p><img src="https://latex.codecogs.com/png.latex?n=280">. La puntuación se fabrica así:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7Bpuntuacion%7D=42+2.1%5Ccdot%5Ctext%7Bpractica%7D+1.4%5Ccdot%5Ctext%7Blectura%7D+3.0%5Ccdot%5Ctext%7Bsueno%7D-0.35%5Ccdot%5Ctext%7Bdistraccion%7D+%5Cvarepsilon.%0A"></p>
<p><code>lectura</code> y <code>practica</code> están correlacionadas (hábitos que se mueven juntos). <code>ruido</code> no entra en <img src="https://latex.codecogs.com/png.latex?y">.</p>
<div id="e1-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:21.003311Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:21.002774Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:21.018754Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:21.018078Z&quot;}}" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">280</span></span>
<span id="cb4-2">lectura <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>, n).clip(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>)</span>
<span id="cb4-3">practica <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.75</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> lectura <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.4</span>, n)).clip(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>)</span>
<span id="cb4-4">sueno <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>, n).clip(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">10.0</span>)</span>
<span id="cb4-5">distraccion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">35</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, n).clip(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>)</span>
<span id="cb4-6">ruido <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, n)</span>
<span id="cb4-7">eps <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.normal(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7.5</span>, n)</span>
<span id="cb4-8">puntuacion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> practica <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.4</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> lectura <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.0</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> sueno <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.35</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> distraccion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> eps).clip(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)</span>
<span id="cb4-9"></span>
<span id="cb4-10">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb4-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lectura_h"</span>: lectura,</span>
<span id="cb4-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"practica_h"</span>: practica,</span>
<span id="cb4-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sueno_h"</span>: sueno,</span>
<span id="cb4-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"distraccion"</span>: distraccion,</span>
<span id="cb4-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ruido"</span>: ruido,</span>
<span id="cb4-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"puntuacion"</span>: puntuacion,</span>
<span id="cb4-17">})</span>
<span id="cb4-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(df.head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb4-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb4-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(df.dtypes)</span>
<span id="cb4-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(df), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  nulos ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(df.isna().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> lectura_h  practica_h  sueno_h  distraccion  ruido  puntuacion
      6.61        5.63     6.92        57.86  56.75       72.46
      3.92        0.50     7.37        35.43  50.05       55.81
      7.50        6.92     7.06        56.04  38.75       67.06

lectura_h      float64
practica_h     float64
sueno_h        float64
distraccion    float64
ruido          float64
puntuacion     float64
dtype: object
n = 280   nulos = 0</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> No hay nulos. Todas las columnas son numéricas de verdad (magnitudes), no IDs. <code>puntuacion</code> es <img src="https://latex.codecogs.com/png.latex?y">.</p>
</section>
<section id="etapa-2-centro-dispersión-y-forma-de-y" class="level3">
<h3 class="anchored" data-anchor-id="etapa-2-centro-dispersión-y-forma-de-y">Etapa 2: Centro, dispersión y forma de <img src="https://latex.codecogs.com/png.latex?y"></h3>
<div id="e2-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:21.020608Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:21.020419Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:21.311790Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:21.310902Z&quot;}}" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"puntuacion"</span>]</span>
<span id="cb6-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(y.describe().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb6-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"media ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y.mean(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  mediana ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y.median(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  DE ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(y.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb6-4">graficar_hist_y(y.to_numpy(), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Puntuación: media y mediana cercanas (poco sesgo grosero)"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>count    280.00
mean      67.55
std       11.18
min       37.53
25%       59.66
50%       67.14
75%       75.57
max       98.76
Name: puntuacion, dtype: float64
media = 67.55   mediana = 67.14   DE = 11.18</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/14-proyecto-integrador-final/index_files/figure-html/cell-5-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> El baseline ingenuo (predecir la media) tendrá RMSE del orden de la DE. Un modelo útil debe <strong>bajar</strong> de ese piso en prueba.</p>
</section>
<section id="etapa-3-relaciones-correlación-no-es-causa" class="level3">
<h3 class="anchored" data-anchor-id="etapa-3-relaciones-correlación-no-es-causa">Etapa 3: Relaciones — correlación no es causa</h3>
<div id="e3-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:21.313671Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:21.313444Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:21.475448Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:21.474622Z&quot;}}" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(df.corr(numeric_only<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>).to_string())</span>
<span id="cb8-2">graficar_corr(df, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Matriz de correlación (Pearson)"</span>)</span>
<span id="cb8-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb8-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lectura vs practica (diseñadas juntas):"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lectura_h"</span>].corr(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"practica_h"</span>]), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb8-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ruido vs puntuacion (debe ~ 0):"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ruido"</span>].corr(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"puntuacion"</span>]), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>             lectura_h  practica_h  sueno_h  distraccion  ruido  puntuacion
lectura_h         1.00        0.74    -0.03         0.01   0.07        0.55
practica_h        0.74        1.00     0.04         0.01   0.01        0.52
sueno_h          -0.03        0.04     1.00         0.05   0.01        0.31
distraccion       0.01        0.01     0.05         1.00   0.11       -0.31
ruido             0.07        0.01     0.01         0.11   1.00        0.03
puntuacion        0.55        0.52     0.31        -0.31   0.03        1.00</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/14-proyecto-integrador-final/index_files/figure-html/cell-6-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>
lectura vs practica (diseñadas juntas): 0.742
ruido vs puntuacion (debe ~ 0): 0.026</code></pre>
</div>
</div>
<p><strong>Lectura.</strong> <code>lectura</code> y <code>practica</code> se solapan: en un lineal los <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> de esas dos se <strong>reparten</strong> la señal (no se leen como efectos aislados). <code>ruido</code> no debe ganar peso. Nada de esto prueba que “estudiar más causa” la nota: el laboratorio lo fabricó.</p>
</section>
<section id="etapa-4-partición-la-prueba-no-se-toca-para-elegir" class="level3">
<h3 class="anchored" data-anchor-id="etapa-4-partición-la-prueba-no-se-toca-para-elegir">Etapa 4: Partición — la prueba no se toca para elegir</h3>
<div id="e4-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:21.477165Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:21.476966Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:21.483607Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:21.482941Z&quot;}}" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1">features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lectura_h"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"practica_h"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sueno_h"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"distraccion"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ruido"</span>]</span>
<span id="cb11-2">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[features]</span>
<span id="cb11-3">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"puntuacion"</span>]</span>
<span id="cb11-4">X_tr, X_te, y_tr, y_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb11-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n train ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_tr), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  n test ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(y_te))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>n train = 196   n test = 84</code></pre>
</div>
</div>
</section>
<section id="etapa-5-baseline-y-lineal" class="level3">
<h3 class="anchored" data-anchor-id="etapa-5-baseline-y-lineal">Etapa 5: Baseline y lineal</h3>
<div id="e5-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:21.485545Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:21.485240Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:21.498663Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:21.497586Z&quot;}}" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">dummy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DummyRegressor(strategy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>).fit(X_tr, y_tr)</span>
<span id="cb13-2">lin <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression().fit(X_tr, y_tr)</span>
<span id="cb13-3"></span>
<span id="cb13-4">filas <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb13-5">    ficha(y_tr, dummy.predict(X_tr), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"baseline / train"</span>),</span>
<span id="cb13-6">    ficha(y_te, dummy.predict(X_te), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"baseline / TEST"</span>),</span>
<span id="cb13-7">    ficha(y_tr, lin.predict(X_tr), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lineal / train"</span>),</span>
<span id="cb13-8">    ficha(y_te, lin.predict(X_te), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lineal / TEST"</span>),</span>
<span id="cb13-9">]</span>
<span id="cb13-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.DataFrame(filas).to_string(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>))</span>
<span id="cb13-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb13-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Intercepto ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(lin.intercept_), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb13-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(pd.Series(lin.coef_, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>features).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>).to_string())</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>        conjunto   RMSE     R2
baseline / train 10.846  0.000
 baseline / TEST 11.896 -0.016
  lineal / train  7.320  0.545
   lineal / TEST  8.231  0.514

Intercepto = 37.18
lectura_h      2.200
practica_h     1.264
sueno_h        3.048
distraccion   -0.326
ruido          0.043</code></pre>
</div>
</div>
<p><strong>Cómo leer la tabla.</strong> El lineal debe ganar al baseline <strong>en TEST</strong>. El hueco train–test debe ser chico (modelo rígido, <img src="https://latex.codecogs.com/png.latex?n"> no minúsculo). <code>ruido</code> debe quedar cerca de 0. <code>lectura</code> y <code>practica</code> pueden verse “débiles” por separado aunque juntas sí importen.</p>
</section>
<section id="etapa-6-residuos-en-prueba" class="level3">
<h3 class="anchored" data-anchor-id="etapa-6-residuos-en-prueba">Etapa 6: Residuos en prueba</h3>
<div id="e6-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:21.501361Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:21.501173Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:21.751570Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:21.751022Z&quot;}}" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1">yhat_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lin.predict(X_te)</span>
<span id="cb15-2">e_te <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y_te.to_numpy() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> yhat_te</span>
<span id="cb15-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Media de residuos TEST ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(e_te.mean()), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  (debe ~ 0)"</span>)</span>
<span id="cb15-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE TEST ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse(y_te, yhat_te), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  DE de y (train) ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(y_tr.std(ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb15-5">graficar_residuos(yhat_te, e_te, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Si hay U o embudo, la recta no era toda la historia"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Media de residuos TEST = 0.056   (debe ~ 0)
RMSE TEST = 8.231   DE de y (train) = 10.874</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://biitt.com/es/blog/analisis-de-datos/basico/14-proyecto-integrador-final/index_files/figure-html/cell-9-output-2.png" class="img-fluid figure-img"></p>
</figure>
</div>
</div>
</div>
<p><strong>Lectura.</strong> Banda horizontal: el lineal es una descripción honesta <em>en esta clase de modelo</em>. Un U delataría que faltaba un término no lineal. RMSE se compara con la DE de <img src="https://latex.codecogs.com/png.latex?y"> y con el rango 20–100.</p>
</section>
<section id="etapa-7-hace-falta-ruido" class="level3">
<h3 class="anchored" data-anchor-id="etapa-7-hace-falta-ruido">Etapa 7: ¿Hace falta <code>ruido</code>?</h3>
<p>Se reajusta <strong>sin</strong> <code>ruido</code>, misma partición (no se vuelve a mirar la prueba para <em>elegir</em> a ciegas: aquí es un contraste de diseño).</p>
<div id="e7-code" class="cell" data-quarto-private-1="{&quot;key&quot;:&quot;execution&quot;,&quot;value&quot;:{&quot;iopub.execute_input&quot;:&quot;2026-09-26T01:13:21.753220Z&quot;,&quot;iopub.status.busy&quot;:&quot;2026-09-26T01:13:21.753036Z&quot;,&quot;iopub.status.idle&quot;:&quot;2026-09-26T01:13:21.760857Z&quot;,&quot;shell.execute_reply&quot;:&quot;2026-09-26T01:13:21.760337Z&quot;}}" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1">feats2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lectura_h"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"practica_h"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sueno_h"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"distraccion"</span>]</span>
<span id="cb17-2">lin2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression().fit(X_tr[feats2], y_tr)</span>
<span id="cb17-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE TEST con ruido    ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse(y_te, lin.predict(X_te)), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb17-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE TEST sin ruido    ="</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(rmse(y_te, lin2.predict(X_te[feats2])), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb17-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"El ruido no debería mejorar el test de forma estable. Si baja por azar, es n de prueba."</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>RMSE TEST con ruido    = 8.231
RMSE TEST sin ruido    = 8.152
El ruido no debería mejorar el test de forma estable. Si baja por azar, es n de prueba.</code></pre>
</div>
</div>
</section>
<section id="caso-aplicado-ficha-de-veredicto" class="level3">
<h3 class="anchored" data-anchor-id="caso-aplicado-ficha-de-veredicto">Caso aplicado: ficha de veredicto</h3>
<ol type="1">
<li><strong>Uso.</strong> Estimar la puntuación de un estudiante a partir de hábitos (prioridad pedagógica, no un ranking oficial).</li>
<li><strong><img src="https://latex.codecogs.com/png.latex?y"> y unidad.</strong> Puntos de 20 a 100. Un error de ~8 puntos es del orden del ruido de diseño (<img src="https://latex.codecogs.com/png.latex?%5Csigma=7.5">).</li>
<li><strong>Protocolo.</strong> Test 30%, una vez. Baseline = media de train. Lineal OLS.</li>
<li><strong>Cifras.</strong> RMSE y <img src="https://latex.codecogs.com/png.latex?R%5E2"> de TEST (print etapa 5). Hueco train–test.</li>
<li><strong>Diagnóstico.</strong> Residuos de TEST (etapa 6). <code>ruido</code> no aporta (etapa 7).</li>
<li><strong>Decisión.</strong> <em>Aceptar como baseline estadístico de la plataforma de práctica, no como sistema de calificación automática.</em> Gana a la media, el hueco no denuncia sobreajuste grosero, el RMSE vive cerca del <img src="https://latex.codecogs.com/png.latex?%5Csigma"> inyectado. No se usa para decidir becas: <img src="https://latex.codecogs.com/png.latex?n"> es de laboratorio y <img src="https://latex.codecogs.com/png.latex?y"> es sintética.</li>
</ol>
<blockquote class="blockquote">
<p>En <img src="https://latex.codecogs.com/png.latex?n=280"> estudiantes sintéticos, un lineal con hábitos predice <code>puntuacion</code> con RMSE de TEST <img src="https://latex.codecogs.com/png.latex?8.23"> (baseline de la media, más alto; print de la etapa 5), cerca del ruido de diseño. Residuos sin patrón grosero. Se acepta como suelo descriptivo. Limitación: datos diseñados, una partición, dos <em>features</em> colineales, sin validación temporal.</p>
</blockquote>
</section>
<section id="errores-que-este-proyecto-no-debe-repetir" class="level3">
<h3 class="anchored" data-anchor-id="errores-que-este-proyecto-no-debe-repetir">Errores que este proyecto no debe repetir</h3>
<ol type="1">
<li>Publicar el RMSE de train.</li>
<li>Leer <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> de <code>lectura</code> como “efecto causal de leer”.</li>
<li>Dejar <code>ruido</code> porque “más columnas es más modelo”.</li>
<li>Declarar “bueno” sin baseline.</li>
<li>Olvidar las unidades de <img src="https://latex.codecogs.com/png.latex?y">.</li>
</ol>
</section>
<section id="idea-clave" class="level3">
<h3 class="anchored" data-anchor-id="idea-clave">Idea clave</h3>
<p><strong>El proyecto termina cuando hay un veredicto con conjunto no visto, no cuando <code>LinearRegression</code> corre.</strong></p>
</section>
</section>
<section id="guía-rápida-del-cierre" class="level2">
<h2 class="anchored" data-anchor-id="guía-rápida-del-cierre">6. Guía rápida del cierre</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Paso</th>
<th>Pregunta</th>
<th>Si falla</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>EDA</td>
<td>¿Sé qué es cada columna?</td>
<td>No modelar</td>
</tr>
<tr class="even">
<td><img src="https://latex.codecogs.com/png.latex?y"></td>
<td>¿Cuál es la unidad y la DE?</td>
<td>No hay “alto/bajo”</td>
</tr>
<tr class="odd">
<td><img src="https://latex.codecogs.com/png.latex?r"></td>
<td>¿Hay redundancia o una <img src="https://latex.codecogs.com/png.latex?x"> muerta?</td>
<td>Podar o no sobreinterpretar <img src="https://latex.codecogs.com/png.latex?%5Cbeta"></td>
</tr>
<tr class="even">
<td>Split</td>
<td>¿La prueba votó el modelo?</td>
<td>Hay fuga</td>
</tr>
<tr class="odd">
<td>Baseline</td>
<td>¿Gano a la media en TEST?</td>
<td>No hay señal usable</td>
</tr>
<tr class="even">
<td>Residuos</td>
<td>¿U / embudo?</td>
<td>La recta no basta</td>
</tr>
</tbody>
</table>
</section>
<section id="plantilla-para-el-informe-final" class="level2">
<h2 class="anchored" data-anchor-id="plantilla-para-el-informe-final">7. Plantilla para el informe final</h2>
<blockquote class="blockquote">
<p>“Dataset <code>[…]</code>, <img src="https://latex.codecogs.com/png.latex?n="><code>[...]</code>, <img src="https://latex.codecogs.com/png.latex?y="><code>[unidad]</code>. Baseline TEST = <code>[RMSE]</code>. Modelo <code>[…]</code>, TEST <img src="https://latex.codecogs.com/png.latex?n="><code>[...]</code>: RMSE=<code>[...]</code>, <img src="https://latex.codecogs.com/png.latex?R%5E2="><code>[...]</code>. Hueco train–test: <code>[…]</code>. Residuos: <code>[banda / patrón]</code>. <strong>Veredicto:</strong> <code>[aceptar para… / rechazar]</code>. Limitación: <code>[…]</code>.”</p>
</blockquote>
</section>
<section id="puente" class="level2">
<h2 class="anchored" data-anchor-id="puente">8. Puente</h2>
<p>El avanzado del sitio retoma la recta con más <img src="https://latex.codecogs.com/png.latex?x">, regularización y remuestreo. El criterio no cambia: baseline, conjunto no visto, unidades, límite.</p>
</section>
<section id="cierre" class="level2">
<h2 class="anchored" data-anchor-id="cierre">9. Cierre</h2>
<p>Este notebook cierra el básico con un ciclo completo: dato, descripción, relación, modelo, prueba y <strong>frase de decisión</strong>. El estudiante que puede llenar la plantilla de la sección 7 sin inventar un <img src="https://latex.codecogs.com/png.latex?R%5E2"> de entrenamiento terminó el arco.</p>
<p><strong>Resultado esperado:</strong> un veredicto de diez líneas, no un screenshot del <code>score</code> de train.</p>
<section id="te-sirvió" class="level3">
<h3 class="anchored" data-anchor-id="te-sirvió">💬 ¿Te sirvió?</h3>
<p>Deja en los comentarios <strong>una duda o un caso donde aplicarías esto</strong> — respondo todos. Sígueme para no perderte el próximo artículo de la serie y comparte con alguien que esté aprendiendo análisis de datos.</p>
<p>👉 El código completo está disponible para ejecutar directamente.</p>


</section>
</section>
</section>

 ]]></description>
  <category>estadistica</category>
  <category>proyecto</category>
  <category>evaluacion</category>
  <guid>https://biitt.com/es/blog/analisis-de-datos/basico/14-proyecto-integrador-final/</guid>
  <pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
