Exemple #1
0
    def __init__(self,
                 lenguaje,
                 diccionario=None,
                 distancia=2,
                 tokenizador=None):
        """
        Constructor por defecto de la clase Corrector. Esta clase se encarga \
        de realizar corrección ortográfica sobre textos.

        :param lenguaje: (str) Lenguaje de los textos a los que se les va a aplicar \ 
            corrección ortográfica. Para mayor información, consultar la sección de \ 
            :ref:`Lenguajes soportados <seccion_lenguajes_soportados>`.
        :param diccionario: (dict, list o string) Valor por defecto: None. Diccionario (o string con ubicación del \
            archivo JSON que lo contiene), o lista que permite modificar y agregar palabras. \
            Si es una lista, contiene las palabras que serán consideradas como válidas o correctas. \
            Si es un diccionario, las llaves del diccionario son las palabras que serán consideradas
            como válidas o correctas, y los valores del diccionario son las frecuencias de cada palabra \
            en el diccionario. Las frecuencias son utilizadas como criterio de desempate, cuando una \
            palabra incorrecta tiene más de una palabra candidata para la corrección. Si se deja este \
            parámetro como None, se cargará el diccionario por defecto que trae la librería `spellchecker` \
            para el lenguaje determinado.
        :param distancia: (int) Valor por defecto: 2. Máxima distancia de Levenshtein que puede haber \ 
            entre una palabra incorrecta (o no reconocida) y las palabras del diccionario para \
            determinar si hay palabras candidatas para realizar la corrección.
        :param tokenizador: Valor por defecto: None. Objeto encargado de la tokenización y detokenización de \
            textos. Si el valor es 'None', se cargará por defecto una instancia de la clase *TokenizadorNLTK*.
        """
        # Definir lenguaje del corrector ortográfico
        self.establecer_lenguaje(lenguaje)
        # Inicializar corrector
        self.iniciar_corrector(diccionario)
        self.establecer_distancia(distancia)
        self.tokenizador = TokenizadorNLTK(
        ) if tokenizador is None else tokenizador
Exemple #2
0
    def __init__(self, lenguaje="es", tokenizador=None):
        """
        Constructor por defecto de la clase `Stemmer`. Esta clase se encarga \
        de hacer la operación de *stemming*, o reducción de palabras a su \
        raíz, en textos.

        :param lenguaje: Lenguaje de los textos a los que se va a aplicar \
            *stemming*. Para mayor información, consultar la sección de \
            :ref:`Lenguajes soportados <seccion_lenguajes_soportados>`. \
            Valor por defecto `'es'`.
        :type lenguaje: {'es', 'en', 'fr', 'ge'}, opcional
        :param tokenizador: Objeto encargado de la tokenización y \
            detokenización de textos. Si el valor es 'None', se utilizará \
            por defecto una instancia de la clase `TokenizadorNLTK`.
        :type tokenizador: Tokenizer, opcional
        :return: (Stemmer) Objeto del tipo de la clase `Stemmer`.
        """
        # Definir lenguaje del stemmer
        self.establecer_lenguaje(lenguaje)
        # Inicializar stemmer
        self.iniciar_stemmer()
        # Para tokenizar los textos antes de aplicar el stemming
        self.tokenizador = (
            TokenizadorNLTK() if tokenizador is None else tokenizador
        )
Exemple #3
0
    def __init__(self, lenguaje, tokenizador=None):
        """
        Constructor por defecto de la clase Stemmer. Esta clase se encarga \
        de hacer la operación de *stemming*, o reducción de palabras a su \
        raíz, en textos.

        :param lenguaje: (str) Lenguaje de los textos a los que se va \ 
            a aplicar *stemming*. Para mayor información, consultar la sección de \ 
            :ref:`Lenguajes soportados <seccion_lenguajes_soportados>`.
        :param tokenizador: Valor por defecto: None. Objeto encargado de la tokenización y detokenización \
            de textos. Si el valor es 'None', se cargará por defecto una instancia de la clase *TokenizadorNLTK*.            
        :return: (Stemmer) Objeto del tipo de la clase Stemmer
        """
        # Definir lenguaje del stemmer
        self.establecer_lenguaje(lenguaje)
        # Inicializar stemmer
        self.iniciar_stemmer()
        # Para tokenizar los textos antes de aplicar el stemming
        self.tokenizador = TokenizadorNLTK(
        ) if tokenizador is None else tokenizador
