Skip to main content

Libreria Python para analisis de microdatos ENAHO del INEI Peru

Project description

ENAHOPY 🇵🇪

Python 3.8+ License: MIT CI Pipeline codecov Code style: black

Librería Python para análisis de microdatos ENAHO del INEI (Perú)

Herramienta completa y robusta para descargar, procesar, fusionar y analizar microdatos de la Encuesta Nacional de Hogares (ENAHO). Diseñada específicamente para investigadores, analistas y profesionales que trabajan con datos sociales y económicos del Perú.

✨ Características Principales

  • 📥 Descarga Automática: Descarga directa desde servidores oficiales del INEI
  • 📊 Multi-formato: Compatible con DTA (Stata), SAV (SPSS), CSV, Parquet
  • ✅ Validación Inteligente: Validación automática de columnas y mapeo de variables
  • 🔗 Fusión de Módulos: Sistema avanzado para combinar módulos ENAHO (hogar, personas, ingresos)
  • 🗺️ Análisis Geográfico: Integración con datos UBIGEO (departamento/provincia/distrito)
  • 🕳️ Análisis de Valores Nulos: Detección de patrones missing y estrategias de imputación
  • ⚡ Sistema de Cache: Optimización automática de descargas repetidas
  • 🚀 Alto Rendimiento: Procesamiento eficiente con bajo uso de memoria
  • 📈 Visualizaciones: Gráficos especializados para datos de encuestas sociales

📦 Instalación

Instalación básica

pip install enahopy

Instalación con todas las características

pip install enahopy[all]

🚀 Inicio Rápido

1. Descargar datos ENAHO

from enahopy.loader import ENAHODataDownloader

# Inicializar downloader
downloader = ENAHODataDownloader(verbose=True)

# Descargar múltiples módulos en paralelo
data_multi = downloader.download(
    modules=['01', '02', '05', '34'],  # Hogar, Persona, Empleo, Sumaria
    years=['2024'],
    output_dir='./data',
    decompress=True,
    load_dta=True,
    parallel=True,
    max_workers=3
)

# Extraer datasets
df_hogar = data_multi[('2024', '01')]['enaho01-2024-100']
df_persona = data_multi[('2024', '02')]['enaho01-2024-200']
df_empleo = data_multi[('2024', '05')]['enaho01a-2024-500']
df_sumaria = data_multi[('2024', '34')]['sumaria-2024']

print(f"✓ Hogares: {len(df_hogar):,} registros")
print(f"✓ Personas: {len(df_persona):,} registros")

2. Fusionar módulos

from enahopy.merger import ENAHOModuleMerger
from enahopy.merger.config import ModuleMergeConfig, ModuleMergeLevel

# Configurar merger para nivel persona
config = ModuleMergeConfig(merge_level=ModuleMergeLevel.PERSONA)
merger = ENAHOModuleMerger(config)

# Fusionar módulos individuales
modules_dict = {
    '02': df_persona,
    '05': df_empleo
}

result = merger.merge_multiple_modules(
    modules_dict=modules_dict,
    base_module='02',
    merge_config=config
)

df_merged = result.merged_df
print(f"✓ Fusionado: {df_merged.shape}")

3. Análisis geográfico

from enahopy.merger.geographic.merger import GeographicMerger
import pandas as pd

# Cargar tabla UBIGEO
df_ubigeo = pd.read_excel('UBIGEO_2024.xlsx')
df_ubigeo = df_ubigeo[['IDDIST', 'NOMBDEP', 'NOMBPROV', 'NOMBDIST']]
df_ubigeo = df_ubigeo.rename(columns={'IDDIST': 'ubigeo'})

# Fusionar con datos geográficos
merger_geo = GeographicMerger()
df_geo, report = merger_geo.merge(df_sumaria, df_ubigeo, columna_union='ubigeo')

print(f"✓ Registros con geografía: {report['output_rows']}")

4. Análisis de valores nulos

from enahopy.null_analysis import ENAHONullAnalyzer

# Análisis completo de valores faltantes
analyzer = ENAHONullAnalyzer(complexity='advanced')
result = analyzer.analyze(df_merged)

# Generar reporte HTML
analyzer.export_report(result, 'reporte_nulos.html')

💡 Ejemplos Prácticos

🏆 Análisis Completo de Pobreza Monetaria y Laboral (Avanzado)

Este ejemplo muestra un pipeline completo de análisis fusionando 6 módulos ENAHO para estudiar la relación entre pobreza monetaria y características laborales.

Archivos del ejemplo:

📝 Nota: El módulo .py contiene toda la lógica de procesamiento, cálculo de variables derivadas, y transformaciones. El notebook lo importa para mantener el código organizado y reutilizable.

