105e56cf05
Añade el capítulo `text_distr` al motor AutomaticEDA: perfila columnas de texto libre largo (reseñas, descripciones, comentarios) que la distribución categórica no resume bien. Sigue el patrón de cat_distr/num_distr (build_text_distr(profile, ctx) -> Chapter | None) y se registra en CHAPTER_ORDER tras cat_distr. Activación en dos fases: gate barato desde el perfil (columna no numérica con len_mean >= 50 chars) + confirmación con muestra cruda (mediana de palabras >= 20). Un dataset sin texto largo (p.ej. titanic) devuelve None sin tocar el informe. Bloques por columna (Group con page_break): resumen (longitudes, vocabulario con TTR y % hapax, idioma dominante, % duplicados, legibilidad), histograma de longitudes, top términos (tabla + barras), bigramas/trigramas, idiomas detectados y nube de palabras opcional. Términos ttr/hapax enganchados al glosario clicable. Lógica delegada a 7 funciones nuevas del registry (datascience, tag eda), estilo dict-no-throw: - extract_text_sample (impura, push-down SQL DuckDB/Postgres) - compute_text_length_stats, compute_vocabulary_stats, compute_top_ngrams (puras, stdlib) - detect_corpus_language (langdetect opcional), compute_text_readability (textstat opcional), compute_text_duplicates (hash + datasketch opcional) Versión barata sin modelos pesados: las piezas que dependen de una librería opcional (langdetect, textstat, wordcloud, datasketch) degradan a omitidas sin lanzar. Añade langdetect y textstat (ligeras) al pyproject + uv.lock. Verificado: golden sobre dataset de reviews multi-idioma (capítulo presente en PDF+PPTX+MD con métricas reales), titanic sin capítulo (None), degradación sin libs, suite automatic_eda + pipeline verde (128 passed), fn index OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.6 KiB
6.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 | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| extract_text_sample | function | py | datascience | 1.0.0 | impure | def extract_text_sample(db_path: str, table: str, columns: list, backend: str = 'duckdb', sample: int = 2000) -> dict | Muestrea columnas de texto de una tabla DuckDB/Postgres con push-down SQL (LIMIT sample), SIN traer la tabla entera a RAM. Funcion impura del grupo de capacidad `eda`: la usan los capitulos de texto/NLP del AutomaticEDA que necesitan valores crudos de texto (longitudes, tokens, ejemplos) sobre una muestra acotada. Construye el lector read-only query_fn(sql)->dict igual que build_eda_render_ctx (closure sobre duckdb_query_readonly / pg_query importados perezosamente desde infra). Escapa los identificadores con comillas dobles y lanza una sola query SELECT "c1", "c2" FROM "table" LIMIT n. Por columna, la lista de strings solo contiene valores NO None y NO vacios: cada celda no nula se convierte con str(...) y se descarta si queda cadena vacia. Estilo dict-no-throw del grupo eda: NUNCA lanza; ante cualquier fallo (query, conversion, backend desconocido) devuelve {status:'error', error:str, columns:{}, n:0}. La clave n reporta el numero de FILAS leidas por la query (antes de filtrar None/vacios). |
|
|
false | error_go_core |
|
dict dict-no-throw (NUNCA lanza): {status:'ok'|'error', columns:{col_name:[str,...]}, n:int, error:str}. En exito (status='ok') columns mapea cada columna pedida a la lista de sus valores de texto NO None y NO vacios (cada celda convertida con str(...)); n es el numero de FILAS leidas por la query (antes de filtrar None/vacios). columns vacio -> {status:'ok', columns:{}, n:0}. En error (backend desconocido, query con status!='ok', o cualquier excepcion) -> {status:'error', error:str, columns:{}, n:0}; la clave error solo aparece en este caso. | true |
|
python/functions/datascience/extract_text_sample_test.py | python/functions/datascience/extract_text_sample.py |
Ejemplo
import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
# Import directo del submodulo (no requiere export en datascience/__init__.py).
from datascience.extract_text_sample import extract_text_sample
# Muestrea hasta 2000 filas de dos columnas de texto de una tabla DuckDB.
res = extract_text_sample(
"data/reviews.duckdb", "reviews", ["title", "body"],
backend="duckdb", sample=2000,
)
# res == {
# "status": "ok",
# "columns": {
# "title": ["Gran producto", "No funciona", ...], # solo no-None, no-""
# "body": ["Lo uso a diario...", ...],
# },
# "n": 2000, # filas leidas por la query (antes de filtrar None/vacios)
# }
# Postgres: db_path es el DSN.
res_pg = extract_text_sample(
"postgresql://user:pass@localhost:5433/trends", "comentarios", ["texto"],
backend="postgres", sample=500,
)
Cuando usarla
Cuando necesites valores CRUDOS de texto de una o varias columnas para analisis
NLP/texto (distribucion de longitudes, conteo de tokens, ejemplos representativos,
deteccion de idioma) pero NO quieras cargar la tabla entera en memoria. Es el
muestreador de texto del grupo eda: una sola llamada con push-down LIMIT
devuelve listas de strings por columna, limpias de None y vacios, listas para
alimentar un capitulo de texto del AutomaticEDA o cualquier rutina de tokenizado.
Usala junto a profile_table / build_eda_render_ctx cuando el perfil agregado
no basta y hace falta el texto real.
Gotchas
- Impura: lee de la base de datos a traves de
query_fn(closure sobreduckdb_query_readonly/pg_query). No abre conexiones fuera de esos wrappers del registry. Estilo dict-no-throw del grupoeda: NUNCA lanza; ante cualquier fallo devuelve{status:'error', error:str, columns:{}, n:0}. error_typeen el frontmatter eserror_go_corepor convencion del registry (toda funcion impura debe declararlo y el indexer lo exige), pero el codigo NO lanza esa excepcion: degrada al dict de error. Es metadata, no comportamiento.- Backend desconocido: con un
backendque no seaduckdbnipostgresdevuelve{status:'error', error:'backend desconocido: <valor>', columns:{}, n:0}sin tocar la base. - Las listas NO incluyen None ni cadenas vacias: cada celda no nula se pasa
por
str(...)y se descarta si queda"". Por esolen(columns[col])puede ser menor quen(que cuenta las filas leidas). Si necesitas alineacion por fila (una entrada por fila aunque sea None), usabuild_eda_render_ctx(raw_numeric), no esta funcion. LIMIT samplesinORDER BY: con tablas grandes obtienes el primer tramo por orden fisico del backend, no un muestreo uniforme ni reproducible. Subesamplepara mas cobertura, o pre-ordena/aleatoriza la tabla si necesitas representatividad.- DuckDB en sandbox por defecto:
duckdb_query_readonlyabre la conexion conenable_external_access=False, asi que la query solo puede leer la propia base (noread_csv/httpfs/ATTACHa paths externos). Lee tablas ya existentes en el archivo DuckDB sin problema. - No loguear los datos crudos: las listas de
columnspueden contener texto sensible (reviews, comentarios, PII). En trazas usa solo conteos (n,len(columns[col])) y nombres de columna, no el dict completo.