{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "9a4b86c6",
   "metadata": {},
   "source": [
    "# 02 · Formatos de datos y pandas\n",
    "\n",
    "Los datos llegan como CSV, JSON, hojas de cálculo, bases de datos o archivos columnares, y el formato en el\n",
    "que los guardas decide cuánto ocupan, lo rápido que se cargan y qué puede salir mal. Este módulo presenta\n",
    "pandas, la herramienta estándar para tablas en Python, y después mide los formatos habituales con los mismos\n",
    "datos.\n",
    "\n",
    "**Aprenderás**\n",
    "1. El `DataFrame` de pandas: crear, inspeccionar, seleccionar, filtrar, agrupar\n",
    "2. Leer y escribir CSV, JSON, Excel, Parquet, Feather, SQLite, YAML y pickle\n",
    "3. Qué formato elegir, con mediciones: tamaño del archivo, tiempo de escritura y de lectura, tipos que se conservan\n",
    "4. Trampas: codificaciones, fechas, tipos perdidos en CSV y por qué nunca debes cargar un pickle que no sea de confianza"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e165447d",
   "metadata": {},
   "source": [
    "## 1. El DataFrame de pandas\n",
    "Una tabla bidimensional con etiquetas: las columnas tienen nombre y tipo, y las filas un índice."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "d8b5578e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T10:07:26.340433Z",
     "iopub.status.busy": "2026-10-18T10:07:26.340078Z",
     "iopub.status.idle": "2026-10-18T10:07:27.090651Z",
     "shell.execute_reply": "2026-10-18T10:07:27.088902Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(4, 4)\n",
      "name      object\n",
      "age        int64\n",
      "city      object\n",
      "salary     int64\n",
      "dtype: object\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>name</th>\n",
       "      <th>age</th>\n",
       "      <th>city</th>\n",
       "      <th>salary</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Alice</td>\n",
       "      <td>30</td>\n",
       "      <td>Berlin</td>\n",
       "      <td>62000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Bob</td>\n",
       "      <td>25</td>\n",
       "      <td>Paris</td>\n",
       "      <td>48000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Charlie</td>\n",
       "      <td>35</td>\n",
       "      <td>Berlin</td>\n",
       "      <td>75000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      name  age    city  salary\n",
       "0    Alice   30  Berlin   62000\n",
       "1      Bob   25   Paris   48000\n",
       "2  Charlie   35  Berlin   75000"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "df = pd.DataFrame({\n",
    "    \"name\": [\"Alice\", \"Bob\", \"Charlie\", \"Diana\"],\n",
    "    \"age\": [30, 25, 35, 28],\n",
    "    \"city\": [\"Berlin\", \"Paris\", \"Berlin\", \"Madrid\"],\n",
    "    \"salary\": [62_000, 48_000, 75_000, 51_000],\n",
    "})\n",
    "print(df.shape)\n",
    "print(df.dtypes)\n",
    "df.head(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "3f3adefe",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T10:07:27.094821Z",
     "iopub.status.busy": "2026-10-18T10:07:27.094363Z",
     "iopub.status.idle": "2026-10-18T10:07:27.110926Z",
     "shell.execute_reply": "2026-10-18T10:07:27.108911Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['Alice', 'Bob', 'Charlie', 'Diana']\n",
      "Berlin\n",
      "{'name': 'Bob', 'age': 25, 'city': 'Paris', 'salary': 48000}\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>name</th>\n",
       "      <th>age</th>\n",
       "      <th>city</th>\n",
       "      <th>salary</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Alice</td>\n",
       "      <td>30</td>\n",
       "      <td>Berlin</td>\n",
       "      <td>62000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Charlie</td>\n",
       "      <td>35</td>\n",
       "      <td>Berlin</td>\n",
       "      <td>75000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      name  age    city  salary\n",
       "0    Alice   30  Berlin   62000\n",
       "2  Charlie   35  Berlin   75000"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(df[\"name\"].tolist())            # una columna (una Series)\n",
    "print(df.loc[0, \"city\"])               # por etiqueta\n",
    "print(df.iloc[1].to_dict())            # por posición\n",
    "df[(df[\"age\"] > 26) & (df[\"city\"] == \"Berlin\")]   # filtrado booleano"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c764fd7a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T10:07:27.115484Z",
     "iopub.status.busy": "2026-10-18T10:07:27.115146Z",
     "iopub.status.idle": "2026-10-18T10:07:27.147367Z",
     "shell.execute_reply": "2026-10-18T10:07:27.145516Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "        people  mean_salary\n",
      "city                       \n",
      "Berlin       2      68500.0\n",
      "Madrid       1      51000.0\n",
      "Paris        1      48000.0\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>age</th>\n",
       "      <th>salary</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>4.000000</td>\n",
       "      <td>4.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>29.500000</td>\n",
       "      <td>59000.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>4.203173</td>\n",
       "      <td>12247.448714</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>25.000000</td>\n",
       "      <td>48000.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>27.250000</td>\n",
       "      <td>50250.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>29.000000</td>\n",
       "      <td>56500.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>31.250000</td>\n",
       "      <td>65250.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>35.000000</td>\n",
       "      <td>75000.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "             age        salary\n",
       "count   4.000000      4.000000\n",
       "mean   29.500000  59000.000000\n",
       "std     4.203173  12247.448714\n",
       "min    25.000000  48000.000000\n",
       "25%    27.250000  50250.000000\n",
       "50%    29.000000  56500.000000\n",
       "75%    31.250000  65250.000000\n",
       "max    35.000000  75000.000000"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df[\"senior\"] = df[\"age\"] >= 30                     # columna nueva\n",
    "summary = df.groupby(\"city\").agg(people=(\"name\", \"count\"), mean_salary=(\"salary\", \"mean\"))\n",
    "print(summary)\n",
    "df.describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "441ad271",
   "metadata": {},
   "source": [
    "## 2. Un conjunto de datos realista para comparar formatos\n",
    "200.000 filas de lecturas de sensores sintéticas con los tipos de columna que tienen los datos reales:\n",
    "marcas de tiempo, enteros, decimales, categorías y texto libre."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "fe411cac",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T10:07:27.151687Z",
     "iopub.status.busy": "2026-10-18T10:07:27.151333Z",
     "iopub.status.idle": "2026-10-18T10:07:27.364313Z",
     "shell.execute_reply": "2026-10-18T10:07:27.362443Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "timestamp      datetime64[ns]\n",
      "sensor_id               int64\n",
      "temperature           float64\n",
      "status               category\n",
      "note                   object\n",
      "dtype: object\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "en memoria: 16.6 MB\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "rng = np.random.default_rng(42)\n",
    "n = 200_000\n",
    "data = pd.DataFrame({\n",
    "    \"timestamp\": pd.date_range(\"2025-01-01\", periods=n, freq=\"min\"),\n",
    "    \"sensor_id\": rng.integers(1, 500, n),\n",
    "    \"temperature\": rng.normal(21, 4, n).round(2),\n",
    "    \"status\": rng.choice([\"ok\", \"warning\", \"fault\"], n, p=[0.9, 0.08, 0.02]),\n",
    "    \"note\": rng.choice([\"\", \"manual check\", \"recalibrated\", \"battery low\"], n),\n",
    "})\n",
    "data[\"status\"] = data[\"status\"].astype(\"category\")\n",
    "print(data.dtypes)\n",
    "print(f\"en memoria: {data.memory_usage(deep=True).sum() / 1e6:.1f} MB\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15665217",
   "metadata": {},
   "source": [
    "## 3. Escribir, leer y comparar\n",
    "Cada formato se escribe y se vuelve a leer tres veces, y comprobamos si los tipos de las columnas sobreviven\n",
    "al viaje de ida y vuelta."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "a29b8c8d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T10:07:27.369759Z",
     "iopub.status.busy": "2026-10-18T10:07:27.369400Z",
     "iopub.status.idle": "2026-10-18T10:07:42.106905Z",
     "shell.execute_reply": "2026-10-18T10:07:42.105509Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>size_mb</th>\n",
       "      <th>write_s</th>\n",
       "      <th>read_s</th>\n",
       "      <th>types_kept</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>format</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>CSV.gz</th>\n",
       "      <td>1.556</td>\n",
       "      <td>2.862</td>\n",
       "      <td>0.328</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Parquet</th>\n",
       "      <td>2.306</td>\n",
       "      <td>0.490</td>\n",
       "      <td>0.034</td>\n",
       "      <td>True</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Feather</th>\n",
       "      <td>4.076</td>\n",
       "      <td>0.044</td>\n",
       "      <td>0.018</td>\n",
       "      <td>True</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Pickle</th>\n",
       "      <td>7.305</td>\n",
       "      <td>0.057</td>\n",
       "      <td>0.031</td>\n",
       "      <td>True</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CSV</th>\n",
       "      <td>8.580</td>\n",
       "      <td>1.226</td>\n",
       "      <td>0.313</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>SQLite</th>\n",
       "      <td>10.482</td>\n",
       "      <td>1.696</td>\n",
       "      <td>0.683</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>JSON</th>\n",
       "      <td>21.780</td>\n",
       "      <td>0.595</td>\n",
       "      <td>1.020</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "         size_mb  write_s  read_s  types_kept\n",
       "format                                       \n",
       "CSV.gz     1.556    2.862   0.328       False\n",
       "Parquet    2.306    0.490   0.034        True\n",
       "Feather    4.076    0.044   0.018        True\n",
       "Pickle     7.305    0.057   0.031        True\n",
       "CSV        8.580    1.226   0.313       False\n",
       "SQLite    10.482    1.696   0.683       False\n",
       "JSON      21.780    0.595   1.020       False"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import os, time, tempfile, sqlite3, warnings\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "tmp = tempfile.mkdtemp()\n",
    "\n",
    "def timed(fn, repeat=3):\n",
    "    best = float(\"inf\")\n",
    "    for _ in range(repeat):\n",
    "        t0 = time.perf_counter(); out = fn(); best = min(best, time.perf_counter() - t0)\n",
    "    return best, out\n",
    "\n",
    "formats = {\n",
    "    \"CSV\":     (\"data.csv\",     lambda p: data.to_csv(p, index=False),          lambda p: pd.read_csv(p)),\n",
    "    \"CSV.gz\":  (\"data.csv.gz\",  lambda p: data.to_csv(p, index=False),          lambda p: pd.read_csv(p)),\n",
    "    \"JSON\":    (\"data.json\",    lambda p: data.to_json(p, orient=\"records\", date_format=\"iso\"), lambda p: pd.read_json(p, orient=\"records\")),\n",
    "    \"Parquet\": (\"data.parquet\", lambda p: data.to_parquet(p, index=False),      lambda p: pd.read_parquet(p)),\n",
    "    \"Feather\": (\"data.feather\", lambda p: data.to_feather(p),                   lambda p: pd.read_feather(p)),\n",
    "    \"Pickle\":  (\"data.pkl\",     lambda p: data.to_pickle(p),                    lambda p: pd.read_pickle(p)),\n",
    "    \"SQLite\":  (\"data.db\",      lambda p: data.to_sql(\"readings\", sqlite3.connect(p), index=False, if_exists=\"replace\"),\n",
    "                                lambda p: pd.read_sql(\"select * from readings\", sqlite3.connect(p))),\n",
    "}\n",
    "rows = []\n",
    "for name, (fname, write, read) in formats.items():\n",
    "    path = os.path.join(tmp, fname)\n",
    "    t_write, _ = timed(lambda: write(path), repeat=1)\n",
    "    t_read, back = timed(lambda: read(path))\n",
    "    same_types = list(back.dtypes.astype(str)) == list(data.dtypes.astype(str))\n",
    "    rows.append(dict(format=name, size_mb=os.path.getsize(path) / 1e6, write_s=t_write, read_s=t_read, types_kept=same_types))\n",
    "\n",
    "results = pd.DataFrame(rows).set_index(\"format\").round(3).sort_values(\"size_mb\")\n",
    "results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "520ee504",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T10:07:42.111664Z",
     "iopub.status.busy": "2026-10-18T10:07:42.111293Z",
     "iopub.status.idle": "2026-10-18T10:07:43.246307Z",
     "shell.execute_reply": "2026-10-18T10:07:43.244146Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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vn3RqFEjVYZFRERUquW58NbT08ObN29gbGyMU6dOKTMmIiIiKiB9fX2EhoYCAJ4+fariaIiIiAjIR+HdsmVLNGrUCLVq1QIAdO3aNce+u3fv/vzIiIiIKN9atGiBJk2a4PHjx3j+/DkA4N69e9n27d69O7p3716E0REREZVOeS68t27dinXr1iE4OBgAFJ73JiIiItWrV68ejh07hsOHDyM6OhpAzjmbrxMjIiIqGnmeXO1jrq6uuHHjhjLiKRU4WQsREeWmsPLEP//8AwAYOnRoYYVWqjBfExFRbpQyudrHWHQTEREVfyy4iYiIiocCvcebiIiIiIiIiPKGhTcRERERERGRErHwJiIiIiIiIlIiFt5ERERERERESlSgydWocPTq/AKaGu9UHQaVAPuPmas6BCKiEqvyrhjIdJNVHQZ9pjgvM1WHQESlGK94ExERERERESkRC28iIiIiIiIiJWLhTURERERERKREpeYZ77S0NFy5cgVPnz6FoaEhatWqBTs7O4U+fn5+CA8PR+XKldGwYUPo6uoCAI4dO4bU1FS0b98+2/E3bdoEBwcH1K9fX+n7QkREVJKFh4fjypUrSExMhLW1NVxdXaV8nOXp06e4ffs20tPTUa9ePSmnx8bGwtvbGx07dkSlSpUUxr537x4uXbqEwYMHQ02N1x+IiKholIqMc/ToUdjY2GDQoEE4deoUtm7dig4dOqBt27aIi4sDAAQEBMDW1hY//vgjTp48iXnz5qF27drYvn07AODJkyfo2bMn4uPjFca/desW+vfvj+RkTrxCRERUUImJiejXrx+qV6+O9evX4+zZs5g+fTocHR2xdetWqd/YsWNRu3ZtbNq0CQcOHEDHjh3Rrl07JCQkwMjICLNnz8by5cuz3cavv/6KnTt3sugmIqIiVeKveF+5cgUdOnTAb7/9hqlTp0Imk0nLTpw4gbS0NADAyJEj4eTkhIMHD0rLY2NjcfPmTQBA7969MWHCBGzfvh3Dhg2T28b69etRvXp1NG3atAj2iIiIqGTq1asX7t27h/v378Pa2lpqf/36Na5fvw4AOH36NP766y9cv34drq6uUp9jx44hLS0N6urq6NevHzZu3IhZs2bJFdhRUVE4cuQINm/eXHQ7RUREhFJwxXvatGmoVauWQtENAJ6enjAxMQEAPHr0SOE28fLly6N169YAAENDQ3Tp0gXr16+X65OcnIx///0XgwYNUuJeEBERlWyXLl3CwYMHsWjRIrmiGwDKlSuHNm3aAPiQrzU1NVG3bl25Pm3atEG5cuUAAAMHDkRkZCSOHTsm12fTpk3Q19dH586dlbgnREREikp04Z2eno5z586hXbt2CkX3f3l4eODvv//GmjVrEBISkm2fwYMH49q1a7h//77UtnfvXiQkJKBfv345jp2SkoL4+Hi5HyIiIvo/p06dgkwmQ7t27XLt5+7ujszMTPTu3Rt+fn5ISkpS6GNrawsPDw+FL8vXr1+PPn36QFtbO9uxma+JiEhZSnThHRcXh9TUVFhaWn6y7z///AMvLy/89ttvsLKygrm5OYYPH46XL19KfTw8PGBnZ4d169ZJbevWrcO3336LChUq5Dj23LlzYWhoKP3kJR4iIqLSJDo6GmZmZtDS0sq1n6OjI3x9fREeHo4WLVrAwMAA7u7u2LVrl1y/QYMG4cCBA3j16hUAwM/PD48ePcr1DjXmayIiUpYSXXjr6elBTU1NrnjOiaGhIZYsWYIXL17g0aNHmDZtGg4dOoSvvvoK6enpUr+BAwdi69atSEtLw7Nnz3DmzBkMHjw417EnT56MuLg46ScsLOyz942IiKgkMTAwQGxsLDIyMj7Zt02bNrhw4QJev36No0ePwtraGj169JAmRAWArl27QldXV5qUbd26dXB1dUWdOnVyHJf5moiIlKVEF95aWlqoV68eLly4kOd1ZDIZ7OzsMHz4cKxcuRL3799HUFCQtLx///548+YNDh48iA0bNsDc3Bxt27b9ZBwGBgZyP0RERPR/GjdujPT0dFy5ciXP6xgYGOCrr77Cli1bUK9ePezdu1dapq2tjd69e2P9+vVISEjA7t27P/lFOfM1EREpS4kuvAHgl19+wcmTJ7Fv3z6FZeHh4UhISAAA3L17V2F5TEwMAMDU1FRqq1ixItq1a4c1a9Zg48aN6N+/P9TV1ZUUPRERUenQtm1bODk5YcKECQrPbQshEBgYCAB4/vy5lLuzpKWlIS4uTi5fAx/mZgkICMBPP/0EIQR69eql3J0gIiLKQYl/nVi3bt0wb9489OrVC+3bt0ejRo2QlJSEe/fu4ebNm7hw4QL09fXxyy+/ICEhAe7u7jA3N0dQUBA2bdqEsWPHwszMTG7MwYMHo0OHDpDJZBg4cKCK9oyIiKjkUFdXh4+PDzp27IhatWqhV69eMDMzQ0hICE6dOoXu3btjypQpCAoKwtChQ9GyZUvUrFkT6enp2LdvH+Lj4zF+/Hi5MZ2dnVGvXj2sWbMG/fr14xVsIiJSGZkQQqg6iKIQEhICHx8fPH36FIaGhnB0dETHjh1RpkwZqc+1a9dw9uxZREZGokKFCmjVqpXCK8YAICMjA+PGjYOZmRmmTp2a71ji4+NhaGiIdi0Doamh/1n7RQQA+4+ZqzoEIipEWXkiLi6u1BWLGRkZOHLkCC5fvoz379/DysoKbdq0QY0aNaQ+8fHx2L9/P+7fvw91dXXY2dmhW7du0NPTUxjv8OHDOHDgAIYPHw5nZ+d8xZL1e9BfEwyZLvP1ly7Oy+zTnYiI8iE/+brUFN7FCQtvKmwsvIlKltJceBcnLLxLFhbeRFTY8pOvS/wz3kRERERERESqxMKbiIiIiIiISIlYeBMREREREREpUYmf1bw4276vEp/dIyIiKubCu5syXxMR0WfhFW8iIiIiIiIiJWLhTURERERERKRELLyJiIiIiIiIlIiFNxEREREREZESsfAmIiIiIiIiUiIW3kRERERERERKxMKbiIiIiIiISIlYeBMREREREREpEQtvIiIiIiIiIiVi4U1ERERERESkRCy8iYiIiIiIiJSIhTcRERERERGRErHwJiIiIiIiIlIiFt5ERERERERESsTCm4iIiIiIiEiJWHgTERERERERKRELbyIiIiIiIiIlYuFNREREREREpEQaqg6gNOvV+QU0Nd6pOgyiz7b/mLmqQyAiUprKu2Ig001WdRhEpERxXmaqDoFKOF7xJiIiIiIiIlIiFt5ERERERERESsTC+yNxcXGIjY1VdRhERESUCyEEwsPDkZaWpupQiIiI8uSLKbxfv34NIUSufdLT0xEdHY3k5Oyfw4qPj0dUVFSO60+fPh39+vWTPr99+5aFOBERUT4kJyfj3btPz1+SkJCA2NjYHHN7eHg43r9/n+2yuLg4WFpawt/fHwCQmZnJQpyIiIq1Yl14JyQkYMiQIShbtixsbW1hbGyMnj174uHDh3L9wsPD0atXLxgZGaFWrVowNjZG06ZNcfHiRbl+f/75Jxo2bJjj9oyMjGBiYiJ9njp1KgYNGlS4O0VERFQC+fr6wtHREUZGRrC0tIS9vT1WrFiB9PR0uX4bN25EjRo1ULFiRdjZ2cHMzAwTJ05ESkqKXD9LS0vs2rUr222pqanBwsICZcqUAfDhy3lLS0vcv39fOTtHRET0mYp14T1q1ChcuHABd+/exevXr/HixQt069YNhw4dkvpERUWhYcOGePv2LR4+fIiYmBjExsaiZcuWaNmyJU6dOpXn7Y0bNw6LFi0C8OHqeGJiIpKTkxEeHo7w8HC5PwoyMzPx6tUrZGZmFt4OExERfYECAwPx3XffoW/fvnj37h3evHmDI0eO4OHDh3j58qXUb/bs2fjhhx8wbdo0xMfH4/Xr1zh69Ch8fHzQvn17ZGRk5Gl7+vr6uHLlCmrWrAkAePHiBQAgOjoa4eHhiImJkev/7t07JCQkFNLeEhER5V+xLrxPnjyJ3r17w8bGBgCgo6ODLl264Oeff5b6TJ06FcnJydi1axcsLS0BALq6upg5cybatGmD4cOH57k4/vhW87Vr18Lb2xvnzp1Dw4YN0bBhQ1y+fBkAMG/ePJiamqJ69eowMDDAyJEjc7y9nYiIqKTz8/ODEAITJkyAhsaHN5VWq1YNy5Ytg4WFBQDg+fPnmDlzJn777Td4eXlBXV0dAODi4oJ///0XJ06cwLZt2/K0vf/eat6mTRsAwPfff4+GDRtKd6sFBQXBw8MDpqamqFy5MhwcHHDu3LlC3XciIqK8KNaFt6WlJQ4dOoSIiIhslwshsHfvXvTu3Rv6+voKy4cPH47g4GApMefH+PHj0b9/f7Rp00a64t28eXMsXrwYGzZswKVLl/D69WsEBwfj6tWrmD59eo5jpaSkID4+Xu6HiIiopLC0tERaWho2b96c45fdPj4+yMjIwPDhwxWW1atXD/Xr18eePXsKtP27d+8CAI4dO4bw8HAcOHAACQkJaNWqFTw9PZGQkIC4uDiMHz8eHTt2zHG+F+ZrIiJSlmJdeK9cuVJ6bqt27doYMmSI3G3mcXFxePPmDWxtbbNdP6v96dOnhRbTwoULMXLkSBgaGuLFixfIzMzEgAEDcnwODQDmzp0LQ0ND6SfryjwREVFJ0LZtW4wbNw6DBw9G+fLl0aZNG8ybN0+6BRwAnj17hnLlysHY2DjbMWxtbQs1X2/fvh1qamoYPHgwYmJiEBkZiXbt2qF8+fI4duxYtuswXxMRkbIU68K7bt26CAwMxJUrVzBw4EC8ePECHTp0QP/+/QFAup3tvxOyZMlq19HRKZR4YmNjERkZif/9739wdXVF/fr14ebmhrlz5+b6XNrkyZMRFxcn/YSFhRVKPERERMXFn3/+iaioKKxevRoODg5Yvnw5atSoId11pqGhgdTU1BzXT0lJKbR8DQABAQGIjo6Wy9dubm5ISUnBmzdvsl2H+ZqIiJRFQ9UBfIqampqULMeNG4e//voLY8eOxYwZM2BlZQVLS0vcu3cv23Wz2mvUqFEosWQ9j7Z69Wp06tQpz+tpaWlBS0urUGIgIiIqrkxMTNC9e3d0794ds2fPhoODAxYvXoyNGzfCwcEB7969w/Pnz2FlZaWw7v3799GgQYNCi0VdXR329va4c+dOntdhviYiImUp1le8s7uKnFVEZ31r3r9/f+zYsQMhISEK6y5cuBAtWrRAtWrVCrR9LS0tudegGBkZwd7eHvv371foy9nNiYiotMouX+vp6cHCwkLK1507d4aBgQHmzZun0Hffvn0ICgoq8Cs8s4rlj3N2w4YNcf/+fTx+/FihP3M2EREVtWJ9xbtRo0bo3Lkz3N3dYW5ujqCgIPzyyy9o0KAB7OzsAAC//vorzp49i1atWmHevHmoW7cuIiMjMXfuXERGRipM1JKRkYHw8HC5Nk1NTVSoUEFh+3Z2dti1axf8/f1Rvnx5mJqaYv78+ejSpQsqVaqEnj17IjU1FadPn0ZgYCA2bNigvINBRERUTG3atAk+Pj7o27cvatasifT0dOzcuRPXrl3DlClTAADGxsbYuHEjevbsCS0tLQwYMABly5bFiRMnMHnyZEyaNAnNmjWTG/fNmzcKObt8+fIK29fX10eFChVw8OBBmJqaQldXF127dsXSpUvRsWNHLFiwALa2tnj06BGWL1+OuXPnom7duso7IERERP9RrAtvHx8frFy5ElOmTEFkZCQqVKiALl26YMyYMZDJZAAAbW1tnDhxAitXrsSSJUsQHh6OFy9ewMbGBvfv30e5cuWk8QwMDCCEQMOGDeW2Y2tri7Nnz8LIyAgmJiZSe9++fXHjxg306tUL8fHx2Lp1Kzp06IDTp09j4cKF6NKlC0xMTPDVV1/hzz//LJqDQkREVMwMGDAAZmZm2Lx5M+7fvw91dXXY2dnh6NGj8PT0lPp17twZ165dw59//gkvLy+8evUKMTExWLVqFYYNGyY3poWFBRYtWoRFixbJta9YsQLNmzeHhYUFypQpI7Vv2LABc+bMwaZNm+Dk5IQDBw7gxIkT+OOPPzBt2jQkJCTAwcEB48ePZ9FNRERFTiaEEKoOorDt3r0b3bt3x549e9C5c2dVh6MgPj4ehoaGaNcyEJoaiq9BI/rS7D9mruoQiEqUrDwRFxcHAwMDVYejNCkpKWjSpAnU1dXh5+cnV0gXB1m/B/01wZDpMl8TlWRxXmaqDoG+QPnJ18X6Ge+C6tq1K8aPH4+pU6fKvcqEiIiIig8tLS3s2rULr1+/xvz581UdDhERkdIU61vNP8fChQuxcOFCVYdBREREuahWrVq2E6ARERGVJCXyijcRERERERFRcVFir3h/Cbbvq1Sin90jIiIqCcK7mzJfExHRZ+EVbyIiIiIiIiIlYuFNREREREREpEQsvImIiIiIiIiUiIU3ERERERERkRKx8CYiIiIiIiJSIhbeRERERERERErEwpuIiIiIiIhIiVh4ExERERERESkRC28iIiIiIiIiJWLhTURERERERKRELLyJiIiIiIiIlIiFNxEREREREZESsfAmIiIiIiIiUiIW3kRERERERERKxMKbiIiIiIiISIlYeBMREREREREpEQtvIiIiIiIiIiVi4U1ERERERESkRBqqDqA069X5BTQ13qk6DCIiKiT7j5mrOgRSgsq7YiDTTVZ1GEREVEjivMyKfJu84k1ERERERESkRCy8iYiIiIiIiJSIhTcRERERERGREpWowvvp06e4ePGiQntoaCguXbqE0NDQT65//vx53L17FxkZGdkuP3nyJMLCwuTaU1JScPLkScTHx3/eDhAREZUSJ0+exIsXL+Ta3r9/D39/f9y8eRPv37/Pcd2kpCRcv34dFy9eRHR0dI7jnzt3TqH94cOHuHPnzmfFTkRElF8lqvDevHkzevfuLX2OiIhA06ZNUadOHUyYMAHNmzdHvXr1cPr0abn1rl+/jrp168LNzQ1TpkxB586dYWFhgS1btiiM7+npiZ49e8q1x8TEwNPTEw8ePFDezhEREZUgnp6eOHbsmPR52bJlqFSpEnr16oUffvgBVlZWGD16NJKSkqQ+6enpmDRpEkxMTDB48GD8/PPPsLa2RseOHRUKcE9PTzRv3hwnTpyQa1+0aBEmTZqk3J0jIiL6jxJVeP/XsGHDkJmZiYiICFy6dAlPnz7F5s2bERkZKfV5+PAhWrRogUaNGiEiIgJ+fn548uQJFi9ejIEDB2Lz5s1yY5YvXx43b97E/v37i3hviIiISqbr169j9OjR2LRpEx48eICrV68iLCwM9vb2SEhIkPoNGzYMGzZswLlz5+Dv749Lly4hJCQEb9++RcuWLeWKdAAwNzfHxIkTIYQo6l0iIiKSU6IL75s3b6Jdu3bQ1dWV2hwdHdGnTx/p89SpU2FmZoa//voLWlpaUnuvXr3Qt29f/Pzzz0hNTZXaTUxMMHLkSEyePDnb29GJiIgof27dugVNTU107NhRatPS0sLIkSNhZvbhlS8BAQFYv349/ve//8HV1VXqZ2Jigg0bNuDRo0f4559/5Mb9+eef8ejRI/z7779FsyNEREQ5KNGFt5OTEzZu3IgzZ84gLS1NYXlmZiaOHj2Kbt26QVNTU2F57969ER0djRs3bsi1T5kyBVFRUVi3bl2e4khJSUF8fLzcDxEREX3g5OSEtLQ0/Prrr3J3pX3s8OHDAAAvLy+FZdWqVUPDhg3h6+sr116xYkWMHz8eU6dOlfsSPSfM10REpCwluvBeu3Yt7O3t4enpCUNDQzRt2hQLFy5EcnIyAODt27d4//49qlatmu36VlZWAD48K/6xcuXKYeLEiZgxY0auk79kmTt3LgwNDaUfS0vLz9sxIiKiEqRRo0ZYtWoVNm7cCAsLC1StWhX9+/fH9evXpT4REREwNTWVu4vtY1ZWVgr5Gvhw1TsxMRErVqz4ZBzM10REpCwluvC2tLTEoUOHEBMTgz179qBBgwaYOXMm2rZtCyEEdHR0AABxcXHZrv/27VsAkPp9bMyYMVBTU8PixYs/GcfkyZMRFxcn/fx3VnQiIqLSbtiwYYiMjIS/vz9+/fVXBAcHo2HDhjh58iSAD7k4Pj4+x+e13759m22+1tfXx9SpUzFnzpwc830W5msiIlKWEl14ZzE2NsbXX3+NhQsXYtWqVTh37hweP34MHR0d1KhRQ+4b9Y/duHEDMpkMdevWVVimo6ODGTNmYP78+Xj16lWu29fS0oKBgYHcDxEREcmTyWRwcnLCsGHDcO7cOdjZ2WH9+vUAgHr16iElJQUBAQEK66Wnp+POnTtwcXHJdtzhw4fD0NAQf/zxR67bZ74mIiJlKdGFd2xsrEJb1rfh2traAICRI0fCx8dH4Tnud+/eYd68efjuu+9gYWGR7fgDBgxA5cqVMXv27EKOnIiIqPR48+aNwpVsdXV1aGlpSfm6Y8eOqFy5Mn777TeFvqtXr0ZkZCRGjBiR7fhlypTBnDlzsGTJkhyfISciIlImDVUHoEytW7eGo6Mj3N3dYW5ujqCgIMyfPx/fffcdqlSpAuBD4X39+nV4enpiwoQJqFu3LiIjI7FkyRIYGhpi1apVOY6vrq6O33//HZ06dSqiPSIiIip5Tp48iRkzZsDLyws1a9ZEeno6du3ahUePHmHNmjUAPnxhvmfPHrRr1w5ff/01+vfvj7Jly+LEiRP4559/sGLFCjg7O+e4jZ49e2LhwoU4cuQI2rRpU0R7RkRE9EGJKrzT09PlXgl25coVeHt74+zZs4iMjESFChWwePFidO3aVeojk8mwadMmHD16FHv27MHFixdhaGiIsWPHom/fvihTpozUt1q1amjcuLHcNjt27IiBAwciJCQEhoaGyt9JIiKiL1x6ejoASDm7W7ducHZ2xpYtW7Bt2zaoq6vD3t4e8+bNg62trbSem5sbHj58iLVr12LXrl1ITU2Fvb09bty4AUdHR7ltfPXVV6hYsaL0WSaT4c8//8Ts2bOzfYSMiIhImWQip1lKvkB9+/ZFREQETp06pepQchUfHw9DQ0O0axkITQ19VYdDRESFZP8x80IZJytPxMXFlcjnjJ8+fQobGxucP38eTZs2VXU4Ocr6PeivCYZMl/maiKikiPMyK5Rx8pOvS8QV78DAQJw6dQp79uzB0qVLVR0OERERZSM1NRXHjh3DqlWrYG1tjYYNG6o6JCIioiJRIiZXO3bsGC5evIjVq1dj0KBBqg6HiIiIspGYmIhVq1ahevXq8PPzg6ampqpDIiIiKhIl4or3mDFjVB0CERERfYKxsTF8fX1VHQYREVGRKxGF95dq+75KJfLZPSIiopIkvLsp8zUREX2WEnGrOREREREREVFxxcKbiIiIiIiISIlYeBMREREREREpEQtvIiIiIiIiIiVi4U1ERERERESkRCy8iYiIiIiIiJSIhTcRERERERGREvE93ioghAAAxMfHqzgSIiIqjpgfigfmayIiyk1WfsjKF7lh4a0CsbGxAABLS0sVR0JEREQ5Yb4mIqK8SEhIgKGhYa59WHirQLly5QAAoaGhn/wFUd7Fx8fD0tISYWFhMDAwUHU4JQaPq3LwuCpHSTmuWd+c6+vrqziS0o35Om9Kyv93ysRjlDc8Tp/GY5Q3RXWchBBISEiAubn5J/uy8FYBNbUPj9YbGhryfxglMDAw4HFVAh5X5eBxVQ4eVyoMzNf5w//vPo3HKG94nD6NxyhviuI45fWLWU6uRkRERERERKRELLyJiIiIiIiIlIiFtwpoaWlh+vTp0NLSUnUoJQqPq3LwuCoHj6ty8LhSYeL5lDc8Tp/GY5Q3PE6fxmOUN8XxOMlEXuY+JyIiIiIiIqIC4RVvIiIiIiIiIiVi4U1ERERERESkRCy8iYiIiIiIiJSI7/EuYklJSXjw4AEMDQ1ha2ur6nC+eBkZGbh8+bJCu729PUxNTVUQ0Zft1atXCAwMRI0aNWBiYpJtn6ioKISFhaFatWooX758EUf4ZXr79i3u378PGxsbVKxYUW5ZZGQknj59Ktcmk8nQpEmTogzxixQSEoL4+HjY2NhAV1c32z6xsbF4+vQpLC0tFY49EVCwvFwac3lISAhiYmJgb28PfX39T/bPyMhAUFAQypQpAysrK2holPw/OZOTk/HgwQPo6emhevXq+Vr37t27iI+PR+PGjaX3x5dUoaGhiI6ORvXq1fP8fuWMjAzp2FpbWys5QtVLSUnB/fv3UbZsWdjb2+dpnbi4ODx79gza2tqoVq0aypQpo+QoVS8qKgrBwcGoXbt2nt+lHR4ejqioKNjZ2eV5nUIjqMjs3btXGBoaCltbW2FoaCgaN24sYmJiVB3WF+3NmzcCgKhTp45o0qSJ9HPs2DFVh/ZFefDggfj+++9FpUqVBACxfft2hT7p6eli0KBBQltbWzg4OAgtLS0xbdo0FUT75Xjy5IkYNGiQqFSpklBTUxMrV65U6LN48WKhq6srd/56eHgUfbBfkJ07dwp7e3tRpUoVUatWLaGnpycWLFig0G/atGlCS0tLOl8HDRokMjIyVBAxFVcFyculLZcnJiaKb7/9Vujq6ooaNWoIXV1dsXr16hz7Z2RkiBkzZggzMzNRs2ZNUaVKFVGlShVx9OjRIoy66B08eFCUK1dO2NjYCCMjI+Hm5iaioqLytO758+eFpqamACASEhKUHKnqvH//XnTs2FE6l3R0dMTy5cs/ud6uXbtEhQoVhI2NjahVq5Zo3bq1iI2NLYKIVePw4cOifPnyolq1asLY2Fi4uLiIyMjIXNeZMGGC0NHREXXq1BFWVlaiYsWKwsfHp4giLno3b94UXbt2FWZmZgKAOHHixCfXSU5OFl27dhU6OjqiZs2aQltbWyxevFj5wX6EhXcRCQsLEzo6OuLPP/8UQgiRkJAg6tSpI7p166biyL5sWYX39evXVR3KF23Pnj1i06ZNIiEhIcfCe8mSJcLIyEgEBQUJIYTw8/MTGhoaJfof9s91+PBh8c8//4h3796JsmXL5lh416pVSwXRfbkWLFggHj16JH329fUVMplM7gu3/fv3C01NTXHx4kUhhBCBgYHC0NBQ/PXXX0UeLxVPBcnLpTGXjx07VlhZWYmXL18KIYTYvn27kMlk4vbt29n2f//+vZg+fbp48+aNEEKIzMxMMWnSJKGnpydevXpVRFEXraioKKGnpyd+//13IcSHY1C/fn3Rvn37T64bGxsrrKysxE8//VTiC+8JEyaIKlWqSF9IeHt7C5lMJm7cuJHjOqdPnxZqampi48aNUtupU6fEgwcPlB6vKsTExAh9fX0xa9YsIYQQSUlJomHDhuLrr7/OcZ3jx48LAMLPz09qGzdunDAwMBDp6elKj1kVNm/eLHbu3ClCQ0PzXHhPnTpVmJubi/DwcCHEhy/LAEh/JxQFFt5FZP78+cLY2FikpaVJbRs3bhQaGhpScqL8yyq89+7dK27cuMFj+ZnS0tJyLLydnJzE8OHD5dpatWolOnbsWETRfdlyK7xr1Kgh/P39xYMHD0RqaqoKovvyWVlZid9++0363KFDB9G2bVu5PoMHDxZ16tQp4siouCpIXi5tuTwjI0MYGxuLefPmybXb2dmJMWPG5Hmc58+fCwDi1KlThRxh8bB06VKhp6cnkpKSpLYdO3YINTU16QuLnHTs2FHMmDFDeHt7l+jCOzMzU5QvX17MmTNHrr1mzZpi5MiROa7XtGlT0a5dO2WHV2ysWLFC6OrqisTERKlt9+7dQiaT5XjVe9u2bUJNTU2kpKRIbd7e3kJNTa3Enk9ZXrx4kefC29zcXEydOlWuzdnZWQwaNEhZ4Sko2Q+RFCO3b9+Gk5OT3DNObm5uSE9PR0BAgAojKxmGDRuG/v37w8zMDF5eXoiLi1N1SCVKWloa7t+/DxcXF7l2Nzc33L59W0VRlRxBQUHo2bMn2rRpA1NTU6xZs0bVIX1RIiMjERkZKfes7e3bt7M9X+/du4e0tLSiDpGKoYLk5dKWy58/f443b94o/L9Uv379fP3bf/36dQCAjY1NocZXXNy+fRu1atWCtra21Obm5obMzEz4+/vnuN6yZcsQHR2NqVOnFkWYKhUWFobY2Nh8nUtJSUm4dOkS2rdvj/j4eNy4cQMvXrwoinBV5vbt26hZs6bcvCVubm4QQuDOnTvZrtOpUyc0aNAAffv2xbFjx7Br1y5MmzYN06ZNg56eXhFFXrxFR0cjMjJS5X/HsvAuIq9fv1aYiCrr8+vXr1URUomgqamJbdu2ITo6GgEBAXjw4AEuXryI0aNHqzq0EiUuLg4ZGRnZnsM8fz+Pk5MTHj16hAcPHiA0NBQLFizAsGHDcPr0aVWH9kXIyMjAwIEDYW1tje7du0vtOf2bm5GRgfj4+KIOk4qhguTl0pbLs/bpc/7tj4qKwtixY9G3b19UrVq10GMsDgpyXty5cwezZs3C1q1boa6urvQYVa0g51J0dDQyMjJw584d2NvbY+jQoahevTq+/vprvHnzRukxq0JBziVdXV2MHj0aZ86cwc8//4yff/4ZBgYG6Natm9Lj/VIUxr9lhYGFdxHR1NREcnKyXFtSUhIAlIpZB5WlbNmy8PLykj7b2tri559/hre3NzIzM1UYWcmiqakJANmewzx/P0/Lli3lrtQOGTIE9erVw86dO1UY1ZchMzMTAwcOhL+/Pw4ePCh3tYn/5tKnFOQcKW3n1ef+2//69Wu0adMG1apVw8qVK5USY3FQkPOib9++6N69OyIjI3HhwgUEBgYCAC5fvozQ0FDlBqwCBTmXstY5efIkAgICcOvWLTx79gyPHz/GL7/8otyAVaQg55KPjw/69u2Lffv24e7duwgJCUGrVq3g4eGBt2/fKjvkL0Jx+TuWhXcRqVq1KiIiIuTasj5XqVJFFSGVWBUqVEBSUlKJvPqgKoaGhjAyMsr2HOb5W/gqVKigcKxJnhACgwcPxvHjx3HmzBnY2dnJLc/p31wjI6M8vQqJSr6C5OXSlsuzrlAX5N/+N2/eoFWrVtDX18fhw4dzfOVfSVCQ88LCwgL+/v6YNGkSJk2ahG3btgEApk+fjpMnTyo3YBWoUqUKZDJZvs6lChUqQFtbG126dJFecWpiYoIuXbrAz89P6TGrQkHOpUOHDqFu3bpo3Lix1DZy5Ei8evUKly5dUl6wXxALCwuoq6ur/O9YFt5FxNPTU/oWKouPjw8sLCxQs2ZNFUb2ZUtMTFRoO378OCpWrMh3TBeyVq1a4eDBg9Ln9PR0+Pr6wtPTU4VRffn+ew7HxcXh2rVrcHR0VFFExV9W0X348GGcPn0aNWrUUOjj6emJw4cPIyMjQ2rz8fHh+UqSvOTlpKQkXLhwQbpqVNpyuZGREVxdXXHgwAGpLS4uDmfPnpX7f+nRo0dyzzJnFd26uro4evRoiX/O1NPTE0FBQXj06JHU5uPjA1NTU9SpUwfAh/cyX7hwQboocOTIEVy4cEH6mT17NoAPf8MMHDiw6HdCyfT19dGgQQO5cykhIQGnT5+WO5ceP34sPcusrq6OVq1aKRRL4eHhMDU1LZK4i5qnpyeePHmCBw8eSG0+Pj4oV64c6tWrBwBITU3FhQsXEBsbCwAwNTVFVFSUXL4LCwuTlpVWT548wa1btwAA2traaNq0qdz5l5SUhBMnThTt3wVFNo1bKZeRkSGaNGki6tatK/bs2SMWLFggNDQ0xKZNm1Qd2hdt0aJFomfPnmLbtm3C19dXjBgxQmhoaIjNmzerOrQvyps3b4Sfn584e/asACBmzJgh/Pz8RHBwsNTn7t27QldXVwwfPlwcOHBAdOnSRZiZmYkXL16oMPLiLT4+Xvj5+Qk/Pz+ho6MjJkyYIPz8/ERgYKDUp1mzZmLmzJnC19dXbNu2TdSrV09UqVKFxzUXP/74o9DU1BT//POPdHz9/PzE48ePpT6RkZHCzMxMdO3aVRw4cEAMGzZM6OrqioCAABVGTsVJXvLyw4cPBQBx5MiRPK9T0hw/flxoaGiI3377Tezfv194eHgIe3t78f79e6lP7969hYuLixDiw+uP6tevL8zNzcWRI0fk/h+Njo5W1W4oVWZmpmjZsqWoXbu28Pb2FosXLxZlypSRe9/5s2fPBACxb9++bMco6bOaC/HhNWAaGhri119/Ffv37xctW7YUdnZ24t27d1Kffv36yb194vbt20JfX1/MmDFDHDt2TMyYMUOoq6uLAwcOqGAPikbr1q2Fg4OD8Pb2Fn/99ZfQ0tISK1askJaHhYUJAMLb21sIIcTjx4+Fnp6e6Nq1qzh8+LD4999/hb29vWjcuHGJfZ1YdHS08PPzEz4+PgKAWLx4sfDz8xMhISFSn2HDhgl7e3vp84ULF4Smpqb4+eefhY+Pj2jdurWwsrIScXFxRRa3TAghiq7ML90SEhKwYMECXL58GQYGBujXrx86dOig6rC+eD4+Pti9ezdevXoFGxsbDB06FE5OTqoO64ty9epV/PTTTwrtnTp1woQJE6TP/v7+WLx4MUJDQ2Fvb49ffvkF1tbWRRnqF+XBgwcYOnSoQnurVq0wY8YMAEB8fDyWL1+OS5cuQUtLCy4uLhg1ahRvh85Fz549ER4ertDevn17TJw4Ufr87NkzzJ8/H0FBQahSpQrGjRsnXX0iAj6dl0NDQ+Hl5YVFixahQYMGeVqnJDp37hxWrlyJmJgYODs7Y9KkSXJX0mbPno2QkBCsXbsWMTEx6Ny5c7bjTJs2Da1bty6qsItUYmIiFi1aBD8/P+jp6eH777/Hd999Jy2PiopC165dMXfuXDRt2lRh/bNnz2Lq1Kk4ceIEdHR0ijL0IuXn54cVK1YgOjoaderUwaRJk2BmZiYt//333/H48WNs2LBBart79y6WLFmC0NBQVKlSBUOHDkXDhg1VEX6ReP/+Pf7880+cP38eurq66N27t9xEaVn/j82ZMwfNmzcH8OHq7rJlyxAUFAQdHR00bNgQI0eORNmyZVW0F8p1/PhxzJo1S6G9X79+GDJkCABg4cKFuH37tvQYB/BhDoW///4bUVFRcHR0xKRJk1CpUqUii5uFNxEREREREZES8RlvIiIiIiIiIiVi4U1ERERERESkRCy8iYiIiIiIiJSIhTcRERERERGRErHwJiIiIiIiIlIiFt5ERERERERESsTCm4iIiIiIiEiJWHgTlRCJiYk4evQo0tLS8OrVK1y/fl0p2zl27BgePXqUr3V8fX3x5MkTpcSTm9jYWOzYsQPp6ek59omLi8OOHTuQnJys9HjCwsJw6tQppW7j5cuXOHLkiFK3QURUGAICAnD69GlVh1HoHj58iJMnT37WGCX12GS5ePEiHj9+rOowclXUv4PCOG/y4vr167h//77St0OKWHgT5dPBgwfx9OlTVYeh4IcffsDvv/+Ojh07YsqUKUorviZOnIjDhw/na50xY8bgxIkTSoknN48fP0avXr1yLarDwsLQq1cvvH37VunxDBo0SPpDIykpCTt27MDOnTuRmZmp0PfAgQPYsWMHXr16Jdc/62fPnj24evWqwrpGRkYYNmwYLl26pPT9ISLKq7t37+Ls2bNybTt37sSsWbNUE5AS+fj4YOrUqZ81hjKOTXa/A1UICwtDp06dULZsWVWHkquiPj8L47wBACEE/P39ceDAAdy+fVtheXx8PDp16oTU1NTP3hblj4aqAyD60vz444+YOnUqqlWrpupQ5JiZmWHDhg04duwYfH19MXLkSFWH9EUwMjJCjx49oKOjo9TtnDx5Enfv3oWvry+AD1fje/XqBQAwNjZG69atpb4PHz5Ep06dIISAn58f3N3dpf7NmzdHhQoVkJqaips3b0JLSwsnTpxA1apVAQBaWloYO3YsJk+ejHPnzil1n4iI8urff//FjRs30Lx5c6nNyckJZcqUUV1QpUx2vwNVmDlzJrp37w5zc3OVxvEpX+L5ef36dQwdOhTq6uowNzfH9evXUalSJfj6+qJSpUoAgK+++grGxsZYt24dRowYoeKISxcW3kT5cPz4cSQmJuL69evQ09ODmpoaunfvjlOnTiEmJgYymQyVKlWCs7MzDAwM5Nb18fGBs7MztLS0cOfOHejq6sLd3R1qamoIDQ3F7du3YWFhAVdXV7n18jr2qFGjEBMTAzU1NfTq1QuGhoYK8SckJODSpUtISUmBm5sbKlas+Ml9jomJweXLl1GxYkU4Oztn2yctLQ1XrlzB27dvUbNmTdja2n5y3ILso7OzM9TV1XHz5k1YWlqiXr16AIA3b97g6tWrKFOmDBo1apRtER0YGIjg4GDY2tqiRo0aUru+vj46deoELS0tCCHg7e2Nxo0bo3LlylKfzMxMeHt7o0mTJlJ7SEgIbt++DX19fTRu3PiThfvff/+N3r17Q1NTU669WbNmWLdunVzhvW7dOjRr1izbwnnKlClo1aoVACAlJQW1atXCH3/8gRUrVkh9evfujZ9//hn37t2Do6NjrnERESlbUFAQHj58iJcvX2LHjh0AAHd3d9SsWRMmJiYK/R8+fIigoCCYm5ujbt26cv9u3r59G+/evYOrqyvu3LmDV69ewd3dHcbGxnj//j0uXrwIAGjcuLHcFdWs9VxcXHD79m28efMGTZs2VciVQghcv34d4eHhsLa2Rt26dT+5f2lpafDz80NmZmaOefJT+5VXeRnj0aNHePDgAaytrVGnTh0AOf8OwsPDIZPJ0KBBA2n9Bw8eIDIyUso1Hx+7S5cu4d27d+jUqRMeP36MmzdvAviQSx0dHaUvgXPy5s0b/Pvvvwr5LSIiAv7+/jA0NISLiwu0tbXzdDwKej7k5Xhmd35+6vzI6VhlRxnnTUpKCvbs2SNdHHr//j3q1KmDOXPmYPny5VK/77//HsuXL2fhXcRYeBPlw7lz5/D+/Xvcvn0bcXFxUFdXR/fu3eHn54fAwEAIIfDs2TM8e/YMu3fvhoeHh7TusGHDYGtri4iICDg6OuLSpUtwcnJCmzZtsGbNGjg4OMDPzw99+vTB33//La2X17Hr1KmD4OBgODg44NatW7CyssK5c+egofHhf/MzZ86gS5cusLKygqGhIa5evYr58+dj1KhROe7v0aNH0bVrV9SqVQtaWlqIj49HbGysXJ+AgAB07NgRhoaGsLS0xOXLl9GpUyf8888/kMlkeTqued1HJycnPHr0CHXr1kWHDh1Qr149rF69Gj/99BNq1aoFfX19vHjxAnv27JErrr28vBAWFoZKlSrhzJkzmDp1KqZMmQLg/241f/HiBSpWrIhly5bh0qVLWLJkidzvvXfv3ggLCwMATJ8+HQsWLECTJk0QGRmJt2/fwtfXN8fEmZqaihMnTmDIkCEKywYOHIjhw4cjNjYW5cuXR1paGjZv3oxFixZ98oq1lpYWKlasiHfv3sm1V6hQAQ4ODjh06BALbyJSucePH+Px48d4/fo19u/fDwCwtrbGwYMHceHCBbRs2RIAkJycjD59+uDixYtwdXXFs2fPIJPJcPDgQVhZWQEANm3ahKNHjyI1NRXVq1dHeHg4Xrx4gcWLF2PmzJmoXr06nj17hoyMDFy/fh1GRkbSesePH0d6ejosLS0RExODyMhIHD16VPrC++3bt2jXrh2eP38OZ2dnXLt2DW5ubti3bx+0tLSy3bfY2Fi0bNkSr1+/hqOjIwICAmBjYyPXJy/79Sl5GSMpKQnff/89Tpw4gYYNGyI6OhpWVlbYt29fjr+Dv//+GxoaGnKF9969e3Ho0CGp8M46dkIIVK5cGdbW1ujUqROePXsmjRUXFwc/Pz+MGTMG//vf/3Lcj1OnTkFTUxMuLi5S29KlSzFlyhQ0adIEKSkpiI6Oxs6dO/OUvwp6PuTleO7cuVPu/MzL+ZHTsfovZZ037u7ucp91dXVhaWmJhIQEufaWLVti9OjReP78eZ7PQSoEgojypWrVqmLNmjW59vnjjz9EjRo15NoqVKggXF1dxfv374UQQty+fVsAEE2aNBHJyclCCCH8/PyETCYTYWFh+R7bxcVFvHv3TgghRExMjNDT0xO7du0SQgiRnJwsrKysxNixY6V1tm7dKjQ1NcXjx4+z3U5ycrKwtLQUU6ZMkdoWL14sAIjFixcLIYRIS0sTNjY2YsGCBVKfV69eCQsLC7FlyxapzcbGRqxcuTLHfcrrPtasWVPExcVJbZcvXxYymUzs2LFDanv27Jm4c+eOtByAmDRpkrR8x44dokyZMiIhIUEIIURAQIAAIF68eCGEEGLlypWiQoUKIj09XVpn0KBBwtPTUwghxJUrV4RMJhNnzpwRQgiRkZEhevToIVxcXERmZma2++Pv7y8AiKdPn0ptYWFhAoDw8/MTzZs3F3/99ZcQQghvb29hZ2cnnj17Ji3/uP+UKVPE9u3bxebNm8WIESNEhQoVxI0bNxS22atXL/Hdd9/ldpiJiIrMxIkTxVdffSXXNmXKFOHh4SF9/uWXX4S7u7uUJzMzM8WAAQPEN998I/UZM2aM0NDQELdu3RJCCJGeni5q1aoltLS0xL1794QQQqSmpgpra2uxaNEiufUAiH379klj9+nTR7i4uEh9xo4dK2rUqCHevHkjhBAiIiJCVKhQQfzxxx857tePP/4o6tSpI+WU4OBgUbZsWdGgQYN87dd/FeTYjBs3TlhaWorQ0FCpbf/+/dJ/Z/c76N27t+jXr59c2+zZs+XiHzNmjJDJZOL8+fM5xiuEEIGBgUJHR0fcvn07xz6TJ08Wbm5ucm3GxsbS3ytCCPH8+fNs81p2Cno+5OV4/vd3kJfzI6/HSlnnTZbt27eLjRs3isGDBwt7e3sRFBQktzwzM1Ooq6vLHXdSPk6uRlRIwsLCcPz4cezcuRMaGhoIDAxEfHy8XJ++fftKtyQ7OztDR0cH/fr1k74pbdiwIQAgODi4QGNn3UZlYmICR0dHBAUFAQCuXLmC58+f49dff5X69+7dGxYWFti7d2+2+3P58mWEhYVhwoQJUtvIkSOhp6cnfT5//jyePn2KihUrYvfu3fD29sapU6dga2uLM2fO5P3g5XEf+/fvL3cL+pYtW+Di4oIePXpIbVZWVtKtdVk+vpWqefPmSE1NxfPnz7ONo3v37njz5o00+3jWbVt9+vQBAOzYsQONGjWSnpFTU1PD5MmTcfPmzRxnaM2aIM3Y2Djb5YMGDcK6desAAGvXrsWgQYOy7Qd8mAl2//798PHxwZkzZ+Ds7Izy5csr9DM2Npa2S0T0JdiwYQNq164NX19feHt7w9vbGxUrVsTZs2chhJD6ubm5Sbf4qquro379+mjSpAlq1aoFANIV1f++gcPW1la6+iiTyfDLL7/g5s2b0ls3duzYgR9++EG6Kmpubo4BAwZIt2ZnZ9euXRgxYoSUG21sbNClS5cC7dfnHpvNmzdjzJgxsLS0lNbr2LFjnsb/FGdnZzRt2lShPTExEX5+fvD29sbt27dhZmaW61tVXr16pZALtbW1cf/+fWRkZAAAqlatKndF/FMKcj4U5HeS1/Mjp2P1MWWfN/v378eePXtw6NAhuLi4KPydIJPJYGhoyL8TihhvNScqBOPGjcOaNWtQv359mJiYSLNox8TEyBWK/002ZcqUkWvT0NCAmpqa3CzceR27XLlycmNraWlJfUNCQqCnpwdTU1O5PjY2NggJCcl2n0JDQ2FkZCQlGOBD8rKwsJA+P3/+HBoaGjh06JDcuhUrVoS9vX2242Ynr/uYNTHIxzFWr179k+N/fGyyvuTIaabzcuXKoW3btti2bRtat24NX19fpKam4rvvvgPw4Vj+d2K9rNvDQkJCso0nK7EmJibKHc8sXbp0wahRo7Bv3z6cOXMGGzZsQEpKSrbxffyMtxACvXr1QqdOnXDnzh25fomJidDX1892DCKi4ub9+/eIiYnBgwcP8Pr1a7ll3377LVJTU6V/v/+bS7W0tLJt+++/8/+9pdba2hrAh3+7K1eujKioqGz/fc8pT6akpODly5fZjpv1xXd+9isneRkjPT0dsbGxecqJBfHf/At8eL2ol5cXLC0tYWVlBW1tbbx79w7R0dE5jqOnp4fExES5ts2bN2PUqFFYunQpmjVrhm7dusHLyyvPj6vl93woyO8kJSUlz+dHdsfqv2Mp+7zJ+jLg/fv38PDwwNChQ7Fnzx65Pvw7oeix8Cb6THfv3sWSJUsQFBQkJbwbN27g0KFDef4mW9ljm5iYIDExESkpKXL/UL9+/TrbiW0AoHz58khISEB6err0nDjwYWKULAYGBkhLS8Pq1auzncwtL/Kzj/9NwkZGRoiJiSnQdnPTp08fDBo0CKtWrcK2bdvQsWNHqXg2MTFBRESEXP+spJjTsbS1tYVMJsOzZ8/kvrjIoqOjAy8vLwwYMABt27ZFpUqVcrwi/zGZTIZ27dph586d0jPiWZ49e6YwUR8RUXGlra2NMmXKwMvLC0OHDlXKNj7OXx9/NjExgZaWFgwMDBSKnNzypJaWFvT19XMcFyic/crLGJqamihTpozCPCyfoqampvBayuy+mM6uCB43bhzGjh2L3377TWqztbXN9e+T6tWrY9euXXJtrVq1QmBgIJ49e4ajR49i3LhxCAoKUtqrvAryO8nP+fGpLwyK6rwBPjzj/d1332Hx4sVy7S9evEBKSkq+LpLQ5+Ot5kT5pKenJ5eUoqKioKWlJX1zDgC7d+8ulG0V1thZM4RmTYICfJjsxt/fX2Eijiyurq7Q1NSUu5p98eJFuW+yPTw8oK2tjdWrV8utm5GRgZcvX+Ypts/Zx9atW+PcuXMIDQ2V2oQQ+f7D47/at28PmUyGzZs3w9fXV7rNHPgwccm5c+fktuHt7Q0TExO5Cd0+Vq5cOdStW1eaXTU7P/zwA9q2bYvx48fnK9bg4GBoa2vLffGRmpqKGzduSFfGiYhU7b+587/U1NTg6emJNWvWSLccZ/nvl50FdefOHbkvNffu3QtTU1PpS98mTZrIPX4lhMCePXtyzJNZ63ycW9PS0nDw4EHpc2HsV17GUFNTQ6tWrbBlyxa5wvfjL6ez+x1YWFgoPN6W13d9R0VFyRVut2/fxtOnT3Nd56uvvkJERIR0lTgtLU36u8La2hojRoxAr169cOXKFQAfJjTbsWNHrlfR86ugv5OCnB+5jaWM8+bFixcKbVlvgvnYxYsXUa5cOentMFQ0eMWbKJ9cXV2xYcMGGBgYQFtbG23atIGxsTG6du2Kjh074tq1a/D29i6UbTVo0KBQxq5QoQKmTp2KwYMH49GjRzA0NMTixYvx7bffwtPTM8d1fvrpJ/Tv3x+TJk1CmTJl8Ndff8ndlmRqaoply5ZhxIgRePToERo1aoSIiAjs2bMHs2bNytOzZZ+zj15eXti+fTsaN26MUaNGQU9PD97e3vjtt98+q+jU1tZGly5dMGHCBBgaGsq96qtPnz5YuXIlmjdvjhEjRiA8PByLFi3CypUrc32l2JAhQ7Bq1SpMnDgx2+WOjo65PkeY5ezZs3j16hXS09Nx7949LF26FJMnT5a7K+HgwYMwMTGRi5uISJVcXV3x+++/Y+nSpTAzM8u2WFmyZAk8PDzg7u4OLy8vZGZm4ty5c9DT08PmzZs/OwYDAwO0bdsWo0aNwsuXL7FgwQIsWbJEenXVvHnz0LhxY/Tu3RvNmzfHgQMH8PTp01y/DJ49ezbc3d0xYMAANGrUCDt27EBCQgLMzMwKdb/yMsaff/6Jpk2bonXr1ujSpQtevnyJ3bt3IyAgAED2vwMvLy8sXLgQo0aNgrOzMw4dOoRHjx4p3FKdnU6dOmHSpEmIjY1FQkICFi9eLDcPTHbs7Ozg4eGB7du3Y9KkSUhLS0Pjxo3x9ddfw9nZGTExMdi0aRMWLFgAAHjy5Al69eqFS5cuyR3Tz1WQ30lBzo+cKOu8mTBhAtTU1NCoUSOoqanh+PHjOHr0KA4cOCDXb+fOnejfvz/U1dXzHTsVHAtvonxavHgxVqxYgVOnTiE9PR3du3fHlStXsGLFCpw7dw62trY4f/48Zs+eLVekdurUSeF5ni5duih8C9mjRw/p+SBDQ8MCj92yZUu5K7C//vor6tSpg4MHD+LZs2eYOnUq+vbtm+u+zp49GzVq1MCpU6dQsWJF+Pj4YMeOHXLfcA8ePBj169fHjh07cP78eVSrVg07d+6U2/a3336b47u9P2cf1dXVcfDgQezYsQNnz55F2bJlMXfuXDRu3BjAh9sHe/ToIffOyzJlyqBHjx7Sc99GRkbo0aOHQtE8fPhwvH//Hs2aNZMratXU1HD69GmsXbsW165dg56eHo4fPy736rPs9OvXD3PnzsW5c+fg4eEBXV1d9OjRQ+G5+yxly5aVW57VPzg4GMHBwdDQ0IC5uTkOHz4sTfSWZdmyZZg0aRITKhEVG23btsXatWtx7tw5XLp0CdbW1nByckKZMmWkPra2trh37x42btyIW7duwcjICP3790eHDh2kPvXq1YO5ubnc2PXr11d4XVJW4fGxxo0bY+LEifDx8cGbN2/g7e2N9u3bS8udnJxw584drFu3Dn5+fqhXrx5WrVqV7SNCWVxdXXHlyhWsXbsW/v7+GDJkCHR1dXHjxo187dd/FeTY2Nvb4969e1i7di2uXLkCGxsbnD59OtffQYMGDXDp0iVs3boV/v7+6NevH/r164dbt27leswBYNWqVVi9ejWuXbsGQ0ND7N27F4cPH5YmNcvJtGnTMHDgQIwfPx66urq4c+cONm7ciMuXL8PAwAD79u1DixYtAHyYHLZ+/frS5LP/VdDzIa+/k49vG8/L+ZHTsfovZZ03W7dulSZfTUlJQePGjbFq1Sq5gj4kJASnTp3C3bt3PxknFS6Z+NyHUImIKE+OHj2KBw8e5Pt28vwICQnB3LlzsXz5chbeRET/39ixYxEcHKwwGSipxvTp09G2bVs0atQo135Lly5Fw4YN4ebmVkSR/Z/Ro0dLd/GVJNu3b0dycjIGDBig6lBKHRbeRERERFSisfCmvEpNTcWWLVswbdo0TJo0CT/++KOqQ6ISgreaExEREVGJltdbgIlSUlLg5+eHqVOnKm2GfSqdeMWbiIiIiIiISIn4OjEiIiIiIiIiJWLhTURERERERKRELLyJiIiIiIiIlIiFNxEREREREZESsfAmIiIiIiIiUiIW3kRERERERERKxMKbiIiIiIiISIlYeBMREREREREpEQtvIiIiIiIiIiX6f4tVxEp7faJVAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 1000x340 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "fig, ax = plt.subplots(1, 2, figsize=(10, 3.4))\n",
    "results[\"size_mb\"].plot.barh(ax=ax[0], color=\"#4f46e5\"); ax[0].set_xlabel(\"tamaño del archivo (MB)\")\n",
    "results[\"read_s\"].plot.barh(ax=ax[1], color=\"#0ea5e9\"); ax[1].set_xlabel(\"tiempo de lectura (s, mejor de 3)\")\n",
    "for a in ax: a.invert_yaxis()\n",
    "plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "87bf164c",
   "metadata": {},
   "source": [
    "**Cómo leer el resultado.** Los formatos binarios columnares (Parquet, Feather) son los más pequeños y\n",
    "rápidos *y además* conservan los tipos: las marcas de tiempo siguen siendo marcas de tiempo y las categorías\n",
    "siguen siendo categorías. CSV y JSON pierden los tipos, así que `timestamp` vuelve como texto y `status` como\n",
    "cadenas normales, salvo que le digas al lector qué esperar:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "456b7de7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T10:07:43.250153Z",
     "iopub.status.busy": "2026-10-18T10:07:43.249672Z",
     "iopub.status.idle": "2026-10-18T10:07:43.691576Z",
     "shell.execute_reply": "2026-10-18T10:07:43.689926Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "timestamp      datetime64[ns]\n",
      "sensor_id               int64\n",
      "temperature           float64\n",
      "status               category\n",
      "note                   object\n",
      "dtype: object\n"
     ]
    }
   ],
   "source": [
    "back = pd.read_csv(os.path.join(tmp, \"data.csv\"),\n",
    "                   parse_dates=[\"timestamp\"], dtype={\"status\": \"category\"}, keep_default_na=False)\n",
    "print(back.dtypes)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c2667eba",
   "metadata": {},
   "source": [
    "## 4. Formatos pequeños de configuración e intercambio\n",
    "No todo es una tabla. La configuración vive en YAML, TOML o JSON; las API intercambian JSON."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ee86d2b1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T10:07:43.696239Z",
     "iopub.status.busy": "2026-10-18T10:07:43.695872Z",
     "iopub.status.idle": "2026-10-18T10:07:43.779545Z",
     "shell.execute_reply": "2026-10-18T10:07:43.778206Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "model:\n",
      "  name: baseline\n",
      "  layers:\n",
      "  - 64\n",
      "  - 32\n",
      "train:\n",
      "  epochs: 10\n",
      "  lr: 0.001\n",
      "\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "import json, yaml, tomllib\n",
    "\n",
    "config = {\"model\": {\"name\": \"baseline\", \"layers\": [64, 32]}, \"train\": {\"epochs\": 10, \"lr\": 0.001}}\n",
    "as_json = json.dumps(config, indent=2)\n",
    "as_yaml = yaml.safe_dump(config, sort_keys=False)\n",
    "print(as_yaml)\n",
    "assert json.loads(as_json) == yaml.safe_load(as_yaml) == config\n",
    "\n",
    "toml_text = '[model]\\nname = \"baseline\"\\nlayers = [64, 32]\\n\\n[train]\\nepochs = 10\\nlr = 0.001\\n'\n",
    "print(tomllib.loads(toml_text) == config)     # TOML: lo que usa pyproject.toml (módulo 07)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dbb83ceb",
   "metadata": {},
   "source": [
    "## 5. Excel\n",
    "Habitual en entornos de empresa. Lento y frágil con los tipos comparado con Parquet, pero a veces es el\n",
    "formato que necesita quien va a leer los datos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "ee1783dc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T10:07:43.783774Z",
     "iopub.status.busy": "2026-10-18T10:07:43.783414Z",
     "iopub.status.idle": "2026-10-18T10:07:44.069124Z",
     "shell.execute_reply": "2026-10-18T10:07:44.067419Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "    status   count   mean    max\n",
      "0    fault    4045  20.84  37.87\n",
      "1       ok  180055  21.01  40.97\n",
      "2  warning   15900  21.01  35.84\n"
     ]
    }
   ],
   "source": [
    "path = os.path.join(tmp, \"summary.xlsx\")\n",
    "summary_by_status = data.groupby(\"status\", observed=True)[\"temperature\"].agg([\"count\", \"mean\", \"max\"]).round(2)\n",
    "with pd.ExcelWriter(path) as xl:\n",
    "    summary_by_status.to_excel(xl, sheet_name=\"by_status\")\n",
    "    data.head(100).to_excel(xl, sheet_name=\"sample\", index=False)\n",
    "print(pd.read_excel(path, sheet_name=\"by_status\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b2f4a9de",
   "metadata": {},
   "source": [
    "## 6. Trampas que conviene conocer\n",
    "- **Codificaciones.** Los archivos de otros sistemas pueden no estar en UTF-8: `pd.read_csv(path, encoding=\"latin-1\")`.\n",
    "- **Separadores decimales y de miles.** Los CSV europeos suelen usar `;` y `,`: `pd.read_csv(path, sep=\";\", decimal=\",\")`.\n",
    "- **Fechas.** `01/02/2025` significa días distintos en países distintos; prefiere ISO 8601 (`2025-02-01`).\n",
    "- **Cargar un pickle ejecuta código.** Está bien para tus propios objetos en caché, pero nunca cargues un\n",
    "  pickle de una fuente no fiable. La demostración de abajo ejecuta una orden solo con deserializarse:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "4f59da39",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T10:07:44.073270Z",
     "iopub.status.busy": "2026-10-18T10:07:44.072899Z",
     "iopub.status.idle": "2026-10-18T10:07:44.079464Z",
     "shell.execute_reply": "2026-10-18T10:07:44.078061Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "esto se ejecutó durante pickle.loads: podría haber sido cualquier orden\n"
     ]
    }
   ],
   "source": [
    "import pickle\n",
    "\n",
    "class Malicious:\n",
    "    def __reduce__(self):                      # le dice a pickle cómo \"reconstruir\" el objeto\n",
    "        return (print, (\"esto se ejecutó durante pickle.loads: podría haber sido cualquier orden\",))\n",
    "\n",
    "payload = pickle.dumps(Malicious())\n",
    "pickle.loads(payload)                           # imprime: cargarlo ejecutó código"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "899d9bc2",
   "metadata": {},
   "source": [
    "## ¿Qué formato y cuándo?\n",
    "\n",
    "| Necesidad | Usa |\n",
    "|---|---|\n",
    "| Datos de análisis, cualquier cosa de más de unos pocos MB | **Parquet** (comprimido, tipado, columnar, legible por cualquier herramienta) |\n",
    "| Intercambio temporal rápido entre Python y R | Feather / Arrow IPC |\n",
    "| Legible por personas, pequeño, universal | CSV (con tipos explícitos al leer) |\n",
    "| Datos anidados, API web | JSON |\n",
    "| Configuración | YAML o TOML |\n",
    "| Muchos escritores, consultas, transacciones | una base de datos (SQLite en local, PostgreSQL en un servidor) |\n",
    "| Personas que viven en hojas de cálculo | Excel |\n",
    "| Guardar en caché tus propios objetos de Python | pickle (solo datos de confianza) |\n",
    "\n",
    "## Ejercicios\n",
    "1. Añade una columna `float32` y comprueba qué formatos mantienen `float32` tras el viaje de ida y vuelta.\n",
    "2. Escribe las lecturas en Parquet particionado por `status` (`partition_cols=[\"status\"]`) y vuelve a leer solo las filas `fault`.\n",
    "3. Carga el CSV con `usecols=[\"timestamp\", \"temperature\"]` y compara el tiempo con cargarlo todo."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
