7fa19d65db
Añade el capítulo `missingness` al motor AutomaticEDA, complemento natural de `calidad`: donde calidad reporta cuánto falta por columna, este capítulo analiza el PATRÓN de los nulos — dónde faltan y si las columnas faltan juntas (co-ocurrencia de ausencias), la señal que distingue MCAR de MAR antes de imputar. Capítulo (`chapters/missingness.py`), registrado en `chapters_registry.py` justo tras `calidad`: - Resumen global: % de celdas faltantes, columnas con nulos, filas completas vs incompletas. - Ranking por columna (tabla + barras horizontales). - Co-ocurrencia: correlación de las máscaras is-null entre columnas (heatmap + tabla de los pares que co-faltan, con co-faltantes y Jaccard). - Patrones de fila más frecuentes (estilo matriz de missingno). - Lectura MCAR/MAR exploratoria (heurística por correlación/solape de ausencias, no confirmatoria), que cita la evidencia concreta. - Términos de glosario clicables: missingness, MCAR, MAR. La máscara is-null por fila de TODAS las columnas (numéricas y categóricas) se construye con un push-down DuckDB sobre ctx['db_path']/table (mismo patrón que el capítulo agregación), con fallback a ctx['raw_numeric'] cuando no hay BD. Activa solo si la tabla tiene nulos; si no, devuelve None. Funciones nuevas del grupo `eda` (dominio datascience): - extract_null_mask (impura): máscara is-null por fila vía query_fn. - missingness_overview (pura): resumen global + filas completas/incompletas. - missingness_correlation (pura): correlación de ausencias + pares + Jaccard, reutiliza pearson. - missingness_row_patterns (pura): patrones de fila más comunes. - missingness_corr_heatmap_figure / missingness_rank_bar_figure (impuras): figuras. Verificado: EDA de titanic genera el capítulo en PDF + PPTX + MD con Cabin 77.1%, Age 19.9% y la co-ocurrencia Age↔Cabin (158 filas). Suite completa de AutomaticEDA + render_automatic_eda en verde (125 passed); tests por función y por capítulo; fn index sin error. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
100 lines
5.0 KiB
Markdown
100 lines
5.0 KiB
Markdown
---
|
|
id: missingness_overview_py_datascience
|
|
name: missingness_overview
|
|
kind: function
|
|
lang: py
|
|
domain: datascience
|
|
version: "1.0.0"
|
|
purity: pure
|
|
signature: "def missingness_overview(null_mask) -> dict"
|
|
description: "Resumen de ausencias a nivel de dataset a partir de una máscara de nulos 0/1 por columna ({col: [1=falta, 0=presente]} alineada por fila). Calcula celdas y porcentaje de datos faltantes, cuántas columnas tienen algún nulo y cuántas filas son completas vs. incompletas. Estilo dict-no-throw del grupo eda: nunca lanza. Lectura defensiva — no-dict o dict vacío devuelve todo a 0; columnas no-lista se tratan como vacías; listas de longitud distinta se alinean a la longitud máxima rellenando la cola corta como presente (0); valores None/no-int cuentan como presente; sin ZeroDivisionError."
|
|
tags: [eda, missing, missingness, nulls, profiling, datascience, pure]
|
|
uses_functions: []
|
|
uses_types: []
|
|
returns: []
|
|
returns_optional: false
|
|
error_type: ""
|
|
imports: []
|
|
example: |
|
|
from datascience.missingness_overview import missingness_overview
|
|
mask = {
|
|
"a": [1, 0, 0, 0, 1],
|
|
"b": [1, 0, 1, 0, 0],
|
|
"c": [0, 0, 0, 0, 1],
|
|
}
|
|
missingness_overview(mask)
|
|
# n_missing_cells=5, missing_cell_pct≈33.33, complete_rows=2, incomplete_rows=3
|
|
tested: true
|
|
tests:
|
|
- "test_cooccurrence_three_cols_exact"
|
|
- "test_empty_dict_all_zero"
|
|
- "test_output_keys_contract"
|
|
- "test_not_a_dict_returns_zero"
|
|
- "test_no_nulls_all_complete"
|
|
- "test_none_values_treated_as_present"
|
|
- "test_unequal_lengths_pad_with_max"
|
|
- "test_columns_present_but_no_rows"
|
|
- "test_never_raises_on_garbage"
|
|
test_file_path: "python/functions/datascience/missingness_overview_test.py"
|
|
file_path: "python/functions/datascience/missingness_overview.py"
|
|
params:
|
|
- name: null_mask
|
|
desc: "Dict {col_name: [int 0/1, ...]} con la máscara de nulos por columna, alineada por fila (1 = el valor falta, 0 = el valor está presente). Normalmente todas las listas tienen la misma longitud = nº de filas. Lectura defensiva: si no es dict o está vacío se devuelve todo a 0; columnas cuyo valor no es lista/tupla se tratan como vacías; listas de longitud distinta se alinean a la longitud máxima (las posiciones inexistentes de las columnas más cortas cuentan como presentes, 0); valores None o no enteros cuentan como presentes."
|
|
output: "Dict con exactamente 9 claves, todas siempre presentes (la función nunca lanza): n_rows (longitud de fila = longitud máxima entre columnas, 0 si vacío), n_cols (nº de columnas), n_cols_with_null (columnas con >=1 falta), n_missing_cells (suma total de 1s), missing_cell_pct (0-100 = n_missing_cells / (n_rows*n_cols) * 100), complete_rows (filas sin ninguna falta), incomplete_rows (filas con >=1 falta), complete_pct (0-100), incomplete_pct (0-100). Los porcentajes son 0.0 cuando el denominador es 0 (sin ZeroDivisionError)."
|
|
---
|
|
|
|
## Ejemplo
|
|
|
|
```python
|
|
from datascience.missingness_overview import missingness_overview
|
|
|
|
# Máscara de nulos por columna: 1 = falta, 0 = presente, alineada por fila.
|
|
mask = {
|
|
"a": [1, 0, 0, 0, 1],
|
|
"b": [1, 0, 1, 0, 0],
|
|
"c": [0, 0, 0, 0, 1],
|
|
}
|
|
|
|
missingness_overview(mask)
|
|
# {
|
|
# "n_rows": 5,
|
|
# "n_cols": 3,
|
|
# "n_cols_with_null": 3, # a, b y c tienen al menos una falta
|
|
# "n_missing_cells": 5, # 2 (a) + 2 (b) + 1 (c)
|
|
# "missing_cell_pct": 33.33, # 5 / (5*3) * 100
|
|
# "complete_rows": 2, # filas 1 y 3 sin ninguna falta
|
|
# "incomplete_rows": 3, # filas 0 (a&b), 2 (b), 4 (a&c)
|
|
# "complete_pct": 40.0, # 2 / 5 * 100
|
|
# "incomplete_pct": 60.0, # 3 / 5 * 100
|
|
# }
|
|
|
|
missingness_overview({})
|
|
# Todo a 0: {"n_rows": 0, "n_cols": 0, "n_cols_with_null": 0,
|
|
# "n_missing_cells": 0, "missing_cell_pct": 0.0,
|
|
# "complete_rows": 0, "incomplete_rows": 0,
|
|
# "complete_pct": 0.0, "incomplete_pct": 0.0}
|
|
```
|
|
|
|
## Cuando usarla
|
|
|
|
Úsala al perfilar un dataset cuando ya tienes una máscara de nulos 0/1 por
|
|
columna (p. ej. derivada del paso de carga/perfilado del EDA) y quieres la foto
|
|
global de ausencias en una llamada: cuánta proporción de celdas falta, cuántas
|
|
columnas están afectadas y, sobre todo, cuántas filas quedan completas vs.
|
|
incompletas. Es el bloque resumen del capítulo de calidad/missingness de un EDA,
|
|
y la base para decidir estrategias de imputación o de borrado de filas. Como es
|
|
pura y dict-no-throw, puedes alimentarla con la máscara tal cual sin validarla
|
|
antes: entradas malformadas degradan a ceros en vez de romper el pipeline.
|
|
|
|
## Gotchas
|
|
|
|
- **`n_rows` es la longitud máxima entre columnas.** Con listas de longitud
|
|
desigual, las posiciones que faltan en las columnas más cortas se cuentan como
|
|
presentes (`0`); no se descartan filas. En el caso normal (todas las listas de
|
|
igual longitud) `n_rows` es simplemente esa longitud.
|
|
- **Solo el valor exacto `1` cuenta como falta.** `None`, `0`, cadenas y
|
|
cualquier otro valor se tratan como presentes. `True` (== 1) también cuenta
|
|
como falta por la igualdad.
|
|
- **Porcentajes en escala 0-100**, no fracciones. División por cero protegida:
|
|
con `n_rows*n_cols == 0` los porcentajes salen `0.0`.
|