{ "cells": [ { "cell_type": "markdown", "id": "fd6678bd", "metadata": {}, "source": [ "# Lectura y exploración de microdatos Parquet con diseño de registro embebido\n", "\n", "Este notebook muestra cómo trabajar en Python con los ficheros `.parquet` de microdatos\n", "publicados por el INE, que incluyen:\n", "\n", "1. Una tabla de microdatos columnar (formato Apache Parquet).\n", "2. Un **diseño de registro** en formato JSON embebido en los metadatos del esquema\n", " Parquet, bajo la clave `record_layout`.\n" ] }, { "cell_type": "markdown", "id": "1dc14a56", "metadata": {}, "source": [ "## 1. Instalación de dependencias\n", "\n", "Ejecutar solo si no están ya instaladas." ] }, { "cell_type": "code", "execution_count": null, "id": "43817fe3", "metadata": {}, "outputs": [], "source": [ "# !pip install pyarrow pandas\n" ] }, { "cell_type": "markdown", "id": "bfecd4d1", "metadata": {}, "source": [ "## 2. Imports y configuración" ] }, { "cell_type": "code", "execution_count": null, "id": "ab153e5b", "metadata": {}, "outputs": [], "source": [ "import json\n", "from pathlib import Path\n", "\n", "import pandas as pd\n", "import pyarrow.parquet as pq\n", "\n", "pd.set_option(\"display.max_columns\", 100)\n", "pd.set_option(\"display.width\", 140)\n" ] }, { "cell_type": "markdown", "id": "642a5024", "metadata": {}, "source": [ "## 3. Descarga del ZIP del INE y localización del Parquet\n", "\n", "Se descarga el ZIP de microdatos directamente desde la web del INE y se extrae\n", "el fichero `.parquet` que contiene, sin necesidad de guardarlo manualmente en local.\n", "Ajustar `url_zip` si se quiere apuntar a otra operación o año." ] }, { "cell_type": "code", "execution_count": null, "id": "afacce55", "metadata": {}, "outputs": [], "source": [ "import io\n", "import urllib.request\n", "import zipfile\n", "\n", "url_zip = \"https://www.ine.es/ftp/microdatos/eaner/datos_2025.zip\"\n", "directorio_descarga = Path(\"microdatos_descargados\")\n", "directorio_descarga.mkdir(exist_ok=True)\n", "\n", "# Descarga del ZIP\n", "print(f\"Descargando {url_zip} ...\")\n", "with urllib.request.urlopen(url_zip) as respuesta:\n", " contenido_zip = respuesta.read()\n", "print(f\"Descarga completada ({len(contenido_zip) / 1_048_576:.1f} MB)\")\n", "\n", "# Extracción del ZIP (en memoria, sin guardar el .zip en disco)\n", "with zipfile.ZipFile(io.BytesIO(contenido_zip)) as zf:\n", " nombres_parquet = [n for n in zf.namelist() if n.lower().endswith(\".parquet\")]\n", "\n", " if not nombres_parquet:\n", " raise FileNotFoundError(\"No se ha encontrado ningún fichero .parquet dentro del ZIP.\")\n", " if len(nombres_parquet) > 1:\n", " print(\"Aviso: hay varios ficheros .parquet en el ZIP, se usará el primero:\")\n", " print(nombres_parquet)\n", "\n", " nombre_parquet = nombres_parquet[0]\n", " zf.extract(nombre_parquet, path=directorio_descarga)\n", "\n", "ruta_parquet = directorio_descarga / nombre_parquet\n", "\n", "assert ruta_parquet.exists(), f\"No se encuentra el fichero: {ruta_parquet}\"\n", "ruta_parquet\n", "\n" ] }, { "cell_type": "markdown", "id": "3904b24d", "metadata": {}, "source": [ "## 4. Lectura de la tabla Parquet\n", "\n", "Se usa `pyarrow.parquet` directamente (en lugar de `pandas.read_parquet`) porque\n", "así se conserva el acceso al `schema.metadata`, donde va embebido el diseño de\n", "registro. Si se carga solo con pandas, es fácil perder esos metadatos." ] }, { "cell_type": "code", "execution_count": null, "id": "f18ad36e", "metadata": {}, "outputs": [], "source": [ "tabla = pq.read_table(ruta_parquet)\n", "\n", "print(f\"Filas: {tabla.num_rows:,}\")\n", "print(f\"Columnas: {tabla.num_columns}\")\n", "print()\n", "print(\"Nombres de columnas:\")\n", "print(tabla.column_names)\n" ] }, { "cell_type": "markdown", "id": "805f55e6", "metadata": {}, "source": [ "## 5. Datos: vista previa como DataFrame de pandas" ] }, { "cell_type": "code", "execution_count": null, "id": "8edc4c01", "metadata": {}, "outputs": [], "source": [ "df = tabla.to_pandas()\n", "df.head()\n" ] }, { "cell_type": "code", "execution_count": null, "id": "337663f9", "metadata": {}, "outputs": [], "source": [ "df.dtypes\n" ] }, { "cell_type": "markdown", "id": "326c748d", "metadata": {}, "source": [ "## 6. Metadatos: extracción del `record_layout`\n", "\n", "El diseño de registro está guardado como texto JSON (UTF-8) en la clave\n", "`record_layout` de los metadatos del esquema." ] }, { "cell_type": "code", "execution_count": null, "id": "8eceeaaf", "metadata": {}, "outputs": [], "source": [ "metadata = tabla.schema.metadata\n", "\n", "if metadata and b\"record_layout\" in metadata:\n", " json_bytes = metadata[b\"record_layout\"]\n", " json_texto = json_bytes.decode(\"utf-8\")\n", " record_layout = json.loads(json_texto)\n", " print(\"record_layout encontrado correctamente.\")\n", "else:\n", " record_layout = None\n", " print(\"No se encontró 'record_layout' en los metadatos del fichero.\")\n" ] }, { "cell_type": "code", "execution_count": null, "id": "423f6ea4", "metadata": {}, "outputs": [], "source": [ "# Vista previa \"cruda\" del JSON (primeros 1000 caracteres)\n", "if record_layout is not None:\n", " print(json.dumps(record_layout, indent=2, ensure_ascii=False)[:1000])\n" ] }, { "cell_type": "markdown", "id": "da9981ce", "metadata": {}, "source": [ "### 6.1 Inspección interactiva (opcional)\n", "\n", "Si se trabaja en Jupyter clásico (no todos los entornos soportan `IPython.display.JSON`\n", "o widgets), esta celda ofrece una vista interactiva y colapsable del JSON." ] }, { "cell_type": "code", "execution_count": null, "id": "4afec12a", "metadata": {}, "outputs": [], "source": [ "try:\n", " from IPython.display import JSON, display\n", " display(JSON(record_layout))\n", "except Exception as e:\n", " print(\"Vista interactiva no disponible en este entorno:\", e)\n" ] }, { "cell_type": "code", "execution_count": null, "id": "0524ee64", "metadata": {}, "outputs": [], "source": [] } ], "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.13.7" } }, "nbformat": 4, "nbformat_minor": 5 }