PoS tagging en Español

En este ejercicio vamos a jugar con uno de los corpus en español que está disponible desde NLTK: CESS_ESP, un treebank anotado a partir de una colección de noticias en español.

Este corpus está actualmente incluído en un recurso más amplio, el corpus AnCora que desarrollan en la Universitat de Barcelona. Para más información, podéis leer el artículo de M. Taulé, M. A. Martí y M. Recasens "AnCora: Multilevel Annotated Corpora for Catalan and Spanish". Proceedings of 6th International Conference on Language Resources and Evaluation (LREC 2008). 2008. Marrakesh (Morocco).

Antes de nada, ejecuta la siguiente celda para acceder al corpus y a otras herramientas que vamos a usar en este ejercicio.


In [1]:
import nltk
from nltk.corpus import cess_esp

cess_esp = cess_esp.tagged_sents()

print(cess_esp[5])


[('EDF', 'np00000'), ('tiene', 'vmip3s0'), ('previsto', 'aq0msp'), ('invertir', 'vmn0000'), ('194', 'Z'), ('millones', 'ncmp000'), ('de', 'sps00'), ('euros', 'Zm'), ('-Fpa-', 'Fpa'), ('186', 'Z'), ('millones', 'ncmp000'), ('de', 'sps00'), ('dólares', 'Zm'), ('-Fpt-', 'Fpt'), ('en', 'sps00'), ('la', 'da0fs0'), ('central', 'ncfs000'), ('de', 'sps00'), ('Río_Bravo', 'np00000'), (',', 'Fc'), ('con', 'sps00'), ('una', 'di0fs0'), ('potencia', 'ncfs000'), ('de', 'sps00'), ('495', 'Z'), ('megavatios', 'ncmp000'), (',', 'Fc'), ('y', 'cc'), ('134', 'Z'), ('millones', 'ncmp000'), ('de', 'sps00'), ('euros', 'Zm'), ('-Fpa-', 'Fpa'), ('28', 'Z'), ('millones', 'ncmp000'), ('de', 'sps00'), ('dólares', 'Zm'), ('-Fpt-', 'Fpt'), ('en', 'sps00'), ('Saltillo', 'np00000'), (',', 'Fc'), ('que', 'pr0cn000'), ('como', 'cs'), ('la', 'da0fs0'), ('primera', 'ao0fs0'), ('funcionará', 'vmif3s0'), ('con', 'sps00'), ('gas', 'ncms000'), ('natural', 'aq0cs0'), ('y', 'cc'), ('cuya', 'pr0fs000'), ('potencia', 'ncfs000'), ('prevista', 'aq0fsp'), ('es', 'vsip3s0'), ('de', 'sps00'), ('247', 'Z'), ('megavatios', 'ncmp000'), ('.', 'Fp')]

Fíjate que las etiquetas que se usan en el treebank español son diferentes a las etiquetas que habíamos visto en inglés. Para empezar, el español es una lengua con una morfología más rica: si queremos reflejar el género y el número de los adjetivos, por ejemplo, no nos vale con etiquetar los adjetivos con una simple JJ.

Echa un vistazo a las etiquetas morfológicas y trata de interpretar su significado. En estas primeras 50 palabras encontramos:

  • da0ms0: determinante artículo masculino singular
  • ncms000: nombre común masculino singular
  • aq0cs0: adjetivo calificativo de género común singular
  • np00000: nombre propio
  • sps00: preposición
  • vmis3s0: verbo principal indicativo pasado 3ª persona del singular

Aquí tienes el la explicación de las etiquetas y el catálogo completo de rasgos para el etiquetado en español usadas en este corpus. A partir de lo que aprendas en el enlace anterior:

  • Imprime por pantalla solo las palabras etiquetadas como formas verbales en 3ª persona del plural del pretérito perfecto simple de indicativo.
  • Calcula qué porcentaje del total representan las palabras del corpus CEES_ESP etiquetadas como formas verbales en 3ª persona del plural del pretérito perfecto simple de indicativo.

In [2]:
# escribe tu código aquí 
# la etiqueta de 3 pers plur del pret. perf simpl es: vmis3p0

verbos_en_pasado = []
total = 0

for oracion in cess_esp:
    total += len(oracion)
    for item in oracion:
        if item[1] == 'vmis3p0':
            verbos_en_pasado.append(item[0])
        
print('Tengo', len(verbos_en_pasado), 'verbos en pasado y', total, 'palabras en total') 
print('El porcentaje de verbos es', len(verbos_en_pasado)/total)


Tengo 629 verbos en pasado y 192685 palabras en total
El porcentaje de verbos es 0.0032643952565067336

Las etiquetas morfológicas que hemos visto son bastante complejas, ya que incorporan los rasgos de la flexión del español. Afortunadamente, NLTK permite cargar los corpus etiquetados con un conjunto de etiquetas universal y simplificado (todos los detalles en el paper) utilizando la opcion tagset='universal'. Para ello, asegúrate de que has almacenado dentro de tu directorio de recursos de nltk el mapeo de etiquetas originales del corpus con su versión simplificada. Este fichero se llama universal_tagset-ES.map y lo tienes en la carpeta data del respositorio. Es recomendable renombrarlo, por ejemplo:


In [3]:
!cp ../data/universal_tagset-ES.map ~/nltk_data/taggers/universal_tagset/es-ancora.map

Después, ejecuta la siguiente celda y fíjate cómo hemos cargado una lista de oraciones etiquetadas con esta nueva versión de las etiquetas.


