--- id: compute_vocabulary_stats_py_datascience name: compute_vocabulary_stats kind: function lang: py domain: datascience version: "1.0.0" purity: pure signature: "def compute_vocabulary_stats(texts: list, top_k: int = 20, remove_stopwords: bool = True) -> dict" description: "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." tags: [eda, datascience, text, nlp, vocabulary, ttr, hapax, pure, python] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "" imports: [re, collections] example: | from datascience.compute_vocabulary_stats import compute_vocabulary_stats result = compute_vocabulary_stats(["el gato y el perro", "gato veloz"], top_k=5) tested: true tests: - "test_basico" - "test_vacio" - "test_stopwords_quitadas" - "test_stopwords_conservadas" test_file_path: "python/functions/datascience/compute_vocabulary_stats_test.py" file_path: "python/functions/datascience/compute_vocabulary_stats.py" params: - name: texts desc: "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: top_k desc: "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: remove_stopwords desc: "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)." output: "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 ```python 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.