láminas para la clase de hoy
Transcripción
láminas para la clase de hoy
Curso de procesamiento del lenguaje natural César Antonio Aguilar Facultad de Letras 19/10/2016 [email protected] Análisis de frases con NLTK (1) Como hemos señalado en clases anteriores, el análisis sintáctico de un texto es una tarea que podemos emprender usando y combinando criterios lingüísticos y estadísticos, creando así métodos híbridos eficaces. 2 Análisis de frases con NLTK (2) Ahora, como hemos señalado también antes, existen dos tipos de objetos sintácticos que podemos analizar: frases y oraciones. Los métodos y técnicas que se ocupan para hacer análisis de frase se les agrupa usualmente con el término chunking (literalmente, trozado o partición de oraciones en frases): 3 Análisis de frases con NLTK (3) La partición de una oración en frases es parte de un criterio jerárquico sencillo de deducir: lo que queremos identificar son combinaciones de palabras que, gramaticalmente, cumplan un rol como núcleo de una frase, o como modificador ligado a dicho núcleo. Los mejores candidatos son las frases nominales (NPs): 4 Implementando un chunker (1) Veamos ahora cómo podemos programar un analizador de frases con NLTK, importando las siguientes librerías: import nltk, re, os Una vez hecho esto, podemos analizar la siguiente oración, la cual cuenta con etiquetas morfosintácticas: sentence01 = [("the", "DT"), ("little", "JJ"), ("yellow", "JJ"), ("dog", "NN"), ("barked", "VBD"), ("at", "IN"), ("the", "DT"), ("cat", "NN")] 5 Implementando un chunker (2) Ahora, escribamos el siguiente código: grammar01 = "NP: {<DT>?<JJ>*<NN>}” cp = nltk.RegexpParser(grammar01) result01 = cp.parse(sentence01) print (result01) result01.draw() ¿Qué obtenemos con esto?: 1. Una estructura arbórea, en donde se indica con paréntesis cuáles son las frases que cumplen con el patrón que establecimos en nuestra gramática. 2. El gráfico de un árbol sintáctico, el cual representa la estructura sintáctica de nuestra oración. 6 Implementando un chunker (3) El resultado es: 7 Implementando un chunker (4) Si observan, nuestra gramática es una secuencia de etiquetas con expresiones regulares, las cuales simplemente indican aquí: 1. Busca toda secuencia que inicie con un determinante (o DT), más cualquier otra palabra subsecuente. 2. A esta cadena se debe ligar un adjetivo (o JJ), el cual puede tener una recurrencia de 0 a infinito. 3. Finalmente, a esta secuencia se liga un nombre común (o NN). Las reglas y patrones que podamos construir con nuestras gramáticas pueden ser tan simples o complejos como lo creamos conveniente. Veamos el siguiente ejemplo: 8 Implementando un chunker (5) sentence02 = [("Rapunzel", "NNP"), ("let", "VBD"), ("down", "RP"), ("her", "PP$"), ("long", "JJ"), ("golden", "JJ"), ("hair", "NN")] Nuestra gramática va a ser la siguiente: grammar02 = r””” NP: {<DT|PP\$>?<JJ>*<NN>} # Frases que tengan determinante/posesivo, adjetivo y nombre {<NNP>+} # Frases con nombres propios ””” cp = nltk.RegexpParser(grammar02) result02 = cp.parse(sentence02) print (result02) result02.draw() Y el resultado es: 9 Implementando un chunker (6) 10 Implementando un chunker (7) Las frases anteriores, claro está, son ejemplos simples. ¿Qué pasa con secuencias más complejas? Veamos: Text01 = ''' he PRP B-NP accepted VBD B-VP the DT B-NP position NN I-NP of IN B-PP vice NN B-NP chairman NN I-NP of IN B-PP Carlyle NNP B-NP Group NNP I-NP ,,O a DT B-NP merchant NN I-NP banking NN I-NP concern NN I-NP ..O ''' 11 Implementando un chunker (8) Apliquen ahora la siguiente instrucción: nltk.chunk.conllstr2tree(Text01, chunk_types=['NP']).draw() Y el resultado es: 12 Implementando un chunker (9) Como lo hemos comentado antes, NLTK cuenta con una serie de corpus etiquetados que podemos aprovechar para hacer varias tareas. Una de ellas es justo la detección de frases empleando estas técnicas de chunking. Por ejemplo, tratemos de identificar frases que sigan la secuencia Verbo + TO + Verbo en el Brown Corpus. Para ello, requerimos de una gramática, así como importar el Brown Corpus a nuestro intérprete: cp = nltk.RegexpParser(‘CHUNK: {<V.*> <TO> <V.*>}’) brown = nltk.corpus.brown 13 Implementando un chunker (10) Ahora, lo que vamos a hacer es elaborar un ciclo, el cual nos permita reconocer cuáles son las oraciones que, dentro del Brown, cumplan con nuestra regla. Una vez que las detectemos, las agruparemos en un listado que se desplegará en pantalla. Veamos: for sent in brown.tagged_sents(): tree = cp.parse(sent) for subtree in tree.subtrees(): if subtree.label() == 'CHUNK': print (subtree) 14 Implementando un chunker (11) Y el resultado final, si confiamos en nuestro proceso, son frases verbales que dentro del Brown sigan el patrón Verbo + TO + Verbo : 15 Métodos de evaluación (1) Tras haber hecho una exploración en el Corpus Brown, ahora pasamos a implementar un método de evaluación estadístico, con el fin de evaluar si nuestras gramáticas son eficaces o no para localizar los patrones que buscamos. Para esta tarea, vamos a ocupar un corpus etiquetado llamado CoNLL 2000, el cual está seccionado en frases. Así, requerimos de esta instrucción: from nltk.corpus import conll2000 Métodos de evaluación (2) Veamos un fragmento del CoNLL 2000, usando esta instrucción: print(conll2000.chunked_sents('train.txt')[99]) El resultado es: Métodos de evaluación (3) Una vez que hemos visto parte del contenido del CoNLL 2000, implementemos el siguiente ciclo: cp = nltk.RegexpParser("") test_sents = conll2000.chunked_sents('test.txt', chunk_types=['NP']) print (cp.evaluate(test_sents)) El resultado lo vemos en la siguiente lámina: Métodos de evaluación (4) Pregunta: ¿por qué nos da como resultado cero? ¿Qué es lo que estamos buscando en este corpus? Métodos de evaluación (5) La razón por la cual no nos presenta ningún resultado es porque no hemos definido una gramática. Probemos con la siguiente regla: grammar = r"NP: {<[CDJNP].*>+}" La regla que acabos de escribir nos permite localizar frases nominales que estén conformadas por un número cardinal (CD), un determinante (DT), un adjetivo (JJ) y nombre (NN). Ahora, unamos esta gramática con nuestro código anterior, y obtenemos: Métodos de evaluación (6) Nuestro código es: grammar = r"NP: {<[CDJNP].*>+}" test_sents = conll2000.chunked_sents('test.txt’, chunk_types=['NP’]) cp = nltk.RegexpParser(grammar) print (cp.evaluate(test_sents)) Métodos de evaluación (7) Las medidas que hemos generado indican lo siguiente: 1. El índice IOB indica el total de palabras que fueron excluidas de nuestra gramática, porque no forman parte de la estructura de una frase nominal. 2. El índice de Precision nos muestra el total de patrones que mejor encuadran con nuestra regla sobre constitución de una FN. 3. El índice de Recall indica el total de candidatos a FN que hay en nuestro corpus. 4. El índice F-Measure establece un ajuste entre Precision y Recall. NLTK para el español: esto es lo que hay (1) Siendo demasiado francos, si bien NLTK cuenta con un corpus en español, las colecciones de árboles sintácticos llamadas CESS Treebanks (que son derivados del proyecto Freeling), en español y catalán, estos recursos no permiten todavía desarrollar un proceso de etiquetado de nuevos documentos, como pasa con el corpus Brown. Las razones son varias: 1. Los corpus CESS están diseñados para mostrar resultados respecto a las consultas que hagamos en ellos, pero no permiten implementar algún proceso de aprendizaje para un etiquetador en español. 2. Todavía no se ha desarrollado algún método en NLTK para entrenar un etiquetador en español. 3. No hay un corpus etiquetado de referencia en español, el cual sea de libre uso, y pueda formar parte de las librerías de NLTK. 4. No hay criterios unificados sobre el proceso de etiquetado de palabras en español. NLTK para el español: esto es lo que hay (2) Si probamos la demo que ofrece Freeling en línea, podemos ver que se cuentan con algunos recursos para el etiquetado de oraciones, p.e.: Incluso podemos graficar árboles sintácticos con cierto grado de complejidad, digamos un parseo basado en gramática de dependencias. Veamos la siguiente lámina: NLTK para el español: esto es lo que hay (3) NLTK para el español: esto es lo que hay (4) Esto último sí podemos hacerlo desde NLTK: lanzar consultas al corpus CESS en español, mostrar sus resultados, e incluso generar árboles sintácticos con las oraciones que hay en tal corpus. Así, si ocupan la instrucción: from nltk.corpus import cess_esp nltk.corpus.cess_esp.words() Nos muestra el ejemplo de una oración: ['El', 'grupo', 'estatal', 'Electricit\xe9_de_France', ...] NLTK para el español: esto es lo que hay (5) Las etiquetas que ocupa este corpus son una variante del sistema de anotación EAGLES,el cual ustedes ya conocen. Si escriben: nltk.corpus.cess_esp.tagged_words() Nos arroja como resultado: [('El', 'da0ms0'), ('grupo', 'ncms000'), ...] Finalmente, podemos generar un esquema arbóreo, seleccionado alguna de las oraciones que cuenta este corpus. Usemos esta instrucción, y veamos el resultado en la siguiente lámina: Tree01 = nltk.corpus.cess_esp.parsed_sents()[1].draw() NLTK para el español: esto es lo que hay (6) A manera de comentario final: hay muchas cosas por hacer todavía respecto al uso de NLTK para el procesamiento de corpus, pero lo importante es que hay soluciones. ¿Qué posibles vías creen que puedan ser útiles para aprovechar estos recursos para el análisis de textos en español? Gracias por su atención Blog del curso: http://cesaraguilar.weebly.com/curso-deprocesamiento-del-lenguaje-natural.html
Documentos relacionados
Diapositiva 1 - Inicio
En esta clase, vamos a tratar de hacer algunos ejercicios mínimos
con algunas herramientas disponibles para análisis de corpus
lingüísticos, en concreto las suites de herramientas Jaguar (IULAUPF),...