Files
fn_registry/python/functions/datascience/compute_vocabulary_stats.md
T
egutierrez 105e56cf05 feat(eda): capítulo text_distr (TEXTO/NLP) — primer capítulo de datos no tabulares
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>
2026-06-30 20:38:17 +02:00

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.
eda
datascience
text
nlp
vocabulary
ttr
hapax
pure
python
false
re
collections
from datascience.compute_vocabulary_stats import compute_vocabulary_stats result = compute_vocabulary_stats(["el gato y el perro", "gato veloz"], top_k=5) true
test_basico
test_vacio
test_stopwords_quitadas
test_stopwords_conservadas
python/functions/datascience/compute_vocabulary_stats_test.py python/functions/datascience/compute_vocabulary_stats.py
name desc
texts List of documents (strings) forming the corpus. Entries that are None or not a str are silently discarded. Tokens are extracted per document with re.findall(r'\w+', doc.lower(), re.UNICODE); purely numeric tokens (tok.isdigit()) are dropped.
name desc
top_k Maximum number of most-frequent terms to return in top_terms. Default 20. Does not affect n_tokens/n_types/ttr/hapax — only the length of the top_terms list.
name desc
remove_stopwords When True (default) common Spanish+English stopwords from the inline _STOPWORDS set (~120 entries) are removed from the token stream before any counting. Set False to keep every word (raw lexical profile).
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 _STOPWORDS cubre español e inglés. Para otros idiomas pon remove_stopwords=False o filtra fuera, o el perfil mezclará stopwords no reconocidas en top_terms.
  • La tokenización es \w+ con re.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.
  • ttr baja 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/[]. Comprueba n_tokens == 0 para detectar el caso degenerado.