{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CwG7lZuo8LoM"
      },
      "source": [
        "# Clase 3 -24/07 — Del hallazgo al documento\n",
        "### Curaduría de datos abiertos · Codebook, README y publicación\n",
        "\n",
        "En la Clase 2 auditamos el dataset y encontramos sus fallas. Hoy hacemos lo que falta para que sea publicable: **documentarlo**.\n",
        "\n",
        "El principio de toda la clase:\n",
        "\n",
        "> **La máquina hace el inventario. Las personas deciden su significado.**\n",
        "\n",
        "Cada bloque genera automáticamente lo que una computadora puede saber sola, y deja en blanco  lo que requiere una decisión humana. Eso que queda en blanco es el trabajo de curaduría.\n",
        "\n",
        "---\n",
        "⚠️ **Antes de empezar:** `Archivo → Guardar una copia en Drive`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Zh0m4Rvw8LoS"
      },
      "source": [
        "## 0. Preparación"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "qxVt3f4G8LoS",
        "outputId": "0f364343-e15d-4587-a960-7ea94e2b9268"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Entorno listo ✔\n"
          ]
        }
      ],
      "source": [
        "import pandas as pd\n",
        "import datetime\n",
        "\n",
        "pd.set_option('display.max_columns', None)\n",
        "pd.set_option('display.max_rows', 100)\n",
        "\n",
        "print(\"Entorno listo ✔\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZBnUyOBi8LoV"
      },
      "source": [
        "## 1. Cargar el dataset\n",
        "\n",
        "**Si terminaste tu propia reparación en la Clase 2:** subí tu CSV al panel de carpeta (ícono de carpeta a la izquierda, arrastrar el archivo) y usá la Opción B.\n",
        "\n",
        "**Si no llegaste a terminarla:** usá el archivo de referencia con la Opción A. Es una versión con reparaciones mínimas documentadas — y trabajar sobre el archivo de otro es exactamente lo que hace un curador de repositorio todos los días.\n",
        "\n",
        "### Opción A — Archivo de referencia desde Drive"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Bc82ftyW8LoX",
        "outputId": "e78021c8-df51-4aa9-dc52-fc9f88abeee1"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Cargado: 1902 filas y 25 columnas\n"
          ]
        }
      ],
      "source": [
        "FILE_ID = \"1y6pUwXFgrWRdd0rSLFIxZs0V2XCHuc_H\" # ID del archivo de Google Drive\n",
        "\n",
        "URL = f\"https://drive.google.com/uc?export=download&id={FILE_ID}\" # URL de descarga directa\n",
        "\n",
        "df_limpio = pd.read_csv(URL, dtype=str, keep_default_na=False)\n",
        "print(f\"Cargado: {df_limpio.shape[0]} filas y {df_limpio.shape[1]} columnas\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ls5_ufRt8LoY"
      },
      "source": [
        "### Opción B — Tu propio archivo, subido al panel de carpeta"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "13yESXmC8Loa"
      },
      "outputs": [],
      "source": [
        "# Cambiá el nombre por el de tu archivo\n",
        "# df_limpio = pd.read_csv('mi_archivo_limpio.csv', dtype=str, keep_default_na=False)\n",
        "# print(f\"Cargado: {df_limpio.shape[0]} filas y {df_limpio.shape[1]} columnas\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "a2xFab_N8Lob"
      },
      "source": [
        "### Por qué `dtype=str`\n",
        "\n",
        "Le dice a pandas: **leé todo como texto, no adivines tipos.**\n",
        "\n",
        "Sin eso, `id_provincia` con valor `06` se convierte en `6` y `cod_localidad` con valor `06854100` se convierte en `6854100`. Los ceros iniciales desaparecen y los códigos INDEC quedan destruidos — en 540 filas.\n",
        "\n",
        "Es la lección de la Clase 2 en una sola palabra: **hay fallas que se arreglan corrigiendo la lectura, no el dato.**\n",
        "\n",
        "Verificalo:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "yAllKgOa8Loc",
        "outputId": "8c096825-39e1-4dd2-dc4b-7dc85b34e7c2"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "id_provincia: 06\n",
            "cod_localidad: 06854100\n",
            "\n",
            "Si ves '06' y '06854100', los ceros sobrevivieron ✔\n"
          ]
        }
      ],
      "source": [
        "print(\"id_provincia:\", df_limpio['id_provincia'].iloc[0])\n",
        "print(\"cod_localidad:\", df_limpio['cod_localidad'].iloc[0])\n",
        "print(\"\\nSi ves '06' y '06854100', los ceros sobrevivieron ✔\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pgGQraV68Lod"
      },
      "source": [
        "---\n",
        "# BLOQUE 0 · Recuperar el diagnóstico de la Clase 2\n",
        "\n",
        "Antes de documentar, recuperamos todo lo que encontramos la clase pasada — de una sola vez, en un informe consolidado.\n",
        "\n",
        "**Esto no es repetir el trabajo:** el diagnóstico de la Clase 2 es exactamente la materia prima de la columna `observaciones` del codebook. Nada de lo que hicimos se descarta; se transcribe al documento.\n",
        "\n",
        "Ejecuten la celda y **guarden la salida**: la van a copiar mientras completan el codebook."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "R0u83k678Loe",
        "outputId": "0b2bf0f0-e7dd-4c86-e259-006a824a645b"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "==============================================================\n",
            "DIAGNOSTICO CONSOLIDADO\n",
            "==============================================================\n",
            "\n",
            "Filas: 1902   Columnas: 25\n",
            "\n",
            "[1] COLUMNAS SIN INFORMACION -> 9 de 25\n",
            "    100% vacias (5): ['observacion', 'subcategoria', 'piso', 'web', 'informacion_adicional']\n",
            "    Valor constante (4): ['categoria', 'tipo_latitud_longitud', 'fuente', 'anio_actualizacion']\n",
            "\n",
            "[2] FALTANTES (columnas afectadas, de mayor a menor)\n",
            "    departamento                 1  (0.1%)\n",
            "    localidad                    1  (0.1%)\n",
            "    cod_tel                    165  (8.7%)\n",
            "    telefono                   165  (8.7%)\n",
            "    mail                       880  (46.3%)\n",
            "    fecha_fundacion             40  (2.1%)\n",
            "\n",
            "[3] DUPLICADOS\n",
            "    Filas exactas repetidas: 0\n",
            "    nro_conabip repetidos:   0\n",
            "\n",
            "[4] INTEGRIDAD REFERENCIAL\n",
            "    id_departamento distintos: 437\n",
            "    nombres de departamento distintos: 366\n",
            "    codigos con MAS DE UN nombre: 40\n",
            "      06021 -> ['Alberti', 'Bragado']\n",
            "      06028 -> ['Almte Brown', 'Merlo', 'Quilmes']\n",
            "      06091 -> ['Berazategui', 'Quilmes']\n",
            "\n",
            "[5] VALORES DE RELLENO SOSPECHOSOS\n",
            "    fecha_fundacion '1980-01-01': 468 filas (24.6%)\n",
            "    fecha_fundacion '1996-07-01': 3 filas (0.2%)\n",
            "    telefono == '0': 37   cod_tel == '0': 37\n",
            "\n",
            "[6] COORDENADAS\n",
            "    tipo_latitud_longitud declara: ['Exacta']\n",
            "    filas que comparten coordenada exacta con otra: 33\n",
            "\n",
            "[7] FORMATOS MEZCLADOS EN cp\n",
            "    CP viejo de 4 digitos: 1657   CPA alfanumerico: 236\n",
            "    No coinciden con ningun formato: ['0', 'AB1647VA', 'AB7607XA', 'B600GZC', 'N3338WA', 'X5809BW9', 'xxxx']\n",
            "\n",
            "[8] ENCODING\n",
            "    Patrones de mojibake encontrados: ninguno — el archivo esta correctamente en UTF-8\n",
            "\n",
            "==============================================================\n",
            "Copien lo que corresponda a la columna 'observaciones' del codebook.\n",
            "==============================================================\n"
          ]
        }
      ],
      "source": [
        "vacio = lambda s: s.astype(str).str.strip() == ''\n",
        "\n",
        "print(\"=\"*62)\n",
        "print(\"DIAGNOSTICO CONSOLIDADO\")\n",
        "print(\"=\"*62)\n",
        "print(f\"\\nFilas: {len(df_limpio)}   Columnas: {df_limpio.shape[1]}\")\n",
        "\n",
        "# 1. Columnas sin informacion\n",
        "vacias = [c for c in df_limpio.columns if vacio(df_limpio[c]).all()]\n",
        "const  = [c for c in df_limpio.columns if c not in vacias and df_limpio[c].nunique() == 1]\n",
        "print(f\"\\n[1] COLUMNAS SIN INFORMACION -> {len(vacias)+len(const)} de {df_limpio.shape[1]}\")\n",
        "print(f\"    100% vacias ({len(vacias)}): {vacias}\")\n",
        "print(f\"    Valor constante ({len(const)}): {const}\")\n",
        "\n",
        "# 2. Faltantes\n",
        "print(\"\\n[2] FALTANTES (columnas afectadas, de mayor a menor)\")\n",
        "for c in df_limpio.columns:\n",
        "    n = vacio(df_limpio[c]).sum()\n",
        "    if 0 < n < len(df_limpio):\n",
        "        print(f\"    {c:<24} {n:>5}  ({n/len(df_limpio)*100:.1f}%)\")\n",
        "\n",
        "# 3. Duplicados\n",
        "print(\"\\n[3] DUPLICADOS\")\n",
        "print(f\"    Filas exactas repetidas: {df_limpio.duplicated().sum()}\")\n",
        "print(f\"    nro_conabip repetidos:   {df_limpio.duplicated(subset=['nro_conabip']).sum()}\")\n",
        "\n",
        "# 4. Integridad referencial\n",
        "d = df_limpio[~vacio(df_limpio['departamento'])]\n",
        "g = d.groupby('id_departamento')['departamento'].nunique()\n",
        "rotos = g[g > 1]\n",
        "print(f\"\\n[4] INTEGRIDAD REFERENCIAL\")\n",
        "print(f\"    id_departamento distintos: {df_limpio['id_departamento'].nunique()}\")\n",
        "print(f\"    nombres de departamento distintos: {d['departamento'].nunique()}\")\n",
        "print(f\"    codigos con MAS DE UN nombre: {len(rotos)}\")\n",
        "for cod in list(rotos.index)[:3]:\n",
        "    print(f\"      {cod} -> {sorted(d[d['id_departamento']==cod]['departamento'].unique())}\")\n",
        "\n",
        "# 5. Valores de relleno\n",
        "print(\"\\n[5] VALORES DE RELLENO SOSPECHOSOS\")\n",
        "top = df_limpio[~vacio(df_limpio['fecha_fundacion'])]['fecha_fundacion'].value_counts().head(2)\n",
        "for v, n in top.items():\n",
        "    print(f\"    fecha_fundacion '{v}': {n} filas ({n/len(df_limpio)*100:.1f}%)\")\n",
        "print(f\"    telefono == '0': {(df_limpio['telefono']=='0').sum()}   cod_tel == '0': {(df_limpio['cod_tel']=='0').sum()}\")\n",
        "\n",
        "# 6. Geo\n",
        "dup = df_limpio.duplicated(subset=['latitud','longitud'], keep=False)\n",
        "print(f\"\\n[6] COORDENADAS\")\n",
        "print(f\"    tipo_latitud_longitud declara: {list(df_limpio['tipo_latitud_longitud'].unique())}\")\n",
        "print(f\"    filas que comparten coordenada exacta con otra: {dup.sum()}\")\n",
        "\n",
        "# 7. Formatos\n",
        "cp4  = df_limpio['cp'].str.match(r'^\\d{4}$')\n",
        "cpa  = df_limpio['cp'].str.match(r'^[A-Z]\\d{4}[A-Z]{3}$')\n",
        "print(f\"\\n[7] FORMATOS MEZCLADOS EN cp\")\n",
        "print(f\"    CP viejo de 4 digitos: {cp4.sum()}   CPA alfanumerico: {cpa.sum()}\")\n",
        "print(f\"    No coinciden con ningun formato: {sorted(df_limpio.loc[~cp4 & ~cpa, 'cp'].unique())}\")\n",
        "\n",
        "# 8. Encoding\n",
        "print(\"\\n[8] ENCODING\")\n",
        "sosp = ['Ã','Â','â€','\\ufffd']\n",
        "hall = [(c,s,int(df_limpio[c].str.contains(s, regex=False).sum()))\n",
        "        for c in df_limpio.columns for s in sosp\n",
        "        if df_limpio[c].str.contains(s, regex=False).sum() > 0]\n",
        "print(f\"    Patrones de mojibake encontrados: {hall if hall else 'ninguno — el archivo esta correctamente en UTF-8'}\")\n",
        "\n",
        "print(\"\\n\" + \"=\"*62)\n",
        "print(\"Copien lo que corresponda a la columna 'observaciones' del codebook.\")\n",
        "print(\"=\"*62)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ofcaZqgM8Loe"
      },
      "source": [
        "### Lean el informe con atención a tres cosas\n",
        "\n",
        "1. **`[3] Duplicados` da cero en todo.** No hay filas repetidas ni identificadores repetidos. Eso también es un resultado: una auditoría verifica lo que está bien.\n",
        "2. **`[8] Encoding` no encuentra nada.** El archivo está correctamente en UTF-8. Ídem.\n",
        "3. **`[4] Integridad referencial`.** Ahí sí: 437 códigos de departamento para 366 nombres, y 40 códigos que apuntan a más de un nombre. El código `06028` corresponde a Almirante Brown según INDEC, y en este dataset lleva también bibliotecas de Merlo y de Quilmes. Son tres partidos distintos del conurbano.\n",
        "\n",
        "**La pregunta que ordena el resto de la clase:** de todo lo que aparece en ese informe, ¿qué se repara y qué se documenta? No es lo mismo, y casi nada de esto se arregla limpiando."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ldTCBkqu8Lof"
      },
      "source": [
        "---\n",
        "# BLOQUE A · Codebook\n",
        "\n",
        "Un codebook es el diccionario del dataset: **una entrada por variable**, con su definición, su tipo, sus valores posibles y sus rarezas.\n",
        "\n",
        "Sin codebook, un dataset es una tabla de números que solo entiende quien la hizo."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Jn2DxAkZ8Lof"
      },
      "source": [
        "## A.1 Generar el esqueleto\n",
        "\n",
        "Esta celda recorre cada columna y arma una fila con lo que la máquina puede averiguar sola."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "id": "3Bn6kmsU8Lof",
        "outputId": "e808fccf-c8d9-4714-82d8-5e446880b862"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Esqueleto generado: 25 variables\n",
            "\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "                 variable tipo_detectado  faltantes  pct_faltantes  \\\n",
              "0           cod_localidad         object          0            0.0   \n",
              "1            id_provincia         object          0            0.0   \n",
              "2         id_departamento         object          0            0.0   \n",
              "3             observacion         object       1902          100.0   \n",
              "4               categoria         object          0            0.0   \n",
              "5            subcategoria         object       1902          100.0   \n",
              "6               provincia         object          0            0.0   \n",
              "7            departamento         object          1            0.1   \n",
              "8               localidad         object          1            0.1   \n",
              "9                  nombre         object          0            0.0   \n",
              "10              domicilio         object          0            0.0   \n",
              "11                   piso         object       1902          100.0   \n",
              "12                     cp         object          0            0.0   \n",
              "13                cod_tel         object        165            8.7   \n",
              "14               telefono         object        165            8.7   \n",
              "15                   mail         object        880           46.3   \n",
              "16                    web         object       1902          100.0   \n",
              "17  informacion_adicional         object       1902          100.0   \n",
              "18                latitud         object          0            0.0   \n",
              "19               longitud         object          0            0.0   \n",
              "20  tipo_latitud_longitud         object          0            0.0   \n",
              "21                 fuente         object          0            0.0   \n",
              "22        fecha_fundacion         object         40            2.1   \n",
              "23            nro_conabip         object          0            0.0   \n",
              "24     anio_actualizacion         object          0            0.0   \n",
              "\n",
              "    valores_distintos                                           ejemplos  \\\n",
              "0                1053                       06854100, 06588100, 06007010   \n",
              "1                  24                                         06, 10, 22   \n",
              "2                 437                                06854, 06588, 06007   \n",
              "3                   0                                                      \n",
              "4                   1                                 Biblioteca Popular   \n",
              "5                   0                                                      \n",
              "6                  24                     Buenos Aires, Catamarca, Chaco   \n",
              "7                 366              25 De Mayo, 9 De Julio, Adolfo Alsina   \n",
              "8                1162                     25 de Mayo, 9 de Julio, Carhue   \n",
              "9                1460  Comité Cultural y Biblioteca Juan Francisco Ib...   \n",
              "10               1855                 9 y 27 801, Mitre 342, Mendoza 991   \n",
              "11                  0                                                      \n",
              "12               1177                               6660, 6500, B6430CSL   \n",
              "13                326                                   2345, 2317, 2936   \n",
              "14               1670                             462234, 426779, 430724   \n",
              "15               1021  ccibiblio@hotmail.com, bipobrchaves@yahoo.com....   \n",
              "16                  0                                                      \n",
              "17                  0                                                      \n",
              "18               1880              -35.4329170, -35.4333330, -35.4459570   \n",
              "19               1876              -60.1714170, -60.8666670, -60.8833770   \n",
              "20                  1                                             Exacta   \n",
              "21                  1                                            CONABIP   \n",
              "22               1332                 1922-10-02, 1980-01-01, 1933-10-12   \n",
              "23               1902                                     938, 200, 1850   \n",
              "24                  1                                               2023   \n",
              "\n",
              "   descripcion valores_posibles unidad_o_formato observaciones  \n",
              "0                                                               \n",
              "1                                                               \n",
              "2                                                               \n",
              "3                                                               \n",
              "4                                                               \n",
              "5                                                               \n",
              "6                                                               \n",
              "7                                                               \n",
              "8                                                               \n",
              "9                                                               \n",
              "10                                                              \n",
              "11                                                              \n",
              "12                                                              \n",
              "13                                                              \n",
              "14                                                              \n",
              "15                                                              \n",
              "16                                                              \n",
              "17                                                              \n",
              "18                                                              \n",
              "19                                                              \n",
              "20                                                              \n",
              "21                                                              \n",
              "22                                                              \n",
              "23                                                              \n",
              "24                                                              "
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-8c60bd86-9f92-42b9-8a05-1429791bef21\" class=\"colab-df-container\">\n",
              "    <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>variable</th>\n",
              "      <th>tipo_detectado</th>\n",
              "      <th>faltantes</th>\n",
              "      <th>pct_faltantes</th>\n",
              "      <th>valores_distintos</th>\n",
              "      <th>ejemplos</th>\n",
              "      <th>descripcion</th>\n",
              "      <th>valores_posibles</th>\n",
              "      <th>unidad_o_formato</th>\n",
              "      <th>observaciones</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>cod_localidad</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1053</td>\n",
              "      <td>06854100, 06588100, 06007010</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>id_provincia</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>24</td>\n",
              "      <td>06, 10, 22</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>id_departamento</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>437</td>\n",
              "      <td>06854, 06588, 06007</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>observacion</td>\n",
              "      <td>object</td>\n",
              "      <td>1902</td>\n",
              "      <td>100.0</td>\n",
              "      <td>0</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>categoria</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1</td>\n",
              "      <td>Biblioteca Popular</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>subcategoria</td>\n",
              "      <td>object</td>\n",
              "      <td>1902</td>\n",
              "      <td>100.0</td>\n",
              "      <td>0</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>6</th>\n",
              "      <td>provincia</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>24</td>\n",
              "      <td>Buenos Aires, Catamarca, Chaco</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>7</th>\n",
              "      <td>departamento</td>\n",
              "      <td>object</td>\n",
              "      <td>1</td>\n",
              "      <td>0.1</td>\n",
              "      <td>366</td>\n",
              "      <td>25 De Mayo, 9 De Julio, Adolfo Alsina</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>8</th>\n",
              "      <td>localidad</td>\n",
              "      <td>object</td>\n",
              "      <td>1</td>\n",
              "      <td>0.1</td>\n",
              "      <td>1162</td>\n",
              "      <td>25 de Mayo, 9 de Julio, Carhue</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9</th>\n",
              "      <td>nombre</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1460</td>\n",
              "      <td>Comité Cultural y Biblioteca Juan Francisco Ib...</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>10</th>\n",
              "      <td>domicilio</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1855</td>\n",
              "      <td>9 y 27 801, Mitre 342, Mendoza 991</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>11</th>\n",
              "      <td>piso</td>\n",
              "      <td>object</td>\n",
              "      <td>1902</td>\n",
              "      <td>100.0</td>\n",
              "      <td>0</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>12</th>\n",
              "      <td>cp</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1177</td>\n",
              "      <td>6660, 6500, B6430CSL</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>13</th>\n",
              "      <td>cod_tel</td>\n",
              "      <td>object</td>\n",
              "      <td>165</td>\n",
              "      <td>8.7</td>\n",
              "      <td>326</td>\n",
              "      <td>2345, 2317, 2936</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>14</th>\n",
              "      <td>telefono</td>\n",
              "      <td>object</td>\n",
              "      <td>165</td>\n",
              "      <td>8.7</td>\n",
              "      <td>1670</td>\n",
              "      <td>462234, 426779, 430724</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>15</th>\n",
              "      <td>mail</td>\n",
              "      <td>object</td>\n",
              "      <td>880</td>\n",
              "      <td>46.3</td>\n",
              "      <td>1021</td>\n",
              "      <td>ccibiblio@hotmail.com, bipobrchaves@yahoo.com....</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>16</th>\n",
              "      <td>web</td>\n",
              "      <td>object</td>\n",
              "      <td>1902</td>\n",
              "      <td>100.0</td>\n",
              "      <td>0</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>17</th>\n",
              "      <td>informacion_adicional</td>\n",
              "      <td>object</td>\n",
              "      <td>1902</td>\n",
              "      <td>100.0</td>\n",
              "      <td>0</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>18</th>\n",
              "      <td>latitud</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1880</td>\n",
              "      <td>-35.4329170, -35.4333330, -35.4459570</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>19</th>\n",
              "      <td>longitud</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1876</td>\n",
              "      <td>-60.1714170, -60.8666670, -60.8833770</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>20</th>\n",
              "      <td>tipo_latitud_longitud</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1</td>\n",
              "      <td>Exacta</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>21</th>\n",
              "      <td>fuente</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1</td>\n",
              "      <td>CONABIP</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>22</th>\n",
              "      <td>fecha_fundacion</td>\n",
              "      <td>object</td>\n",
              "      <td>40</td>\n",
              "      <td>2.1</td>\n",
              "      <td>1332</td>\n",
              "      <td>1922-10-02, 1980-01-01, 1933-10-12</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>23</th>\n",
              "      <td>nro_conabip</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1902</td>\n",
              "      <td>938, 200, 1850</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>24</th>\n",
              "      <td>anio_actualizacion</td>\n",
              "      <td>object</td>\n",
              "      <td>0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1</td>\n",
              "      <td>2023</td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "      <td></td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "    <div class=\"colab-df-buttons\">\n",
              "\n",
              "  <div class=\"colab-df-container\">\n",
              "    <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-8c60bd86-9f92-42b9-8a05-1429791bef21')\"\n",
              "            title=\"Convert this dataframe to an interactive table.\"\n",
              "            style=\"display:none;\">\n",
              "\n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
              "    <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
              "  </svg>\n",
              "    </button>\n",
              "\n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    .colab-df-buttons div {\n",
              "      margin-bottom: 4px;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "    <script>\n",
              "      const buttonEl =\n",
              "        document.querySelector('#df-8c60bd86-9f92-42b9-8a05-1429791bef21 button.colab-df-convert');\n",
              "      buttonEl.style.display =\n",
              "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "      async function convertToInteractive(key) {\n",
              "        const element = document.querySelector('#df-8c60bd86-9f92-42b9-8a05-1429791bef21');\n",
              "        const dataTable =\n",
              "          await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                    [key], {});\n",
              "        if (!dataTable) return;\n",
              "\n",
              "        const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "          '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "          + ' to learn more about interactive tables.';\n",
              "        element.innerHTML = '';\n",
              "        dataTable['output_type'] = 'display_data';\n",
              "        await google.colab.output.renderOutput(dataTable, element);\n",
              "        const docLink = document.createElement('div');\n",
              "        docLink.innerHTML = docLinkHtml;\n",
              "        element.appendChild(docLink);\n",
              "      }\n",
              "    </script>\n",
              "  </div>\n",
              "\n",
              "\n",
              "  <div id=\"id_d3ff4da4-0914-4e3a-8e22-ce017a295233\">\n",
              "    <style>\n",
              "      .colab-df-generate {\n",
              "        background-color: #E8F0FE;\n",
              "        border: none;\n",
              "        border-radius: 50%;\n",
              "        cursor: pointer;\n",
              "        display: none;\n",
              "        fill: #1967D2;\n",
              "        height: 32px;\n",
              "        padding: 0 0 0 0;\n",
              "        width: 32px;\n",
              "      }\n",
              "\n",
              "      .colab-df-generate:hover {\n",
              "        background-color: #E2EBFA;\n",
              "        box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "        fill: #174EA6;\n",
              "      }\n",
              "\n",
              "      [theme=dark] .colab-df-generate {\n",
              "        background-color: #3B4455;\n",
              "        fill: #D2E3FC;\n",
              "      }\n",
              "\n",
              "      [theme=dark] .colab-df-generate:hover {\n",
              "        background-color: #434B5C;\n",
              "        box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "        filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "        fill: #FFFFFF;\n",
              "      }\n",
              "    </style>\n",
              "    <button class=\"colab-df-generate\" onclick=\"generateWithVariable('codebook')\"\n",
              "            title=\"Generate code using this dataframe.\"\n",
              "            style=\"display:none;\">\n",
              "\n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M7,19H8.4L18.45,9,17,7.55,7,17.6ZM5,21V16.75L18.45,3.32a2,2,0,0,1,2.83,0l1.4,1.43a1.91,1.91,0,0,1,.58,1.4,1.91,1.91,0,0,1-.58,1.4L9.25,21ZM18.45,9,17,7.55Zm-12,3A5.31,5.31,0,0,0,4.9,8.1,5.31,5.31,0,0,0,1,6.5,5.31,5.31,0,0,0,4.9,4.9,5.31,5.31,0,0,0,6.5,1,5.31,5.31,0,0,0,8.1,4.9,5.31,5.31,0,0,0,12,6.5,5.46,5.46,0,0,0,6.5,12Z\"/>\n",
              "  </svg>\n",
              "    </button>\n",
              "    <script>\n",
              "      (() => {\n",
              "      const buttonEl =\n",
              "        document.querySelector('#id_d3ff4da4-0914-4e3a-8e22-ce017a295233 button.colab-df-generate');\n",
              "      buttonEl.style.display =\n",
              "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "      buttonEl.onclick = () => {\n",
              "        google.colab.notebook.generateWithVariable('codebook');\n",
              "      }\n",
              "      })();\n",
              "    </script>\n",
              "  </div>\n",
              "\n",
              "    </div>\n",
              "  </div>\n"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "dataframe",
              "variable_name": "codebook",
              "summary": "{\n  \"name\": \"codebook\",\n  \"rows\": 25,\n  \"fields\": [\n    {\n      \"column\": \"variable\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 25,\n        \"samples\": [\n          \"localidad\",\n          \"web\",\n          \"cod_localidad\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"tipo_detectado\",\n      \"properties\": {\n        \"dtype\": \"category\",\n        \"num_unique_values\": 1,\n        \"samples\": [\n          \"object\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"faltantes\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 771,\n        \"min\": 0,\n        \"max\": 1902,\n        \"num_unique_values\": 6,\n        \"samples\": [\n          0\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"pct_faltantes\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 40.561301343357655,\n        \"min\": 0.0,\n        \"max\": 100.0,\n        \"num_unique_values\": 6,\n        \"samples\": [\n          0.0\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"valores_distintos\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 757,\n        \"min\": 0,\n        \"max\": 1902,\n        \"num_unique_values\": 17,\n        \"samples\": [\n          1053\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"ejemplos\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 21,\n        \"samples\": [\n          \"06854100, 06588100, 06007010\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"descripcion\",\n      \"properties\": {\n        \"dtype\": \"object\",\n        \"num_unique_values\": 1,\n        \"samples\": [\n          \"\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"valores_posibles\",\n      \"properties\": {\n        \"dtype\": \"object\",\n        \"num_unique_values\": 1,\n        \"samples\": [\n          \"\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"unidad_o_formato\",\n      \"properties\": {\n        \"dtype\": \"object\",\n        \"num_unique_values\": 1,\n        \"samples\": [\n          \"\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"observaciones\",\n      \"properties\": {\n        \"dtype\": \"object\",\n        \"num_unique_values\": 1,\n        \"samples\": [\n          \"\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    }\n  ]\n}"
            }
          },
          "metadata": {},
          "execution_count": 9
        }
      ],
      "source": [
        "filas = []\n",
        "\n",
        "for col in df_limpio.columns:\n",
        "    s = df_limpio[col]\n",
        "    no_vacios = s[s.astype(str).str.strip() != '']\n",
        "    vacias = len(s) - len(no_vacios)\n",
        "    ejemplos = ', '.join(map(str, no_vacios.unique()[:3]))[:60]\n",
        "\n",
        "    filas.append({\n",
        "        'variable': col,\n",
        "        'tipo_detectado': str(s.dtype),\n",
        "        'faltantes': vacias,\n",
        "        'pct_faltantes': round(vacias / len(df_limpio) * 100, 1),\n",
        "        'valores_distintos': no_vacios.nunique(),\n",
        "        'ejemplos': ejemplos,\n",
        "        'descripcion': '',          # <-- lo completan ustedes\n",
        "        'valores_posibles': '',     # <-- lo completan ustedes\n",
        "        'unidad_o_formato': '',     # <-- lo completan ustedes\n",
        "        'observaciones': ''         # <-- lo completan ustedes\n",
        "    })\n",
        "\n",
        "codebook = pd.DataFrame(filas)\n",
        "codebook.to_csv('codebook_esqueleto.csv', index=False, encoding='utf-8')\n",
        "\n",
        "print(f\"Esqueleto generado: {len(codebook)} variables\\n\")\n",
        "codebook"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3XTp3Els8Lof"
      },
      "source": [
        "### Qué hace, línea por línea\n",
        "\n",
        "- `for col in df_limpio.columns:` — el mismo bucle que usaron para buscar problemas de encoding, aplicado a otro fin.\n",
        "- `s.astype(str).str.strip() == ''` — cuenta celdas vacías, incluidas las que solo tienen espacios.\n",
        "- `s.nunique()` — cuántos valores distintos hay.\n",
        "- `[x for x in s.unique() if ...][:3]` — toma tres ejemplos reales, salteando los vacíos.\n",
        "- Las **cuatro últimas columnas van vacías a propósito**. Ninguna computadora puede saber qué *significa* una variable.\n",
        "\n",
        "### Miren la fila de `id_departamento` y la de `departamento`\n",
        "\n",
        "Una tiene **437** valores distintos y la otra **366**. Hay más códigos que nombres. Es el hallazgo de la clase pasada, ahora visible de un vistazo."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4-CkVUiO8Log"
      },
      "source": [
        "## A.2 Descargar el esqueleto para completarlo"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 17
        },
        "id": "G2QApoqy8Log",
        "outputId": "49527ab0-a092-4fa6-b902-f5ae656303bc"
      },
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<IPython.core.display.Javascript object>"
            ],
            "application/javascript": [
              "\n",
              "    async function download(id, filename, size) {\n",
              "      if (!google.colab.kernel.accessAllowed) {\n",
              "        return;\n",
              "      }\n",
              "      const div = document.createElement('div');\n",
              "      const label = document.createElement('label');\n",
              "      label.textContent = `Downloading \"${filename}\": `;\n",
              "      div.appendChild(label);\n",
              "      const progress = document.createElement('progress');\n",
              "      progress.max = size;\n",
              "      div.appendChild(progress);\n",
              "      document.body.appendChild(div);\n",
              "\n",
              "      const buffers = [];\n",
              "      let downloaded = 0;\n",
              "\n",
              "      const channel = await google.colab.kernel.comms.open(id);\n",
              "      // Send a message to notify the kernel that we're ready.\n",
              "      channel.send({})\n",
              "\n",
              "      for await (const message of channel.messages) {\n",
              "        // Send a message to notify the kernel that we're ready.\n",
              "        channel.send({})\n",
              "        if (message.buffers) {\n",
              "          for (const buffer of message.buffers) {\n",
              "            buffers.push(buffer);\n",
              "            downloaded += buffer.byteLength;\n",
              "            progress.value = downloaded;\n",
              "          }\n",
              "        }\n",
              "      }\n",
              "      const blob = new Blob(buffers, {type: 'application/binary'});\n",
              "      const a = document.createElement('a');\n",
              "      a.href = window.URL.createObjectURL(blob);\n",
              "      a.download = filename;\n",
              "      div.appendChild(a);\n",
              "      a.click();\n",
              "      div.remove();\n",
              "    }\n",
              "  "
            ]
          },
          "metadata": {}
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<IPython.core.display.Javascript object>"
            ],
            "application/javascript": [
              "download(\"download_b9a66bef-4f81-4514-891d-06a1eb788090\", \"codebook_esqueleto.csv\", 1542)"
            ]
          },
          "metadata": {}
        }
      ],
      "source": [
        "from google.colab import files\n",
        "files.download('codebook_esqueleto.csv')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "E6ajIJFj8Log"
      },
      "source": [
        "Ábranlo en una planilla y completen las cuatro columnas en blanco.\n",
        "\n",
        "**Reparto sugerido por grupo (6 a 8 variables cada uno, no las 25):**\n",
        "- Grupo 1 → identificadores y códigos: `cod_localidad`, `id_provincia`, `id_departamento`, `nro_conabip`, `id_bp`, `categoria`, `subcategoria`\n",
        "- Grupo 2 → ubicación: `provincia`, `departamento`, `localidad`, `domicilio`, `piso`, `cp`, `latitud`, `longitud`, `tipo_latitud_longitud`\n",
        "- Grupo 3 → contacto, fechas y resto: `nombre`, `cod_tel`, `telefono`, `mail`, `web`, `fecha_fundacion`, `observacion`, `informacion_adicional`, `fuente`, `anio_actualizacion`\n",
        "\n",
        "### Cuando lleguen a las columnas vacías, van a preguntar qué escribir\n",
        "\n",
        "Esa pregunta **es** el contenido del bloque.\n",
        "\n",
        "Un codebook honesto escribe: *\"columna presente en el archivo original, sin datos en ninguna fila, causa desconocida\"*. No inventa un significado ni la borra en silencio.\n",
        "\n",
        "Y si el grupo decide eliminarla del dataset publicado, esa decisión va documentada con su justificación."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LJTrJzm-8Loh"
      },
      "source": [
        "---\n",
        "# BLOQUE B · README\n",
        "\n",
        "El codebook explica **las variables**. El README explica **el dataset**: de dónde viene, quién lo hizo, qué se le modificó y bajo qué condiciones puede usarse."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "iggOF7E18Loh"
      },
      "source": [
        "## B.1 Hechos verificables\n",
        "\n",
        "Esta celda imprime lo que se copia al README tal cual, sin discusión posible."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "DPWOGp4l8Loh",
        "outputId": "1bd5f820-ad0e-4972-bc36-8ea2d8493b14"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "===== HECHOS PARA EL README =====\n",
            "Filas: 1902\n",
            "Columnas: 25\n",
            "Columnas 100% vacías (5): ['observacion', 'subcategoria', 'piso', 'web', 'informacion_adicional']\n",
            "Columnas de valor constante (4): ['categoria', 'tipo_latitud_longitud', 'fuente', 'anio_actualizacion']\n",
            "Variables con algún faltante: 11 de 25\n",
            "Fecha de generación: 2026-07-31\n"
          ]
        }
      ],
      "source": [
        "vacias_100 = [c for c in df_limpio.columns\n",
        "              if (df_limpio[c].astype(str).str.strip() == '').all()]\n",
        "constantes = [c for c in df_limpio.columns\n",
        "              if c not in vacias_100 and df_limpio[c].nunique() == 1]\n",
        "con_faltantes = sum(1 for c in df_limpio.columns\n",
        "                    if (df_limpio[c].astype(str).str.strip() == '').any())\n",
        "\n",
        "print(\"===== HECHOS PARA EL README =====\")\n",
        "print(f\"Filas: {len(df_limpio)}\")\n",
        "print(f\"Columnas: {df_limpio.shape[1]}\")\n",
        "print(f\"Columnas 100% vacías ({len(vacias_100)}): {vacias_100}\")\n",
        "print(f\"Columnas de valor constante ({len(constantes)}): {constantes}\")\n",
        "print(f\"Variables con algún faltante: {con_faltantes} de {df_limpio.shape[1]}\")\n",
        "print(f\"Fecha de generación: {datetime.date.today().isoformat()}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "L6NEVy1B8Loi"
      },
      "source": [
        "## B.2 Lo que ninguna celda puede imprimir\n",
        "\n",
        "Y que es la parte importante del README:\n",
        "\n",
        "- Quién produjo el dato y con qué mandato\n",
        "- Cuándo se descargó el original (¡anótenlo!)\n",
        "- **Qué transformaciones se aplicaron y por qué**\n",
        "- Qué licencia tiene y a quién se atribuye\n",
        "- Qué quedó sin resolver\n",
        "\n",
        "### La sección más importante: \"Transformaciones aplicadas\"\n",
        "\n",
        "Toda reparación es una **afirmación nueva**.\n",
        "\n",
        "Cuando reemplazaron «Almte Brown» por «Almirante Brown», afirmaron algo que el organismo nunca afirmó. Puede estar muy bien hecho — pero es una afirmación de ustedes, no del productor.\n",
        "\n",
        "Enumerar esas afirmaciones es la diferencia entre **curar** y **editar**.\n",
        "\n",
        "> Si usaron el archivo de referencia, la lista de transformaciones ya está escrita en `CAMBIOS_APLICADOS.md`. Cópienla y agreguen las suyas."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Wqud74qh8Loi"
      },
      "source": [
        "## B.3 La prueba del tercero\n",
        "\n",
        "Intercambien READMEs entre grupos. Tres minutos de lectura y **una sola pregunta**:\n",
        "\n",
        "> *¿Podrías usar este dataset con lo que dice acá?*\n",
        "\n",
        "Eso es la verificación del criterio 12 del marco, y no cuesta nada."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3EKIeb6B8Loj"
      },
      "source": [
        "---\n",
        "# BLOQUE C · Verificar el propio trabajo\n",
        "\n",
        "Hasta ahora auditamos el trabajo de otro. Ahora nos auditamos a nosotros."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "TcWyc2Ie8Loj",
        "outputId": "6a5ce00a-5c73-45a3-f592-a7f39867b4a0"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "No encontre el archivo. Subilo al panel de carpeta (izquierda).\n",
            "CSV que hay en /content: ['codebook_esqueleto.csv']\n"
          ]
        }
      ],
      "source": [
        "import glob\n",
        "\n",
        "archivos = glob.glob('/content/codebook_completado*.csv')\n",
        "\n",
        "if not archivos:\n",
        "    import os\n",
        "    print(\"No encontre el archivo. Subilo al panel de carpeta (izquierda).\")\n",
        "    print(\"CSV que hay en /content:\", [f for f in os.listdir('/content') if f.endswith('.csv')])\n",
        "else:\n",
        "    cb = pd.read_csv(archivos[0], skiprows=4, sep=None, engine='python',\n",
        "                     encoding='utf-8-sig', keep_default_na=False)\n",
        "\n",
        "    # Descartamos filas que no son variables: vacias, notas al pie, totales\n",
        "    cb = cb[cb['tipo_detectado'].astype(str).str.strip() != '']\n",
        "\n",
        "    print(f\"Leyendo: {archivos[0]}\")\n",
        "    print(f\"Variables documentadas: {len(cb)}\\n\")\n",
        "\n",
        "    vacio = cb['descripcion'].astype(str).str.strip().isin(['', '0', 'nan'])\n",
        "    sin_desc = cb[vacio]\n",
        "\n",
        "    print(f\"Variables SIN descripcion: {len(sin_desc)} de {len(cb)}\")\n",
        "    if len(sin_desc):\n",
        "        print(list(sin_desc['variable']))\n",
        "    else:\n",
        "        print(\"Todas las variables estan descriptas \\u2714\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3stWPhrl8Lok"
      },
      "source": [
        "### Un detalle que vale la pena mirar\n",
        "\n",
        "Fíjense en `skiprows=4`.\n",
        "\n",
        "Cuando descargamos la planilla como CSV, el archivo no trajo solo la tabla: trajo **todo lo que había en la hoja**, incluidas las tres líneas de título y la fila en blanco. Un CSV no distingue entre \"título\" y \"encabezado de tabla\" — para él es todo texto en filas.\n",
        "\n",
        "Sin ese `skiprows=4`, pandas habría tomado el título como si fuera el nombre de las columnas, y la celda hubiera fallado buscando una columna llamada `descripcion` que no existiría.\n",
        "\n",
        "Es la misma familia de problema que los ceros iniciales y el encoding: **la falla no está en el dato, está en cómo lo leemos.** Tercera vez que aparece hoy."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GpxCFAti8Lok"
      },
      "source": [
        "### Por qué esta celda importa\n",
        "\n",
        "En la Clase 1, uno de los hallazgos fue que la ficha del portal **describía algunos campos y dejaba otros sin descripción**.\n",
        "\n",
        "Esta celda les hace exactamente la misma pregunta sobre lo que acaban de producir.\n",
        "\n",
        "Si les devuelve seis variables en blanco, acaban de encontrarse el mismo problema que criticaron. No hace falta agregar nada más."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bp1yq6vL8Lok"
      },
      "source": [
        "---\n",
        "# BLOQUE D · Armar el paquete para Zenodo\n",
        "\n",
        "Cuatro archivos. Ni uno menos."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        },
        "id": "DBF7xm_y8Lol",
        "outputId": "994c6e76-cc46-4445-c837-c71050c7b2d8"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "CSV exportado ✔\n"
          ]
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<IPython.core.display.Javascript object>"
            ],
            "application/javascript": [
              "\n",
              "    async function download(id, filename, size) {\n",
              "      if (!google.colab.kernel.accessAllowed) {\n",
              "        return;\n",
              "      }\n",
              "      const div = document.createElement('div');\n",
              "      const label = document.createElement('label');\n",
              "      label.textContent = `Downloading \"${filename}\": `;\n",
              "      div.appendChild(label);\n",
              "      const progress = document.createElement('progress');\n",
              "      progress.max = size;\n",
              "      div.appendChild(progress);\n",
              "      document.body.appendChild(div);\n",
              "\n",
              "      const buffers = [];\n",
              "      let downloaded = 0;\n",
              "\n",
              "      const channel = await google.colab.kernel.comms.open(id);\n",
              "      // Send a message to notify the kernel that we're ready.\n",
              "      channel.send({})\n",
              "\n",
              "      for await (const message of channel.messages) {\n",
              "        // Send a message to notify the kernel that we're ready.\n",
              "        channel.send({})\n",
              "        if (message.buffers) {\n",
              "          for (const buffer of message.buffers) {\n",
              "            buffers.push(buffer);\n",
              "            downloaded += buffer.byteLength;\n",
              "            progress.value = downloaded;\n",
              "          }\n",
              "        }\n",
              "      }\n",
              "      const blob = new Blob(buffers, {type: 'application/binary'});\n",
              "      const a = document.createElement('a');\n",
              "      a.href = window.URL.createObjectURL(blob);\n",
              "      a.download = filename;\n",
              "      div.appendChild(a);\n",
              "      a.click();\n",
              "      div.remove();\n",
              "    }\n",
              "  "
            ]
          },
          "metadata": {}
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<IPython.core.display.Javascript object>"
            ],
            "application/javascript": [
              "download(\"download_f6c3e642-a179-4e32-aad3-9a4e2911f1ac\", \"bibliotecas_populares_limpio.csv\", 410823)"
            ]
          },
          "metadata": {}
        }
      ],
      "source": [
        "from google.colab import files\n",
        "\n",
        "df_limpio.to_csv('bibliotecas_populares_limpio.csv', index=False, encoding='utf-8')\n",
        "print(\"CSV exportado \\u2714\")\n",
        "\n",
        "# Si la descarga no arranca, el archivo esta en el panel de carpeta:\n",
        "# clic derecho sobre el archivo -> Descargar\n",
        "files.download('bibliotecas_populares_limpio.csv')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WoKBLlF68Lol"
      },
      "source": [
        "## Checklist antes de publicar\n",
        "\n",
        "| Archivo | Qué es | ¿Listo? |\n",
        "|---|---|---|\n",
        "| `bibliotecas_populares_limpio.csv` | El dato curado | ☐ |\n",
        "| `codebook_completado.csv` | Una entrada por variable | ☐ |\n",
        "| `README.md` | Origen, transformaciones, licencia, atribución | ☐ |\n",
        "| `notebook_clase3.ipynb` | `Archivo → Descargar → .ipynb` | ☐ |\n",
        "\n",
        "**Advertencia:** en Zenodo, una vez publicado **no se pueden agregar archivos**. Verifiquen los cuatro antes de apretar Publish.\n",
        "\n",
        "---\n",
        "\n",
        "## Y una última cosa sobre el DOI que van a recibir\n",
        "\n",
        "El identificador que devuelve el sandbox empieza con `10.5072`. El de Zenodo real empieza con `10.5281`.\n",
        "\n",
        "El de ustedes **no resuelve, no persiste y no vale nada**.\n",
        "\n",
        "Un identificador persistente vale exactamente lo que vale la institución que se compromete a sostenerlo. Eso no es un detalle técnico: es la dimensión E del marco de criterios, ocurriendo en pantalla."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}