Exemple #4
0
    def __init__(self,
                 lenguaje,
                 diccionario=None,
                 distancia=2,
                 tokenizador=None):
        """
        Constructor por defecto de la clase `Corrector`. Esta clase se \
        encarga de realizar corrección ortográfica sobre textos.

        :param lenguaje: Lenguaje de los textos a los que se les va a \
            aplicar corrección ortográfica. Para mayor información, consultar \
            la sección de \
            :ref:`Lenguajes soportados <seccion_lenguajes_soportados>`.
        :type lenguaje: str
        :param diccionario: Diccionario (o string con ubicación del archivo \
            JSON que lo contiene), o lista que permite modificar y agregar \
            palabras. Si es una lista, contiene las palabras que serán \
            consideradas como válidas o correctas. \
            Si es un diccionario, las llaves del diccionario son las palabras \
            que serán consideradas como válidas o correctas, y los valores \
            del diccionario son las frecuencias de cada palabra en el \
            diccionario. Las frecuencias son utilizadas como criterio de \
            desempate, cuando una palabra incorrecta tiene más de una palabra \
            candidata para la corrección. Si se deja este \
            parámetro como `None`, se cargará el diccionario por defecto que \
            trae la librería `spellchecker` para el lenguaje determinado.
        :type diccionario: dict, list, str, opcional
        :param distancia: Máxima distancia de \
            Levenshtein que puede haber entre una palabra incorrecta (o no \
            reconocida) y las palabras del diccionario para determinar si \
            hay palabras candidatas para realizar la corrección. \
            Valor por defecto `2`.
        :type distancia: int
        :param tokenizador: Objeto encargado de la tokenización y \
            detokenización de textos. Si el valor es `None`, se cargará por \
            defecto una instancia de la clase `TokenizadorNLTK`. Valor por \
            defecto `None`
        :type tokenizador: object, opcional
        """
        # Definir lenguaje del corrector ortográfico
        self.establecer_lenguaje(lenguaje)
        # Inicializar corrector
        self.iniciar_corrector(diccionario)
        self.establecer_distancia(distancia)
        self.tokenizador = (TokenizadorNLTK()
                            if tokenizador is None else tokenizador)
