Files
fn_registry/python/functions/datascience/describe_clusters_llm.md
T
egutierrez 4de071f2f9 feat(eda): project_clusters_2d + describe_clusters_llm para el capitulo MODELOS
project_clusters_2d (pura): PCA(2)+KMeans sobre el MISMO subset estandarizado,
devolviendo proyeccion 2D y labels alineados por fila + centroides en espacio PCA
+ perfiles de cluster desestandarizados. Es la pieza que garantiza la alineacion
points<->labels que pca_explained y kmeans_segments no cubren (estandarizan por
separado y kmeans descarta los labels). Habilita el scatter PCA coloreado por
cluster (MUST-8.1).

describe_clusters_llm (impura): micro-analisis LLM de los clusters en una sola
llamada a ask_llm (grupo claude-direct), devuelve titulo + descripcion por cluster
con degradacion dict-no-throw a titulos genericos si el LLM no responde (MUST-8.2).

Ambas re-exportadas en datascience/__init__.py. Tests: 6/6 y 9/9 (sin red).

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

5.8 KiB

name, kind, lang, domain, version, purity, signature, description, tags, params, output, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags params output uses_functions uses_types returns returns_optional error_type imports tested tests test_file_path file_path
describe_clusters_llm function py datascience 1.0.0 impure def describe_clusters_llm(cluster_profiles: list, feature_names: list, model: str = "claude-haiku-4-5-20251001") -> dict Micro-analisis LLM de clusters de KMeans (grupo eda). Toma los perfiles AGREGADOS de cada cluster (los que produce project_clusters_2d: tamano, centroide en escala original, features distintivas y centroide en z-score) y, con UNA sola llamada al LLM, pide por cada cluster un TITULO corto + una descripcion de 1-2 frases en espanol. Clave de coste/privacidad: NO envia filas crudas, solo el resumen agregado de cada grupo (tamano, % del total y la media de las features distintivas con su signo respecto a la media global). Reusa ask_llm del grupo claude-direct (API directa con token OAuth de Claude). Impura, dict-no-throw: nunca lanza, degrada a titulos genericos 'Cluster N' si el LLM no responde o el parseo falla.
eda
clustering
llm
claude-direct
datascience
kmeans
name desc
cluster_profiles Lista de perfiles de cluster con la forma que produce project_clusters_2d: cada uno {cluster:int, size:int, pct:float, centroid_original:{feature: media en escala original}, distinctive:[features distintivas], centroid_z:{feature: z-score}}. Solo se le envia al LLM un resumen agregado; nunca filas crudas. Lista vacia o no-lista -> clusters=[] sin llamar al LLM.
name desc
feature_names Nombres de las features del dataset. Se incluyen como contexto en el prompt para que el LLM pueda nombrar los clusters; no es obligatorio que coincida con las features distintivas de cada perfil.
name desc
model id del modelo Anthropic a usar. Default 'claude-haiku-4-5-20251001' (haiku, coste bajo, ~2-3s). Para titulos/descripciones mas finas, pasar p.ej. 'claude-opus-4-8'.
dict dict-no-throw: {clusters:[{cluster:int, title:str, description:str}], model:str, note:str}. note=='' si todo fue bien. Si el LLM no respondio (note='LLM no disponible') o el parseo fallo (note='parse fallido'), clusters trae titulos genericos 'Cluster N' con description vacia. Si cluster_profiles esta vacio o no es lista: {clusters:[], model, note:'sin clusters'}. NUNCA lanza.
ask_llm_py_core
false error_go_core
true
test_parse_clusters_json_valid_array
test_parse_clusters_json_wrapped_in_junk_text
test_parse_clusters_json_non_json_returns_none
test_parse_clusters_json_fills_missing_cluster_by_index
test_describe_clusters_llm_ok_with_monkeypatched_llm
test_describe_clusters_llm_degrades_on_empty_response
test_describe_clusters_llm_degrades_on_unparseable_response
test_describe_clusters_llm_empty_list_skips_llm
test_describe_clusters_llm_non_list_input_skips_llm
python/functions/datascience/describe_clusters_llm_test.py python/functions/datascience/describe_clusters_llm.py

Ejemplo

import sys, os
sys.path.insert(0, os.path.join("python", "functions"))

from datascience.describe_clusters_llm import describe_clusters_llm

# Perfiles agregados producidos por project_clusters_2d (no hay filas crudas).
cluster_profiles = [
    {
        "cluster": 0, "size": 60, "pct": 60.0,
        "centroid_original": {"acidez": 8.5, "alcohol": 9.2},
        "distinctive": ["acidez", "alcohol"],
        "centroid_z": {"acidez": 1.4, "alcohol": -0.9},
    },
    {
        "cluster": 1, "size": 40, "pct": 40.0,
        "centroid_original": {"acidez": 5.1, "alcohol": 13.0},
        "distinctive": ["alcohol"],
        "centroid_z": {"acidez": -0.7, "alcohol": 1.6},
    },
]
feature_names = ["acidez", "alcohol", "azucar"]

out = describe_clusters_llm(cluster_profiles, feature_names)   # haiku por defecto
# out = describe_clusters_llm(cluster_profiles, feature_names, model="claude-opus-4-8")

if not out["note"]:
    for c in out["clusters"]:
        print(f"Cluster {c['cluster']}: {c['title']}")
        print("   ", c["description"])
else:
    # Degradacion: titulos genericos "Cluster N".
    print("LLM no usado:", out["note"])
    for c in out["clusters"]:
        print(c["cluster"], c["title"])

Cuando usarla

Cuando ya has clusterizado un dataset (KMeans + project_clusters_2d) y quieres poner NOMBRE y descripcion legible a cada grupo en vez de dejar "Cluster 0/1/2". Es el paso interpretativo que sigue al perfilado de clusters: project_clusters_2d calcula tamano, centroides y features distintivas, y describe_clusters_llm los traduce a un titulo corto + 1-2 frases por cluster. Usala al cerrar un EDA con segmentacion para el resumen final o el report. Una sola llamada al LLM describe todos los clusters a la vez (barato).

Gotchas

  • Impura: hace 1 llamada de red al LLM. No es determinista ni gratis. Latencia tipica ~2-3s con haiku.
  • Requiere token OAuth de Claude en ~/.claude/.credentials.json (via ask_llm / grupo claude-direct). Sin token / sin red, NO lanza: degrada a titulos genericos Cluster N con note="LLM no disponible".
  • NO envia filas crudas al LLM, solo el resumen AGREGADO de cada cluster (tamano, % del total y la media de las features distintivas con su signo respecto a la media global). Privacidad y coste minimos por diseno — pero requiere que los perfiles vengan ya calculados por project_clusters_2d.
  • Modelo haiku por defecto para coste bajo; sube a claude-opus-4-8 si necesitas titulos/descripciones mas finas (mas caro y lento).
  • dict-no-throw: si el modelo no devuelve un JSON array parseable, retorna titulos genericos con note="parse fallido". Comprueba siempre out["note"] antes de fiarte de los titulos.
  • El LLM puede sobre-interpretar: el system prompt le pide ser sobrio y no inventar causas, pero revisa los titulos antes de publicarlos en un report.