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>
4.8 KiB
4.8 KiB
id, name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, example, tested, tests, test_file_path, file_path, params, output
| id | name | kind | lang | domain | version | purity | signature | description | tags | uses_functions | uses_types | returns | returns_optional | error_type | imports | example | tested | tests | test_file_path | file_path | params | output | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| compute_vocabulary_stats_py_datascience | compute_vocabulary_stats | function | py | datascience | 1.0.0 | pure | def compute_vocabulary_stats(texts: list, top_k: int = 20, remove_stopwords: bool = True) -> dict | Profiles the vocabulary of a text corpus for EDA: tokenises a list of documents, counts term frequencies and derives lexical-richness measures — total tokens, unique types, type-token ratio (TTR), hapax legomena and the top-k most frequent terms. Pure, stdlib only (re + collections.Counter); no nltk, no sklearn. Inline ES+EN stopword list, opt-out via remove_stopwords. Never raises: empty/degenerate input returns the zeroed result. |
|
false |
|
from datascience.compute_vocabulary_stats import compute_vocabulary_stats result = compute_vocabulary_stats(["el gato y el perro", "gato veloz"], top_k=5) | true |
|
python/functions/datascience/compute_vocabulary_stats_test.py | python/functions/datascience/compute_vocabulary_stats.py |
|
Dict with the exact keys n_tokens (int), n_types (int), ttr (float|None, n_types/n_tokens rounded to 4 dp), n_hapax (int, terms occurring exactly once), hapax_pct (float|None, n_hapax/n_types*100 rounded to 2 dp) and top_terms (list of {term, count, pct} sorted by count descending, pct = count/n_tokens*100 rounded to 2 dp). For an empty corpus (no tokens after filtering): n_tokens=0, n_types=0, ttr=None, n_hapax=0, hapax_pct=None, top_terms=[]. Any exception degrades to that same empty result — the function never throws. |
Ejemplo
from datascience.compute_vocabulary_stats import compute_vocabulary_stats
compute_vocabulary_stats(
["el gato y el perro", "gato veloz corre", "perro perro perro"],
top_k=5,
)
# {
# "n_tokens": 6, # stopwords (el, y) eliminadas por defecto
# "n_types": 3, # gato, perro, veloz, corre -> tras quitar stopwords
# "ttr": 0.5, # n_types / n_tokens
# "n_hapax": 2, # veloz, corre (1 aparicion cada uno)
# "hapax_pct": 50.0, # n_hapax / n_types * 100
# "top_terms": [
# {"term": "perro", "count": 4, "pct": 44.44},
# {"term": "gato", "count": 2, "pct": 22.22},
# ...
# ],
# }
# Perfil lexico crudo (sin filtrar stopwords):
compute_vocabulary_stats(["the cat and the dog"], remove_stopwords=False)
Cuando usarla
Úsala al perfilar una columna o corpus de texto libre en un EDA del grupo eda:
cuando necesites medir la riqueza léxica (cuántos tokens y cuántas palabras
distintas, type-token ratio, porcentaje de palabras que solo aparecen una vez) y
ver qué términos dominan el vocabulario (top-k frecuencias). Pásale la lista de
documentos crudos (filas de la columna); None y valores no-string se ignoran
solos. Es el equivalente para texto largo de summarize_categorical, que perfila
categorías cortas.
Gotchas
- Función pura y stdlib-only, pero el resultado depende del idioma: la lista
_STOPWORDScubre español e inglés. Para otros idiomas ponremove_stopwords=Falseo filtra fuera, o el perfil mezclará stopwords no reconocidas entop_terms. - La tokenización es
\w+conre.UNICODE: separa por puntuación y conserva acentos/ñ, pero NO hace stemming ni lematización — "gato" y "gatos" cuentan como tipos distintos. Tampoco hace stripping de acentos, así que "más" (con tilde) y "mas" son tokens diferentes (ambos están en la stoplist). - Los tokens puramente numéricos (
"123") se descartan siempre; un token alfanumérico mixto ("covid19") se conserva. ttrbaja artificialmente en corpus grandes (más texto, más repetición): no compares TTR entre corpus de tamaños muy distintos sin normalizar.- Nunca lanza: entrada vacía,
None, o cualquier excepción interna devuelven el resultado con ceros/None/[]. Comprueban_tokens == 0para detectar el caso degenerado.