--- id: compute_top_ngrams_py_datascience name: compute_top_ngrams kind: function lang: py domain: datascience version: "1.0.0" purity: pure signature: "def compute_top_ngrams(texts, n=2, top_k=15, remove_stopwords=True) -> dict" description: "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." tags: [eda, datascience, text, nlp, ngrams, bigrams, trigrams, pure, python] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "" imports: [re, collections] example: | 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}, ...]} tested: true tests: - "test_bigramas" - "test_trigramas" - "test_vacio" - "test_stopwords" test_file_path: "python/functions/datascience/compute_top_ngrams_test.py" file_path: "python/functions/datascience/compute_top_ngrams.py" params: - name: texts desc: "Lista (o tupla) de cadenas. Los elementos None o que no sean str se descartan silenciosamente. Cada documento se tokeniza por separado; los n-gramas no cruzan la frontera entre documentos." - name: n desc: "Tamaño del n-grama: 1 unigramas, 2 bigramas, 3 trigramas, etc. Valores < 1 o no enteros producen top vacío (se conserva tal cual en la clave 'n' del retorno)." - name: top_k desc: "Número máximo de n-gramas a devolver, ordenados por frecuencia descendente con desempate alfabético determinista. Default 15. Valores negativos se tratan como 0." - name: remove_stopwords desc: "Si True (default) elimina las stopwords ES+EN de una lista inline (~130 términos de altísima frecuencia) ANTES de formar los n-gramas, de modo que los n-gramas se construyen sobre la secuencia de tokens de contenido." output: "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 ```python 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=True` la 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, pasa `remove_stopwords=False`. - **Los n-gramas NO cruzan documentos.** Cada elemento de `texts` se 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=False` y posfiltra. - **`top` puede tener menos de `top_k` elementos** si el corpus no tiene tantos n-gramas distintos. El desempate por frecuencia es alfabético (determinista), no por orden de aparición.