Files
fn_registry/python/functions/datascience/suggest_intratable_fk_candidates.md
T
egutierrez 68f4ddabce feat(eda): capítulo RELACIONES para AutomaticEDA
Añade el capítulo `relaciones` al motor AutomaticEDA: analiza las
relaciones de clave de la tabla/base y se coloca tras `correlacion`,
antes de `modelos`, en CHAPTER_ORDER.

Capas que renderiza (solo las que aplican; None si no hay nada que decir):
- Claves declaradas: PK/FK/UNIQUE reales del esquema DuckDB, vía la nueva
  función `detect_declared_keys_duckdb` (lee `duckdb_constraints()`).
- Candidatos a clave primaria: los `key_candidates` del TableProfile.
- FK candidatas inter-tabla: reusa `infer_fk_containment_duckdb`
  (containment + señal de nombre) y `build_join_graph` (roles de nodos +
  diagrama Mermaid pegable). Solo si la fuente DuckDB tiene varias tablas.
- FK candidatas intra-tabla: heurística nombre + cardinalidad, vía la nueva
  función pura `suggest_intratable_fk_candidates`, marcada como sugerencia.

Engancha al glosario clicable los términos PK, FK, containment/inclusión y
cardinalidad (contrato §11.1) y usa Group (keep-together) para el grafo.

Funciones nuevas del registry (grupo `eda`):
- detect_declared_keys_duckdb (impure, datascience) + test.
- suggest_intratable_fk_candidates (pure, datascience) + test.

Tests: relaciones_test.py (golden intra + inter, edges, no-cut render) +
los tests de ambas funciones. Suite automatic_eda + render_automatic_eda
verde (89 passed). Golden end-to-end con el pipeline render_automatic_eda
verificado sobre titanic (intra) y una BD customers/orders (inter).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 18:15:15 +02:00

5.6 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
suggest_intratable_fk_candidates function py datascience 1.0.0 pure def suggest_intratable_fk_candidates(profile: dict, max_candidates: int = 20) -> list Sobre el TableProfile de UNA tabla (el dict de profile_table), sugiere por heuristica de nombre + cardinalidad que columnas PARECEN una clave foranea hacia otra tabla, cuando no hay relaciones inter-tabla que medir (una sola tabla). Es una SUGERENCIA, no una afirmacion: el ref_table_guess es el stem del nombre (customer_id -> customer) y NO confirma containment. Pura: solo lee el dict, sin I/O; nunca lanza (devuelve []).
eda
datascience
relationships
foreign-key
fk
heuristic
schema
python
false
name desc
profile TableProfile (dict que produce profile_table / summarize_table_*). Se leen de forma defensiva `columns` (lista de ColumnProfile con name/inferred_type/physical_type/distinct_count/unique_pct/flags), `n_rows` (int) y `key_candidates` (lista de nombres de columna ya candidatos a PK, que se excluyen). Si no es dict o no trae columns -> [].
name desc
max_candidates Tope de sugerencias devueltas (default 20). Las columnas candidatas se ordenan por distinct_count descendente (mas informativas primero) antes de cortar a este maximo.
list (posiblemente vacia) de dicts, uno por columna sugerida, con claves: `column` (nombre), `ref_table_guess` (tabla conjeturada por el stem del nombre, p.ej. customer_id -> 'customer'), `reason` (frase humana que deja claro que es heuristica sin confirmar containment), `distinct_count` (int|None), `unique_pct` (float|None, fraccion 0-1 tal como viene del profile), `inferred_type` (str), `physical_type` (str). Nunca lanza. true
test_golden_customer_id_detectado_otras_no
test_camelcase_albumid_detectado
test_constante_status_id_no_aparece
test_profile_vacio_y_none_devuelven_lista_vacia
test_category_id_casi_unico_parece_pk_no_aparece
test_ref_table_guess_multitoken_y_orden_por_distinct
test_max_candidates_corta_la_lista
test_id_generico_solo_nunca_es_fk
python/functions/datascience/suggest_intratable_fk_candidates_test.py python/functions/datascience/suggest_intratable_fk_candidates.py

Ejemplo

from datascience import suggest_intratable_fk_candidates

# TableProfile de UNA tabla (tipo titanic): customer_id es FK N:1; id es la PK;
# amount es una medida float; name es categorica sin sufijo de id.
profile = {
    "n_rows": 891,
    "key_candidates": ["id"],
    "columns": [
        {"name": "id", "inferred_type": "numeric", "physical_type": "BIGINT",
         "distinct_count": 891, "unique_pct": 1.0, "flags": ["possible_id"]},
        {"name": "customer_id", "inferred_type": "numeric", "physical_type": "BIGINT",
         "distinct_count": 137, "unique_pct": 0.15, "flags": []},
        {"name": "amount", "inferred_type": "numeric", "physical_type": "DOUBLE",
         "distinct_count": 400, "unique_pct": 0.45, "flags": []},
        {"name": "name", "inferred_type": "categorical", "physical_type": "VARCHAR",
         "distinct_count": 700, "unique_pct": 0.78, "flags": []},
    ],
}

out = suggest_intratable_fk_candidates(profile)
[c["column"] for c in out]              # -> ["customer_id"]
out[0]["ref_table_guess"]               # -> "customer"
out[0]["reason"]
# -> "el nombre termina en '_id' y es N:1 (137 valores distintos < 891 filas):
#     parece (heuristica por nombre, sin confirmar containment) una referencia a
#     una tabla «customer»"

Cuando usarla

Cuando el EDA tiene SOLO UNA tabla y, por tanto, no se puede inferir una FK inter-tabla por containment (no hay otra tabla cuyos valores contener). Es el plan B del capitulo RELACIONES de AutomaticEDA: en vez de medir solapamiento de valores entre tablas (lo correcto cuando hay varias, ver infer_fk_containment_duckdb / build_join_graph), conjetura por el NOMBRE de la columna (<algo>_id) y por su CARDINALIDAD N:1 que columnas parecen apuntar a una entidad externa. Usala para enriquecer el reporte con "estas columnas parecen referencias a otras tablas" sin prometer que esa tabla exista. NO la uses si tienes varias tablas: ahi mide containment de verdad.

Gotchas

  • Es heuristica, no una verdad: produce falsos positivos (una columna period_id que en realidad es un codigo libre, no una FK) y falsos negativos (una FK que no se llama *_id, p.ej. parent, owner, sku). No la trates como una afirmacion de esquema.
  • ref_table_guess es una conjetura por el nombre (el stem sin el sufijo id): customer_id -> customer, AlbumId -> album, manager_staff_id -> manager_staff. Puede no coincidir con el nombre real de la tabla (plurales, prefijos, alias). Es una pista, no un join garantizado.
  • NO confirma containment: no comprueba que los valores de la columna existan en ninguna otra tabla (no puede — solo recibe el perfil de una tabla). Para confirmar una FK real con varias tablas usa infer_fk_containment_duckdb.
  • Excluye deliberadamente: el id/Id/ID generico a secas (suele ser la PK propia, no una referencia), las columnas constantes, las que parecen unicas (unique_pct >= 0.99, mas PK que FK) y los tipos no-clave (float/decimal son medidas; date/time/timestamp y boolean no son claves). En camelCase, paid, valid, grid (con id en minuscula y sin separador) NO se confunden con FK.
  • unique_pct se interpreta como fraccion 0-1 (tal como la emite el profile), no como porcentaje 0-100.