Exemple #5
0
class Corrector():
    def __init__(self,
                 lenguaje,
                 diccionario=None,
                 distancia=2,
                 tokenizador=None):
        """
        Constructor por defecto de la clase Corrector. Esta clase se encarga \
        de realizar corrección ortográfica sobre textos.

        :param lenguaje: (str) Lenguaje de los textos a los que se les va a aplicar \ 
            corrección ortográfica. Para mayor información, consultar la sección de \ 
            :ref:`Lenguajes soportados <seccion_lenguajes_soportados>`.
        :param diccionario: (dict, list o string) Valor por defecto: None. Diccionario (o string con ubicación del \
            archivo JSON que lo contiene), o lista que permite modificar y agregar palabras. \
            Si es una lista, contiene las palabras que serán consideradas como válidas o correctas. \
            Si es un diccionario, las llaves del diccionario son las palabras que serán consideradas
            como válidas o correctas, y los valores del diccionario son las frecuencias de cada palabra \
            en el diccionario. Las frecuencias son utilizadas como criterio de desempate, cuando una \
            palabra incorrecta tiene más de una palabra candidata para la corrección. Si se deja este \
            parámetro como None, se cargará el diccionario por defecto que trae la librería `spellchecker` \
            para el lenguaje determinado.
        :param distancia: (int) Valor por defecto: 2. Máxima distancia de Levenshtein que puede haber \ 
            entre una palabra incorrecta (o no reconocida) y las palabras del diccionario para \
            determinar si hay palabras candidatas para realizar la corrección.
        :param tokenizador: Valor por defecto: None. Objeto encargado de la tokenización y detokenización de \
            textos. Si el valor es 'None', se cargará por defecto una instancia de la clase *TokenizadorNLTK*.
        """
        # Definir lenguaje del corrector ortográfico
        self.establecer_lenguaje(lenguaje)
        # Inicializar corrector
        self.iniciar_corrector(diccionario)
        self.establecer_distancia(distancia)
        self.tokenizador = TokenizadorNLTK(
        ) if tokenizador is None else tokenizador

    def establecer_lenguaje(self, lenguaje):
        """
        Permite definir o cambiar el lenguaje de los textos sobre los cuales \
        va a aplicarse el objeto de la clase Corrector.
            
        :param lenguaje: (str) Lenguaje de los textos a los que se les va a aplicar \
            corrección ortográfica. Para mayor información, consultar la sección de \ 
            :ref:`Lenguajes soportados <seccion_lenguajes_soportados>`.
        """
        self.lenguaje = definir_lenguaje(lenguaje)

    def iniciar_corrector(self, diccionario):
        """
        Inicializa el objeto de la clase `SpellChecker` de la librería spellchecker, \
        para el lenguaje definido previamente, y lo asigna al atributo "corrector" del \
        objeto de clase Corrector.

        :param diccionario: (dict, list o string) Diccionario (o string con ubicación del \
            archivo JSON que lo contiene), o lista que permite modificar y agregar palabras. \
            Si es una lista, contiene las palabras que serán consideradas como válidas o correctas. \
            Si es un diccionario, las llaves del diccionario son las palabras que serán consideradas
            como válidas o correctas, y los valores del diccionario son las frecuencias de cada palabra \
            en el diccionario. Las frecuencias son utilizadas como criterio de desempate, cuando una \
            palabra incorrecta tiene más de una palabra candidata para la corrección.
        """
        self.corrector = None
        if self.lenguaje is not None:
            if isinstance(diccionario, str):
                self.corrector = SpellChecker(local_dictionary=diccionario)
            elif type(diccionario) in [dict, list]:
                self.corrector = SpellChecker(language=self.lenguaje)
                self.actualizar_diccionario(diccionario)
            else:
                self.corrector = SpellChecker(language=self.lenguaje)

    def establecer_distancia(self, distancia):
        """
        Establece la distancia máxima que utilizará el algoritmo de corrección de ortografía \
        para determinar si hay palabras candidatas para corregir una palabra incorrecta o \
        no reconocida.

        :param distancia: (int) Valor por defecto: 2. Máxima distancia de Levenshtein que puede haber 
            entre una palabra incorrecta (o no reconocida) y las palabras del diccionario para \
            determinar si hay palabras candidatas para realizar la corrección.
        """
        if self.corrector is not None:
            self.corrector.distance = distancia

    def actualizar_diccionario(self, diccionario):
        """
        Actualiza el diccionario que contiene las palabras válidas o reconocidas disponibles para \
        realizar la corrección ortográfica. Las palabras contenidas en el argumento *diccionario* \
        de esta función serán añadidas (o sus frecuencias serán actualizadas) en el diccionario \
        que ya existe en el objeto de la clase Corrector.

        :param diccionario: (dict, list o string) Diccionario (o string con ubicación del \
            archivo JSON que lo contiene), o lista que permite modificar y agregar palabras. \
            Si es una lista, contiene las palabras que serán consideradas como válidas o correctas. \
            Si es un diccionario, las llaves del diccionario son las palabras que serán consideradas
            como válidas o correctas, y los valores del diccionario son las frecuencias de cada palabra \
            en el diccionario. Las frecuencias son utilizadas como criterio de desempate, cuando una \
            palabra incorrecta tiene más de una palabra candidata para la corrección.
        """
        if isinstance(diccionario, str):
            diccionario = json.load(open(diccionario))
        if isinstance(diccionario, list):
            diccionario = [palabra.lower() for palabra in diccionario]
            self.corrector.word_frequency.load_words(diccionario)
        elif isinstance(diccionario, dict):
            self.quitar_palabras(list(diccionario.keys()))
            for key in diccionario.keys():
                self.corrector.word_frequency.load_words([key.lower()] *
                                                         diccionario[key])
        else:
            pass

    def quitar_palabras(self, palabras):
        """
        Quita del diccionario del corrector una o más palabras proporcionadas en el argumento \
        *palabras*, haciendo que estas ya no sean reconocidas como palabras válidas o \
        correctas al momento de hacer corrección ortográfica.

        :param palabras: (str o list) Palabra o lista de palabras que se desean quitar del \
            diccionario del objeto de la clase Corrector, para que no sean recnocidas como \
            correctas al momento de hacer la corrección ortográfica.
        """
        if isinstance(palabras, str):
            palabras = [palabras]
        # Quitar de la lista palabras que no estén en el diccionario
        palabras = [p for p in palabras if self.frecuencia_palabra(p) > 0]
        if len(palabras) > 0:
            self.corrector.word_frequency.remove_words(palabras)

    def agregar_palabras(self, palabras):
        """
        Añade al diccionario del corrector una o más palabras proporcionadas en el argumento \
        *palabras*, haciendo que estas sean reconocidas como palabras válidas o \
        correctas al momento de hacer corrección ortográfica.

        :param palabras: (str o list) Palabra o lista de palabras que se desean añadir al \
            diccionario del objeto de la clase Corrector, para que sean reconocidas como \
            correctas al momento de hacer la corrección ortográfica.
        """
        if isinstance(palabras, str):
            palabras = [palabras]
        self.actualizar_diccionario(palabras)

    def palabras_conocidas(self, texto):
        """
        A partir de un texto de entrada, devuelve un conjunto (objeto de clase *set* de \
        Python) con las palabras del texto que se reconocen por estar presentes en \
        el diccionario del corrector.

        :param texto: (str) Texto para el que se desean hayar las palabras conocidas.
        :return: (set) Conjunto de palabras conocidas presentes en el texto de entrada.
        """
        tokens = self.tokenizador.tokenizar(texto)
        return self.corrector.known(tokens)

    def palabras_desconocidas(self, texto):
        """
        A partir de un texto de entrada, devuelve un conjunto (objeto de clase *set* de \
        Python) con las palabras del texto que no están incluidas en \
        el diccionario del corrector y por lo tanto no se reconocen.

        :param texto: (str) Texto para el que se desean hallar las palabras desconocidas.
        :return: (set) Conjunto de palabras desconocidas presentes en el texto de entrada.
        """
        tokens = self.tokenizador.tokenizar(texto)
        return self.corrector.unknown(tokens)

    def palabras_candidatas(self, palabra):
        """
        Para una palabra de entrada, retorna un conjunto de palabras que podrían ser utilizadas \
        para corregirla. Si la palabra de entrada es correcta (está dentro del diccionario \
        del corrector) o no tienen ninguna palabra candidata con una distancia menor o igual \
        a la establecida en el parámetro *distancia* de la clase Corrector, la función \
        devolverá la misma palabra de entrada.

        :param palabra: (str) Palabra para la que se quieren conocer palabras candidatas \
            para su corrección ortográfica.
        :return: (set) Conjunto de palabras candidatas para corregir la palabra de entrada.
        """
        return self.corrector.candidates(palabra)

    def frecuencia_palabra(self, palabra):
        """
        Para una palabra de entrada, devuelve la frecuencia de la misma, de acuerdo al \
        diccionario del corrector. Si la palabra es desconocida (no se encuentra en \
        el diccionario), la frecuencia retornada será de cero.

        :param palabra: (str) Palabra para la cual se desea conocer la frecuencia de \
            aparición en el diccionario del corrector.
        :return: (int) Número mayor o igual a cero que indica la frecuencia de la palabra \
            consultada en el diccionario del corrector.
        """
        return self.corrector[palabra]

    def probabilidad_palabra(self, palabra):
        """
        Para una palabra de entrada, devuelve la probabilidad de aparición de la misma, \
        entendida como su frecuencia sobre la suma de las frecuencias de todas las palabras\
        disponibles, de acuerdo al diccionario del corrector. Si la palabra es desconocida \
        (no se encuentra en el diccionario), la probabilidad retornada será de cero.

        :param palabra: (str) Palabra para la cual se desea conocer la probabilidad \
            de aparición en el diccionario del corrector.
        :return: (float) Probabilidad, entre 0 y 1, de aparición de la palabra.
        """
        return self.corrector.word_probability(palabra)

    def correccion_ortografia(self, texto, limpieza=False):
        """
        Realiza corrección ortográfica sobre un texto de entrada, identificando las palabras \
        que no están en el diccionario del corrector y cambiándolas por su candidata más \
        frecuente o probable, siempre y cuando haya por lo menos una palabra candidata \
        que cumpla con la máxima distancia de Levenshtein permitida.

        :param texto: (str) Texto al cuál se desea aplicar corrección ortográfica.
        :param limpieza: (bool) {True, False} Valor por defecto: False. Argumento \
            opcional que define si se desea hacer una limpieza 
            básica (aplicando la función `limpieza_basica` del módulo `limpieza`) al \
            texto antes de aplicar la corrección ortográfica.
        :return: (str) Texto de entrada luego de la corrección ortográfica.
        """
        if limpieza:
            # Limpieza básica del texto para que no afecte la corrección
            texto = limpieza_basica(texto, quitar_numeros=False)
        lista_palabras = self.tokenizador.tokenizar(texto)
        desconocidas = self.corrector.unknown(lista_palabras)
        texto_corregido = [
            self.corrector.correction(p)
            if len(p) > 1 and p in desconocidas else p for p in lista_palabras
        ]
        return self.tokenizador.destokenizar(texto_corregido)
