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>
5.3 KiB
5.3 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_top_ngrams_py_datascience | compute_top_ngrams | function | py | datascience | 1.0.0 | pure | def compute_top_ngrams(texts, n=2, top_k=15, remove_stopwords=True) -> dict | Calcula los n-gramas de palabras más frecuentes de un corpus de texto (n=1 unigramas, 2 bigramas, 3 trigramas...). Tokeniza a minúsculas con re.findall(r'\w+', ...), descarta tokens numéricos y, si remove_stopwords=True, elimina stopwords ES+EN ANTES de formar los n-gramas (n-gramas contiguos sobre la secuencia de tokens de contenido, sin cruzar documentos). Pura y autocontenida con collections.Counter, sin sklearn. Estilo dict-no-throw del grupo eda: nunca lanza. |
|
false |
|
from datascience.compute_top_ngrams import compute_top_ngrams texts = ["machine learning rocks", "we love machine learning"] compute_top_ngrams(texts, n=2, top_k=5) # {"n": 2, "top": [{"ngram": "machine learning", "count": 2}, ...]} | true |
|
python/functions/datascience/compute_top_ngrams_test.py | python/functions/datascience/compute_top_ngrams.py |
|
Dict con exactamente 2 claves: n (el n recibido, sin normalizar) y top (lista de dicts {'ngram': str, 'count': int} ordenada por count descendente, longitud <= top_k). ngram es la unión de los tokens del n-grama por un espacio. Corpus vacío, tokens insuficientes para formar n-gramas o cualquier excepción interna degradan a {'n': n, 'top': []}. La función nunca lanza. |
Ejemplo
from datascience.compute_top_ngrams import compute_top_ngrams
texts = [
"machine learning rocks",
"machine learning is fun",
"we love machine learning",
]
# Bigramas (n=2): "machine learning" aparece en los 3 documentos.
compute_top_ngrams(texts, n=2, top_k=5)
# {
# "n": 2,
# "top": [
# {"ngram": "machine learning", "count": 3},
# {"ngram": "learning fun", "count": 1},
# {"ngram": "learning rocks", "count": 1},
# {"ngram": "love machine", "count": 1},
# ],
# }
# Unigramas con stopwords fuera (default): solo palabras de contenido.
compute_top_ngrams(["the cat sat on the mat"], n=1, top_k=3)
# {"n": 1, "top": [{"ngram": "cat", "count": 1},
# {"ngram": "mat", "count": 1},
# {"ngram": "sat", "count": 1}]}
Cuando usarla
Úsala en la fase de EDA de texto cuando, además del vocabulario suelto, necesites
ver qué combinaciones de palabras contiguas dominan un corpus: colocaciones,
frases técnicas recurrentes ("machine learning", "data analyst"), o patrones de
trigramas en titulares/descripciones. Es el complemento natural de un perfil de
vocabulario: pasa de "qué palabras aparecen" a "qué secuencias aparecen". Llámala
con n=1 para unigramas, n=2 para bigramas y n=3 para trigramas, y ajusta
top_k al tamaño de la tabla que vas a renderizar. Deja remove_stopwords=True
para que los n-gramas reflejen contenido y no conectores gramaticales.
Gotchas
- Las stopwords se eliminan ANTES de formar los n-gramas. Con
remove_stopwords=Truela frase "data of analysis" produce el bigrama "data analysis" (el "of" intermedio desaparece y los tokens de contenido se vuelven contiguos), no "data of" ni "of analysis". Si quieres preservar la adyacencia literal del texto original, pasaremove_stopwords=False. - Los n-gramas NO cruzan documentos. Cada elemento de
textsse tokeniza y recorre por separado; el último token de un documento nunca se combina con el primero del siguiente. - Tokens puramente numéricos se descartan (
tok.isdigit()), pero los alfanuméricos mixtos no: "3d" o "covid19" sí cuentan como tokens. Un decimal como "3.5" se parte en "3" y "5" por\w+y ambos se descartan por numéricos. - La lista de stopwords es inline ES+EN, pensada para textos generales en
esos dos idiomas. Para otros idiomas o jerga específica de dominio puede dejar
pasar conectores; en ese caso filtra el corpus aguas arriba o usa
remove_stopwords=Falsey posfiltra. toppuede tener menos detop_kelementos si el corpus no tiene tantos n-gramas distintos. El desempate por frecuencia es alfabético (determinista), no por orden de aparición.