feat(browser): auto-commit con 178 cambios

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-20 18:22:23 +02:00
parent 7d100e7f3e
commit 763e06c127
178 changed files with 19917 additions and 317 deletions
@@ -0,0 +1,126 @@
---
id: mutual_info_columns_py_datascience
name: mutual_info_columns
kind: function
lang: py
domain: datascience
version: "1.0.0"
purity: pure
signature: "def mutual_info_columns(a: list, b: list, a_numeric: bool = False, b_numeric: bool = False, bins: int = 10, normalized: bool = True) -> float"
description: "Informacion mutua entre dos columnas pareadas del grupo eda: detector general de dependencia que capta relaciones de cualquier forma (lineal o no, num-num, cat-cat, num-cat). Discretiza numericas por cuantiles, factoriza categoricas, devuelve NMI en [0,1] (normalized) o MI en nats. Funcion pura."
tags: [eda, correlation, mutual-information, association, profiling, datascience]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
example: |
from datascience import mutual_info_columns
a = [i - 1000 for i in range(2000)]
b = [abs(x) for x in a] # V-shape: no lineal, Pearson ~ 0
mutual_info_columns(a, b, a_numeric=True, b_numeric=True) # ~0.69, NMI alto
tested: true
tests:
- "test_identical_categoricals_nmi_near_one"
- "test_nonlinear_numeric_relation_has_positive_nmi"
- "test_independent_columns_near_zero"
- "test_fewer_than_two_pairs_returns_zero"
- "test_none_pairs_are_discarded"
- "test_constant_column_returns_zero_when_normalized"
- "test_unnormalized_returns_mi_in_nats"
- "test_always_returns_float_never_none"
test_file_path: "python/functions/datascience/mutual_info_columns_test.py"
file_path: "python/functions/datascience/mutual_info_columns.py"
params:
- name: a
desc: >
Lista de valores de la primera columna, pareada posicion a posicion con
`b`. None se descarta (junto con su contraparte en `b`).
- name: b
desc: >
Lista de valores de la segunda columna, pareada con `a` (mismo criterio
de descarte de None).
- name: a_numeric
desc: >
Si True, `a` se discretiza en `bins` cubos por cuantiles antes de medir;
si False se trata como categorica (factorizacion valor->id entero).
- name: b_numeric
desc: "Idem que a_numeric pero para la columna `b`."
- name: bins
desc: >
Numero de cubos por cuantiles para las columnas numericas. Cuantiles
repetidos colapsan en menos cubos (columnas de baja variacion).
- name: normalized
desc: >
Si True devuelve la informacion mutua normalizada NMI = MI / sqrt(H(a)*H(b))
en [0, 1] (1 = dependencia total). Si False devuelve la MI cruda en nats.
output: >
float. NMI en [0, 1] cuando normalized=True; MI en nats (>= 0) cuando
normalized=False. Devuelve 0.0 si hay menos de 2 pares validos o si alguna
columna discretizada tiene entropia 0 (constante) bajo normalized. Nunca
devuelve None ni lanza excepcion.
---
## Ejemplo
```python
from datascience import mutual_info_columns
import math
# Relacion NO lineal: b = |a| (forma de V). Pearson ~ 0, pero la dependencia es real.
a = [i - 1000 for i in range(2000)] # -1000 .. 999
b = [abs(x) for x in a]
mutual_info_columns(a, b, a_numeric=True, b_numeric=True)
# -> ~0.69 (NMI alto: a determina b por completo dentro de cada cubo)
# Comparalo con la correlacion lineal, que no ve la relacion:
from datascience import pearson
pearson([float(x) for x in a], [float(x) for x in b]) # -> ~0.0
# Tambien capta relaciones oscilantes resueltas por los bins:
ax = [2 * math.pi * i / 2000 for i in range(2000)] # un periodo de seno
bx = [1.0 if math.sin(x) >= 0 else -1.0 for x in ax]
mutual_info_columns(ax, bx, a_numeric=True) # -> ~0.55, Pearson ~ -0.87
# Dos categoricas identicas -> dependencia total.
c = ["red", "green", "blue", "red", "green", "blue"]
mutual_info_columns(c, list(c)) # -> ~1.0
# MI cruda en nats (sin normalizar).
mutual_info_columns(c, list(c), normalized=False) # -> ~log(3) nats
```
## Cuando usarla
Cuando necesites un **detector general de dependencia** entre dos columnas y no
sepas (o no quieras asumir) la forma de la relacion. Pearson solo ve lineal y
solo num-num; `cramers_v` solo cat-cat. La informacion mutua funciona para
**cualquier par de tipos** (num-num, cat-cat, num-cat) y capta relaciones no
lineales (sinusoidales, escalon, agrupamientos) que la correlacion lineal pasa
por alto. Es la celda "comodin" de una matriz de asociacion en un EDA: usala
para descubrir relaciones ocultas antes de modelar, o para rankear que columnas
predicen mejor un objetivo. Activa `a_numeric`/`b_numeric` por columna segun su
tipo y deja `normalized=True` para obtener un score comparable en [0, 1].
## Notas
Funcion pura y determinista: misma entrada -> misma salida (sin estado, sin
I/O, sin aleatoriedad; `sklearn.metrics.mutual_info_score` es determinista).
- **Discretizacion**: numericas via `np.digitize` sobre los bordes de cuantil
(`np.quantile`); categoricas via mapa valor->id en orden de aparicion. La
eleccion de `bins` afecta la estimacion de MI en columnas numericas: pocos
bins suavizan, muchos bins capturan mas estructura pero inflan el ruido en
muestras pequenas. Una relacion que oscila mas rapido que la resolucion de
los bins (p.ej. un seno de muchos periodos sobre el rango de `a`) da NMI bajo
con `bins` pequeno aunque la dependencia sea real: sube `bins` para resolverla.
- **Sesgo de la MI**: en muestras pequenas la MI cruda tiende a sobreestimarse
(sesgo positivo). La normalizacion NMI lo atenua parcialmente pero no lo
elimina; para columnas independientes con muchos bins y pocos datos el valor
puede no ser exactamente 0.
- **Entropia 0**: si una columna discretizada es constante, H = 0 y la NMI se
define como 0.0 (no hay informacion compartida medible); la MI cruda tambien
es 0 en ese caso.
- **NMI** = MI / sqrt(H(a) * H(b)), clampada a [0, 1] por seguridad numerica.