Exemple #6
0
def matriz_coocurrencias(
    texto,
    min_frec=1,
    max_num=200,
    modo="documento",
    ventana=3,
    tri_sup=True,
    limpiar=False,
    tokenizador=None,
):
    """
    Calcula la matriz de coocurrencias de un texto.

    :param texto: Corresponde al texto (o lista de textos/documentos) que \
        se desea analizar.
    :type texto: str, list
    :param min_frec: Frecuencia mínima de aparición de palabras, si la \
        frecuencia de una palabra es menor a `min_frec`, será excluida de la \
        matriz. Valor por defecto `1`.
    :type min_frec: int, opcional
    :param max_num: Número máximo de palabras que se incluyen en la matriz \
        (se eligen las más frecuentes). Valor por defecto `200`.
    :type max_num: int, opcional
    :param modo: Corresponde al modo de análisis, con `'documento'` se \
        calcula la coocurrencia de términos sin importar la distancia entre \
        estos,  con `'ventana'` se calcula la coocurrencia de términos \
        teniendo en cuenta una distancia máxima entre estos. \
        Valor por defecto `'documento'`.
    :type modo: {'documento', 'ventana'}, opcional
    :param ventana: Tamaño de la ventana (solo cuando `modo = 'ventana'`). \
        Número de palabras anteriores o posteriores a tener en cuenta con \
        respecto al término de análisis, equivalente a calcular la \
        coocurrencia con n-gramas, siendo  `n = ventana + 1`. \
        Valor por defecto `3`.
    :type ventana: int, opcional
    :param tri_sup: Si es `True` devuelve la versión diagonal superior de la \
        matriz de coocurrencias, si es `False` devuelve la matriz completa. \
        Valor por defecto `True`.
    :type tri_sup: bool, opcional
    :param limpiar: Define si se desea hacer una limpieza básica (aplicando \
        la función `limpieza_basica` del módulo `limpieza`) al texto, antes \
        de calcular las coocurrencias. Valor por defecto `False`.
    :type limpiar: bool, opcional
    :param tokenizador: Objeto encargado de la tokenización y detokenización \
        de textos. Si el valor es 'None', se utilizará por defecto una \
        instancia de la clase *TokenizadorNLTK*. Valor por defecto `None`.
    :type tokenizador: Tokenizador, opcional
    :return: (pandas.DataFrame) Matriz de coocurrencias de los textos de \
        entrada.
    """
    # Generar un solo texto con todos los documentos
    if isinstance(texto, Iterable) and not isinstance(texto, str):
        texto_entero = " ".join([str(i) for i in texto])
    else:
        texto_entero = str(texto)
        texto = [texto_entero]  # Convertir variable "texto" en un iterable

    if limpiar:
        texto = [limpieza_basica(t) for t in texto]
        texto_entero = " ".join([texto])
    # Se inicializa un solo tokenizador, para ahorrar un poco de tiempo
    tok = TokenizadorNLTK() if tokenizador is None else tokenizador
    # Generar lista de palabras en todos los textos juntos
    palabras = tokenizar(texto_entero, tok)
    # Dejar solo las palabras con mayor frecuencia y/o que cumplan una
    # frecuencia mínima
    cuenta = dict(Counter(palabras).most_common(max_num))
    cuenta_filt = {k: v for k, v in cuenta.items() if v >= min_frec}
    nombres = list(set(cuenta_filt.keys()))
    # Inicializar en ceros la matriz de coocurrencias
    mat_oc = pd.DataFrame(np.zeros([len(nombres), len(nombres)]),
                          columns=nombres,
                          index=nombres)
    if modo == "ventana":
        for t in texto:
            palabras_t = tokenizar(t, tok)
            # Ciclo a través de las palabras para obtener las coocurrencias:
            for i, p1 in enumerate(palabras_t):
                inicio = max(0, i - ventana)
                fin = min(len(palabras), i + ventana + 1)
                for j, p2 in enumerate(palabras_t[inicio:fin]):
                    if (p2 in nombres) and (p1 in nombres):
                        if p1 != p2:
                            mat_oc[p2][p1] += 1
                        else:
                            if (inicio + j) != i:
                                mat_oc[p2][p1] += 1
    elif modo == "documento":
        for t in texto:
            cuenta_t = dict(Counter(tokenizar(t, tok)))
            for p1 in nombres:
                for p2 in nombres:
                    if p1 != p2:
                        if p1 in cuenta_t and p2 in cuenta_t:
                            mat_oc[p2][p1] += cuenta_t[p1] * cuenta_t[p2]
                    else:
                        if p1 in cuenta_t:
                            mat_oc[p2][p1] += cuenta_t[p1]

    # Ordenar filas y columnas alfabeticamente
    mat_oc.sort_index(inplace=True)
    mat_oc = mat_oc.reindex(sorted(mat_oc.columns), axis=1)
    if tri_sup:
        mat_oc = diag_superior(mat_oc)

    return mat_oc