Funciones principales del módulo analisis_pob_mon_lab.py:

  • pipeline_completo(): Ejecuta todo el flujo de procesamiento end-to-end
  • crear_caracteristicas_individuales(): Calcula variables derivadas (informalidad, seguro de salud, grupos etarios, etc.)
  • extraer_jefe_hogar_completo(): Extrae características del jefe de hogar (educación, ocupación, sector económico)
  • agregar_a_nivel_hogar(): Agrega datos individuales a nivel hogar
  • calcular_variables_objetivo(): Calcula pobreza monetaria y laboral
  • analisis_descriptivo_ponderado(): Análisis con pesos muestrales (factor de expansión)
from enahopy.loader import ENAHODataDownloader
from enahopy.merger import ENAHOModuleMerger
from enahopy.merger.config import ModuleMergeConfig, ModuleMergeLevel
import pandas as pd

# Importar funciones del módulo auxiliar
from analisis_pob_mon_lab import pipeline_completo, analisis_descriptivo_ponderado

# ==================================================
# PASO 1: Descargar múltiples módulos en paralelo
# ==================================================

downloader = ENAHODataDownloader(verbose=True)

# Descargar 6 módulos simultáneamente
data_multi = downloader.download(
    modules=['01', '02', '03', '04', '05', '34'],  # Hogar, Persona, Educación, Salud, Empleo, Sumaria
    years=['2024'],
    output_dir='./data',
    parallel=True,
    max_workers=3,
    load_dta=True
)

# Extraer datasets individuales
df_hogar = data_multi[('2024', '01')]['enaho01-2024-100']
df_persona = data_multi[('2024', '02')]['enaho01-2024-200']
df_educacion = data_multi[('2024', '03')]['enaho01a-2024-300']
df_salud = data_multi[('2024', '04')]['enaho01a-2024-400']
df_empleo = data_multi[('2024', '05')]['enaho01a-2024-500']
df_sumaria = data_multi[('2024', '34')]['sumaria-2024']

print(f"✓ Datasets descargados:")
print(f"  • Hogares: {df_hogar.shape[0]:,} registros")
print(f"  • Personas: {df_persona.shape[0]:,} registros")

# ==================================================
# PASO 2: Fusionar módulos a nivel PERSONA
# ==================================================

# Configurar merger para nivel persona
config_persona = ModuleMergeConfig(merge_level=ModuleMergeLevel.PERSONA)
merger_persona = ENAHOModuleMerger(config_persona)

# Fusionar módulos individuales (persona + educación + salud + empleo)
modules_dict = {
    '02': df_persona,
    '03': df_educacion,
    '04': df_salud,
    '05': df_empleo
}

merge_result = merger_persona.merge_multiple_modules(
    modules_dict=modules_dict,
    base_module='02',
    merge_config=config_persona
)

df_individuos = merge_result.merged_df
print(f"✓ Módulos individuales fusionados: {df_individuos.shape}")

# ==================================================
# PASO 3: Fusionar módulos a nivel HOGAR
# ==================================================

config_hogar = ModuleMergeConfig(merge_level=ModuleMergeLevel.HOGAR)
merger_hogar = ENAHOModuleMerger(config_hogar)

# Fusionar sumaria + características de hogar
merge_hogar = merger_hogar.merge_modules(
    left_df=df_sumaria,
    right_df=df_hogar,
    left_module='34',
    right_module='01',
    merge_config=config_hogar
)

df_hogares = merge_hogar.merged_df
print(f"✓ Módulos de hogar fusionados: {df_hogares.shape}")

# ==================================================
# PASO 4: Análisis de pobreza monetaria y laboral
# ==================================================

# Calcular informalidad laboral (ocupados sin contrato ni beneficios)
df_individuos['es_informal'] = (
    (df_individuos['ocu500'] == 1) &  # Ocupado
    (df_individuos['p507'].isin([7, 8, 9]))  # Sin contrato
).astype(int)

# Agregar a nivel hogar
df_hogar_stats = df_individuos.groupby(['conglome', 'vivienda', 'hogar']).agg({
    'codperso': 'count',  # Personas en el hogar
    'es_informal': 'sum'  # Informales en el hogar
}).rename(columns={'codperso': 'n_personas', 'es_informal': 'n_informales'})

# Fusionar con datos de hogar
df_final = df_hogares.merge(df_hogar_stats, on=['conglome', 'vivienda', 'hogar'])

# Calcular tasa de informalidad por hogar
df_final['tasa_informalidad'] = df_final['n_informales'] / df_final['n_personas']

