César Antonio Aguilar
Facultad de Letras
04/11/2015
Curso de procesamiento del
lenguaje natural
2
Solución de la Tarea I (1)
Como quedamos en la clase pasada, vamos a revisar la tarea pasada, en
donde realizamos un análisis de dos corpus diferentes de medicina. Así,
empecemos con lo básico: cargar nuestro corpus, y convertirlo en una
lista de palabras. Veamos:
Comprobamos:
type(corpus_medicina01)
len(corpus_medicina01)
Importando archivo:
corpus_medicina01 =
open(‘C://Anaconda3/Corpus_Pruebas/corpus_medicina_grupo
_a_01.txt’, encoding=‘utf-8’).read()
3
Solución de la Tarea I (2)
¿Por qué dimos una instrucción diferente esta vez? Básicamente, porque
el primer corpus tiene un problema de codificación, ya que viene en un
formato distinto a UTF-8. Por ello, fue necesario emplear la función
encoding. Aplicándola, ¿qué resultado obtenemos?:
4
Solución de la Tarea I (3)
Una vez fijada nuestra cadena de caracteres, ahora vamos a generar una
lista de tokens:
Comprobamos:
tokens_medicina01 = nltk.word_tokenize(corpus_medicina01)
type(tokens_medicina01)
len(tokens_medicina01)
5
Solución de la Tarea I (4)
Tras crear nuestra lista de tokens, podemos generar una colección de
textos con la siguiente instrucción:
text_medicine01 = nltk.Text(tokens_medicina01)
Comprobamos:
type(text_medicina01)
len(text_medicina01)
6
Solución de la Tarea I (5)
La siguiente fase de la tarea consistía en hacer una búsqueda de
concordancias, considerando 5 términos: analysis, disease, disorder, test
y treatment. Veamos el primer caso:
7
Solución de la Tarea I (6)
Ahora revisemos qué palabras se vinculan a analysis en un contexto
similar:
8
Solución de la Tarea I (6)
Finalmente, creamos un gráfico de dispersión con los 5 términos
considerados:
9
Solución de la Tarea I (7)
Completado el siguiente gráfico, pasamos a la siguiente parte, que era
crear un corpus etiquetado. La instrucción para hacerlo es:
tags_medicina01 = nltk.pos_tag(tokens_medicina01)
Comprobamos:
type(tags_medicina01)
len(tags_medicina01)
tags_medicina01[0:200]
10
Implementando un chunker (1)
Una vez hecho esto, podemos analizar la siguiente oración, la cual cuenta
con etiquetas morfosintácticas:
import nltk, re, os
Lo que hemos visto con la tarea nos sirve muy bien para empezar a usar
chunkers que nos ayuden a reconocer patrones sintácticos. Veamos un
ejemplo, importando primero las siguientes librerías:
sentence01 = [("the", "DT"), ("little", "JJ"), ("yellow",
"JJ"), ("dog", "NN"), ("barked", "VBD"), ("at", "IN"),
("the", "DT"), ("cat", "NN")]
11
Implementando un chunker (2)
¿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.
grammar01 = "NP: {<DT>?<JJ>*<NN>}”
cp = nltk.RegexpParser(grammar01)
result01 = cp.parse(sentence01)
print (result01)
result01.draw()
Ahora, escribamos el siguiente código:
13
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:
Implementando un chunker (4)
14
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()
sentence02 = [("Rapunzel", "NNP"), ("let", "VBD"), ("down", "RP"),
("her", "PP$"), ("long", "JJ"), ("golden", "JJ"), ("hair", "NN")]
Y el resultado es:
Nuestra gramática va a ser la siguiente:
Implementando un chunker (5)
16
Implementando un chunker (7)
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
17
Implementando un chunker (8)
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)
18
Implementando un chunker (9)
Y el resultado final, si
confiamos en nuestro
proceso, son frases
verbales que dentro del
Brown sigan el patrón
Verbo + TO + Verbo :
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
El resultado es:
print(conll2000.chunked_sents('train.txt')[99])
Veamos un fragmento del CoNLL 2000, usando esta
instrucción:
Métodos de evaluación (2)
El resultado lo vemos en la siguiente lámina:
cp = nltk.RegexpParser("")
test_sents = conll2000.chunked_sents('test.txt',
chunk_types=['NP'])
print (cp.evaluate(test_sents))
Una vez que hemos visto parte del contenido del CoNLL 2000,
implementemos el siguiente ciclo:
Métodos de evaluación (3)
Pregunta: ¿por qué nos da como resultado cero? ¿Qué es lo
que estamos buscando en este corpus?
Métodos de evaluación (4)
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:
grammar = r"NP: {<[CDJNP].*>+}"
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:
Métodos de evaluación (5)
grammar = r"NP: {<[CDJNP].*>+}"
test_sents = conll2000.chunked_sents('test.txt’,
chunk_types=['NP’])
cp = nltk.RegexpParser(grammar)
print (cp.evaluate(test_sents))
Nuestro código es:
Métodos de evaluación (6)
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.
Métodos de evaluación (7)
Blog del curso:
http://cesaraguilar.weebly.com/curso-de-
procesamiento-del-lenguaje-natural.html
Gracias por su atención