Exemple #7
0
class Stemmer():
    def __init__(self, lenguaje, tokenizador=None):
        """
        Constructor por defecto de la clase Stemmer. Esta clase se encarga \
        de hacer la operación de *stemming*, o reducción de palabras a su \
        raíz, en textos.

        :param lenguaje: (str) Lenguaje de los textos a los que se va \ 
            a aplicar *stemming*. Para mayor información, consultar la sección de \ 
            :ref:`Lenguajes soportados <seccion_lenguajes_soportados>`.
        :param tokenizador: Valor por defecto: None. Objeto encargado de la tokenización y detokenización \
            de textos. Si el valor es 'None', se cargará por defecto una instancia de la clase *TokenizadorNLTK*.            
        :return: (Stemmer) Objeto del tipo de la clase Stemmer
        """
        # Definir lenguaje del stemmer
        self.establecer_lenguaje(lenguaje)
        # Inicializar stemmer
        self.iniciar_stemmer()
        # Para tokenizar los textos antes de aplicar el stemming
        self.tokenizador = TokenizadorNLTK(
        ) if tokenizador is None else tokenizador

    def establecer_lenguaje(self, lenguaje):
        """
        Permite definir o cambiar el lenguaje de los textos sobre los cuales \
        va a aplicarse el objeto de la case Stemmer.

        :param lenguaje: (str) Lenguaje de los textos a los que se va \ 
            a aplicar stemming. Para mayor información, consultar la sección de \ 
            :ref:`Lenguajes soportados <seccion_lenguajes_soportados>`.
        """
        self.lenguaje = definir_lenguaje(lenguaje, simplificado=False)

    def iniciar_stemmer(self):
        """
        Inicializa el objeto de la clase `SnowballStemmer` de la librería NLTk, \
        para el lenguaje definido previamente, y lo asigna al atributo "stemmer" \
        del objeto de clase Stemmer. 
        """
        if self.lenguaje is not None:
            self.stemmer = nltk.stem.SnowballStemmer(self.lenguaje)
        else:
            self.stemmer = None

    def stemming(self, texto, limpiar=False):
        """
        Aplica *stemming* sobre un texto de entrada, y devuelve el texto \
        resultante.

        :param texto: (str) Texto al que se desea aplicar el *stemming*. 
        :param limpiar: (bool) {True, False} Valor por defecto: False. Argumento \
            opcional que define si se desea hacer una limpieza básica (\
            aplicando la función `limpieza_basica` del módulo `limpieza`) al \
            texto antes de aplicar el *stemming*.
        :return: (str) Texto luego de la aplicación del *stemming*.
        """
        if limpiar:
            texto = limpieza_basica(texto)
        tokens = self.tokenizador.tokenizar(texto)
        salida = [self.stemmer.stem(p) for p in tokens]
        return self.tokenizador.destokenizar(salida)