# Clasificar pobreza monetaria (usando línea de pobreza INEI)
df_final['es_pobre_monetario'] = (df_final['pobreza'] <= 2).astype(int)  # 1=pobre extremo, 2=pobre

# Clasificar pobreza laboral (alta informalidad + bajos ingresos)
df_final['pobreza_laboral'] = (
    (df_final['tasa_informalidad'] >= 0.5) &
    (df_final['inghog2d'] < df_final['inghog2d'].quantile(0.4))
).astype(int)

# ==================================================
# PASO 5: Análisis descriptivo
# ==================================================

# Resumen general
print(f"\n{'='*60}")
print(f"RESULTADOS DEL ANÁLISIS")
print(f"{'='*60}")
print(f"Total de hogares analizados: {len(df_final):,}")
print(f"\nPobreza Monetaria:")
print(f"  • Hogares pobres: {df_final['es_pobre_monetario'].sum():,} ({df_final['es_pobre_monetario'].mean()*100:.1f}%)")
print(f"\nPobreza Laboral:")
print(f"  • Hogares con pobreza laboral: {df_final['pobreza_laboral'].sum():,} ({df_final['pobreza_laboral'].mean()*100:.1f}%)")
print(f"\nInformalidad:")
print(f"  • Tasa promedio de informalidad: {df_final['tasa_informalidad'].mean()*100:.1f}%")

# Análisis por dominio geográfico
analisis_geografico = df_final.groupby('dominio').agg({
    'es_pobre_monetario': 'mean',
    'pobreza_laboral': 'mean',
    'tasa_informalidad': 'mean',
    'inghog2d': 'median'
}).round(3) * 100

print(f"\n{'='*60}")
print("Indicadores por Dominio Geográfico (%)")
print(f"{'='*60}")
print(analisis_geografico)

# Exportar dataset final
df_final.to_csv('analisis_pobreza_completo_2024.csv', index=False)
print(f"\n✓ Dataset final guardado: {df_final.shape[0]:,} hogares × {df_final.shape[1]} variables")

Output esperado:

✓ Datasets descargados:
  • Hogares: 33,691 registros
  • Personas: 117,755 registros
✓ Módulos individuales fusionados: (117755, 45)
✓ Módulos de hogar fusionados: (33691, 28)

============================================================
RESULTADOS DEL ANÁLISIS
============================================================
Total de hogares analizados: 33,691

Pobreza Monetaria:
  • Hogares pobres: 6,812 (20.2%)

Pobreza Laboral:
  • Hogares con pobreza laboral: 16,352 (48.5%)

Informalidad:
  • Tasa promedio de informalidad: 72.9%

✓ Dataset final guardado: 33,691 hogares × 68 variables

Código completo del ejemplo: Ver examples/investigacion/analisis_pob_mon_lab.ipynb y examples/investigacion/analisis_pob_mon_lab.py


🗺️ Merge Geográfico con UBIGEO

Ejemplo simple de cómo agregar información geográfica (departamento, provincia, distrito) usando la tabla UBIGEO oficial del INEI.

Archivo: examples/investigacion/merger_enahopy_geografico.py

from enahopy.merger.geographic.merger import GeographicMerger
import pandas as pd

# Cargar datos finales del análisis
df = pd.read_csv('dataframe_final_2024.csv')

# Cargar tabla UBIGEO oficial (1,891 distritos)
df_ubigeo = pd.read_excel('UBIGEO_2022_1891_distritos.xlsx')
df_ubigeo = df_ubigeo[['IDDIST', 'NOMBDEP', 'NOMBPROV', 'NOMBDIST']]
df_ubigeo = df_ubigeo.rename(columns={'IDDIST': 'ubigeo'})
df_ubigeo = df_ubigeo.dropna()

# Fusionar con GeographicMerger
merger = GeographicMerger()
df_geo, report = merger.merge(df, df_ubigeo, columna_union='ubigeo')

print(f"✓ Registros con geografía: {report['output_rows']}")
print(f"✓ Columnas agregadas: NOMBDEP, NOMBPROV, NOMBDIST")

# Guardar resultado
df_geo.to_csv('dataframe_final_completo_geografico_2024.csv', index=False)

Output:

✓ Registros con geografía: 33,691
✓ Columnas agregadas: NOMBDEP, NOMBPROV, NOMBDIST

🏗️ Arquitectura del Paquete