In [4]:
from nltk.corpus import cess_esp

cess_esp._tagset = 'es-ancora'
oraciones = cess_esp.tagged_sents(tagset='universal')
print(oraciones[0])


[('El', 'DET'), ('grupo', 'NOUN'), ('estatal', 'ADJ'), ('Electricité_de_France', 'NOUN'), ('-Fpa-', '.'), ('EDF', 'NOUN'), ('-Fpt-', '.'), ('anunció', 'VERB'), ('hoy', 'ADV'), (',', '.'), ('jueves', 'X'), (',', '.'), ('la', 'DET'), ('compra', 'NOUN'), ('del', 'ADP'), ('51_por_ciento', 'NUM'), ('de', 'ADP'), ('la', 'DET'), ('empresa', 'NOUN'), ('mexicana', 'ADJ'), ('Electricidad_Águila_de_Altamira', 'NOUN'), ('-Fpa-', '.'), ('EAA', 'NOUN'), ('-Fpt-', '.'), (',', '.'), ('creada', 'ADJ'), ('por', 'ADP'), ('el', 'DET'), ('japonés', 'ADJ'), ('Mitsubishi_Corporation', 'NOUN'), ('para', 'ADP'), ('poner_en_marcha', 'VERB'), ('una', 'DET'), ('central', 'NOUN'), ('de', 'ADP'), ('gas', 'NOUN'), ('de', 'ADP'), ('495', 'X'), ('megavatios', 'NOUN'), ('.', '.')]

Estas etiquetas son más sencillas, ¿verdad? Básicamente tenemos DET para determinante, NOUN para nombre, VERB para verbo, ADJ para adjetivo, ADP para preposición, etc.

Vamos a utilizar este corpus para entrenar varios etiquetadores basados en ngramas, tal y como hicimos en clase y se explica en la presentación nltk-pos.

Construye de manera incremental cuatro etiquetadores.

  1. un etiquetador que por defecto que asuma que una palabra desconocida es un nombre común en masculino singular y asigne la etiqueta correspondiente a todas las palabras.
  2. un etiquetador basado en unigramas que aprenda a partir de la lista oraciones y utilice en etiquetador anterior como respaldo.
  3. un etiquetador basado en bigramas que aprenda a partir de la lista oraciones y utilice en etiquetador anterior como respaldo.
  4. un etiquetador basado en trigramas que aprenda a partir de la lista oraciones y utilice en etiquetador anterior como respaldo.

In [5]:
# escribe tu código aquí
defaultTagger = nltk.DefaultTagger('NOUN')
unigramTagger = nltk.UnigramTagger(oraciones, backoff=defaultTagger)
bigramTagger = nltk.BigramTagger(oraciones, backoff=unigramTagger)
trigramTagger = nltk.TrigramTagger(oraciones, backoff=bigramTagger)

In [6]:
# prueba tu etiquetador basado en trigramas con las siguientes oraciones que, 
# con toda seguridad, no aparecen en el corpus
print(trigramTagger.tag("Este banco está ocupado por un padre y por un hijo. El padre se llama Juan y el hijo ya te lo he dicho".split()))
print(trigramTagger.tag("""El presidente del gobierno por fin ha dado la cara para anunciar aumentos de presupuesto en Educación y Sanidad a costa de dejar de subvencionar las empresas de los amigotes.""".split()))
print(trigramTagger.tag("El cacique corrupto y la tonadillera se comerán el turrón en prisión.".split()))


[('Este', 'DET'), ('banco', 'NOUN'), ('está', 'VERB'), ('ocupado', 'VERB'), ('por', 'ADP'), ('un', 'DET'), ('padre', 'NOUN'), ('y', 'CONJ'), ('por', 'ADP'), ('un', 'DET'), ('hijo.', 'NOUN'), ('El', 'DET'), ('padre', 'NOUN'), ('se', 'PRON'), ('llama', 'VERB'), ('Juan', 'NOUN'), ('y', 'CONJ'), ('el', 'DET'), ('hijo', 'NOUN'), ('ya', 'ADV'), ('te', 'PRON'), ('lo', 'PRON'), ('he', 'VERB'), ('dicho', 'VERB')]
[('El', 'DET'), ('presidente', 'NOUN'), ('del', 'ADP'), ('gobierno', 'NOUN'), ('por', 'ADP'), ('fin', 'NOUN'), ('ha', 'VERB'), ('dado', 'VERB'), ('la', 'DET'), ('cara', 'NOUN'), ('para', 'ADP'), ('anunciar', 'VERB'), ('aumentos', 'NOUN'), ('de', 'ADP'), ('presupuesto', 'NOUN'), ('en', 'ADP'), ('Educación', 'NOUN'), ('y', 'CONJ'), ('Sanidad', 'NOUN'), ('a', 'ADP'), ('costa', 'NOUN'), ('de', 'ADP'), ('dejar', 'VERB'), ('de', 'ADP'), ('subvencionar', 'NOUN'), ('las', 'DET'), ('empresas', 'NOUN'), ('de', 'ADP'), ('los', 'DET'), ('amigotes.', 'NOUN')]
[('El', 'DET'), ('cacique', 'NOUN'), ('corrupto', 'NOUN'), ('y', 'CONJ'), ('la', 'DET'), ('tonadillera', 'NOUN'), ('se', 'PRON'), ('comerán', 'VERB'), ('el', 'DET'), ('turrón', 'NOUN'), ('en', 'ADP'), ('prisión.', 'NOUN')]