Exemple #8
0
def matriz_coocurrencias(texto,
                         min_frec=1,
                         max_num=200,
                         modo='documento',
                         ventana=3,
                         tri_sup=True,
                         limpiar=False,
                         tokenizador=None):
    """ Calcula la matriz de coocurrencias de un texto.

    :param texto: (str o list) Corresponde al texto (o lista de textos/documentos) que se desea analizar.
    :param min_frec: (int) Valor por defecto: 1. Frecuencia mínima de aparición de palabras, si la frecuencia de una palabra es menor a min_frec, dicha palabra es excluida de la matriz.
    :param max_num: (int) Valor por defecto: 200. Número máximo de palabras a dejar en la matriz (se eligen las más frecuentes).
    :param modo: (str) {'documento', 'ventana'} Valor por defecto: 'documento'. Corresponde al modo de análisis, con 'documento' se calcula la co-ocurrencia de términos sin importar la distancia entre estos,  con 'ventana' se calcula la co-ocurrencia de términos teniendo en cuenta una distancia máxima entre estos.
    :param ventana: (int) Valor por defecto: 3. Tamaño de la ventana (solo se usa cuando modo='ventana'). Número de palabras anteriores o posteriores a tener en cuenta con respecto al término de análisis, equivalente a calcular la co-ocurrencia con n-gramas, siendo n=ventana+1.
    :param tri_sup: (bool) {True, False} Valor por defecto: True. Si el valor es True devuelve la versión diagonal superior de la matriz de coocurrencias, si es False devuelve la matriz completa.
    :param limpiar: (bool) {True, False} Valor por defecto: False. Define \
        si se desea hacer una limpieza básica (aplicando la función `limpieza_basica` \
        del módulo `limpieza`) al texto de entrada, antes de calcular las coocurrencias.
    :param tokenizador: Valor por defecto: None. Objeto encargado de la tokenización y detokenización \
        de textos. Si el valor es 'None', se utilizará por defecto una instancia de la clase *TokenizadorNLTK*.        
    :return: (dataframe) Coocurrencias de los textos de entrada.
    """
    # Generar un solo texto con todos los documentos
    if isinstance(texto, Iterable) and not isinstance(texto, str):
        texto_entero = ' '.join([str(i) for i in texto])
    else:
        texto_entero = str(texto)
        texto = [texto_entero]  # Convertir variable "texto" en un iterable

    if limpiar:
        texto = [limpieza_basica(t) for t in texto]
        texto_entero = ' '.join([texto])
    # Se inicializa un solo tokenizador, para ahorrar un poco de tiempo
    tok = TokenizadorNLTK() if tokenizador is None else tokenizador
    # Generar lista de palabras en todos los textos juntos
    palabras = tokenizar(texto_entero, tok)
    # Dejar solo las palabras con mayor frecuencia y/o que cumplan una
    # frecuencia mínima
    cuenta = dict(Counter(palabras).most_common(max_num))
    cuenta_filt = {k: v for k, v in cuenta.items() if v >= min_frec}
    nombres = list(set(cuenta_filt.keys()))
    # Inicializar en ceros la matriz de coocurrencias
    mat_oc = pd.DataFrame(np.zeros([len(nombres), len(nombres)]),
                          columns=nombres,
                          index=nombres)
    if modo == 'ventana':
        for t in texto:
            palabras_t = tokenizar(t, tok)
            # Ciclo a través de las palabras para obtener las coocurrencias:
            for i, p1 in enumerate(palabras_t):
                inicio = max(0, i - ventana)
                fin = min(len(palabras), i + ventana + 1)
                for j, p2 in enumerate(palabras_t[inicio:fin]):
                    if (p2 in nombres) and (p1 in nombres):
                        if p1 != p2:
                            mat_oc[p2][p1] += 1
                        else:
                            if (inicio + j) != i:
                                mat_oc[p2][p1] += 1
    elif modo == 'documento':
        for t in texto:
            cuenta_t = dict(Counter(tokenizar(t, tok)))
            for p1 in nombres:
                for p2 in nombres:
                    if p1 != p2:
                        if p1 in cuenta_t and p2 in cuenta_t:
                            mat_oc[p2][p1] += cuenta_t[p1] * cuenta_t[p2]
                    else:
                        if p1 in cuenta_t:
                            mat_oc[p2][p1] += cuenta_t[p1]

    # Ordenar filas y columnas alfabeticamente
    mat_oc.sort_index(inplace=True)
    mat_oc = mat_oc.reindex(sorted(mat_oc.columns), axis=1)
    if tri_sup:
        mat_oc = diag_superior(mat_oc)

    return mat_oc