enahopy/
├── loader/              # Descarga y lectura de datos ENAHO
│   ├── core/           # Configuración y excepciones
│   ├── io/             # Readers (DTA, SAV, CSV, Parquet) y downloaders
│   └── utils/          # Utilidades y funciones auxiliares
├── merger/             # Fusión de módulos y datos geográficos
│   ├── geographic/     # Manejo de UBIGEO y validación geográfica
│   ├── modules/        # Fusión entre módulos ENAHO (01, 02, 05, 34, sumaria)
│   └── strategies/     # Estrategias de fusión (hogar, persona, panel)
└── null_analysis/      # Análisis de valores faltantes
    ├── core/          # Motor de análisis y clasificación
    ├── patterns/      # Detección de patrones (MCAR, MAR, MNAR)
    ├── strategies/    # Estrategias de imputación (media, KNN, ML)
    └── reports/       # Generación de reportes y visualizaciones

📚 Módulos ENAHO Soportados

Módulo Descripción Nivel
01 Características de la vivienda y del hogar Hogar
02 Características de los miembros del hogar Persona
03 Educación Persona
04 Salud Persona
05 Empleo e ingresos Persona
34 Programas sociales Hogar
37 Gastos del hogar Hogar
sumaria Indicadores agregados (gasto, ingreso, pobreza) Hogar

🔧 Configuración Avanzada

Cache y Performance

from enahopy.loader import ENAHOConfig, ENAHODataDownloader

# Configuración con cache habilitado
config = ENAHOConfig(
    cache_dir='.enaho_cache',       # Directorio de cache
    enable_cache=True,               # Habilitar sistema de cache
    max_workers=4,                   # Workers para descarga paralela
    chunk_size=50000,                # Tamaño de chunks para lectura
    enable_validation=True           # Validar columnas al cargar
)

downloader = ENAHODataDownloader(config=config)

# Primera descarga: ~30 segundos (descarga desde INEI)
# Segunda descarga: <1 segundo (lee desde cache local)
df = downloader.download_module(year=2023, module='sumaria', format='dta')

Validación Estricta en Mergers

from enahopy.merger import MergerConfig, ENAHOMerger

# Configuración con validación estricta
config = MergerConfig(
    validate_merge=True,      # Validar antes de fusionar
    strict_mode=True,         # Modo estricto (falla si hay errores)
    allow_duplicates=False,   # No permitir duplicados
    validate_ubigeo=True      # Validar códigos UBIGEO
)

merger = ENAHOMerger(config=config)

📊 Ejemplos y Tutoriales

El repositorio incluye scripts de demostración completos:

También hay Jupyter notebooks en examples/:

🤝 Contribuir

¡Las contribuciones son bienvenidas! Ver CONTRIBUTING.md para detalles completos.

Setup de desarrollo:

# Clonar repositorio
git clone https://github.com/elpapx/enahopy.git
cd enahopy

# Instalar en modo desarrollo con dependencias
pip install -e .[dev]

# Instalar pre-commit hooks
pre-commit install

# Ejecutar tests
pytest tests/ -v

# Verificar estilo de código
black enahopy/ tests/
flake8 enahopy/
isort enahopy/ tests/

# Generar reporte de cobertura
pytest tests/ --cov=enahopy --cov-report=html

Estado del CI/CD

Todos los PRs son validados automáticamente:

  • Quality Checks: black, flake8, isort
  • Multi-platform Tests: Ubuntu, Windows, macOS
  • Python Matrix: 3.8, 3.9, 3.10, 3.11, 3.12
  • Coverage: Cobertura mínima 40%
  • Build Validation: Empaquetado PyPI

📈 Roadmap

Próximas características:

  • Soporte para ENDES (Encuesta Demográfica y de Salud Familiar)
  • Integración con ENAPRES (Encuesta Nacional de Programas Presupuestales)
  • Dashboard interactivo con Streamlit
  • Exportación a formatos R (RData, feather)
  • Análisis longitudinal (paneles multi-año)
  • API REST para servicios web

📄 Licencia

Este proyecto está bajo la Licencia MIT - ver LICENSE para detalles.

📞 Soporte

🙏 Agradecimientos

  • INEI (Instituto Nacional de Estadística e Informática) por la disponibilización de microdatos públicos
  • Comunidad de investigadores y analistas de datos sociales en Perú
  • Todos los contribuidores y usuarios del proyecto

Desarrollado con ❤️ para la comunidad de investigación social y económica en Perú

Made in Peru

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

enahopy-1.0.0-py3-none-any.whl (367.8 kB view details)

Uploaded Python 3

File details

Details for the file enahopy-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: enahopy-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 367.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for enahopy-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 75e8f109efe0196a7b1a95ee9c9cc59af311bb9aae975ee4f9d5f2608dd2bbd0
MD5 a1c87ceb23306784a772b5a23f916cb8
BLAKE2b-256 daba0297ddf93a232aa8369c2538137ff5e96dbe7e3282ba9f5608136c625ba7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page