Pequeña introducción a NLTK o cómo analizar un corpus propio

Primer paso: preparar utilización de NLTK (detalles sin importancia). Con import se definen lo módulos que se quieren usar.

nltk.download('book') nos permite descargar varios recursos lingüísticos y corpus (todos los necesarios para los tutoriales en el libro oficial).


In [ ]:
import nltk
nltk.download('book')

cargar el texto

Usamos la variable text para guardar el el texto que queremos analizar. En adelante se puede hacer referencia al texto usando esta variable.

El contenido textual se pone entre comillas, que pueden ser "...", '...' o '''...'''.


In [ ]:
text = '''Neither a recession nor a collapse in revenue has yet been enough to convince \
Russian President Vladimir Putin that it’s time to join with OPEC and cut oil output to \
boost prices. His reasons may be pragmatic rather than political. Russia’s Energy \
Minister Alexander Novak and his Saudi Arabian, Venezuelan and Qatari counterparts \
agreed to freeze output at January levels on Tuesday. The world’s second-largest crude \
producer faces numerous obstacles to any deal that would actually cut production, even if \
Putin decides it’s in the national interest. Reducing the flow of crude might damage \
Russia’s fields and pipelines, require expensive new storage tanks or simply take too long. \
Prior to Tuesday’s agreement, Novak had said he could consider reductions if other producers \
joined in. Yet Igor Sechin, chief executive officer of the country’s largest oil company \
Rosneft OJSC and a close Putin ally, has resisted, saying last week in London that \
coordination would be difficult because no major producer seems willing to pare output. \
"The history of relations with OPEC suggests that Russian companies are not keen to cut \
production," James Henderson, an oil and gas industry analyst at the Oxford Institute for \
Energy Studies, said by phone. "There are certain practical difficulties, and the companies \
would rather somebody else did that, and they could benefit once the price goes up."'''

ver el texto cargado

Al poner el nombre de una variable en una célula de entrada, el sistema responde con el contenido de esta variable.


In [ ]:
text

Lo mismo funciona con una expresión matemática o cosas parecidas


In [ ]:
2+3

longitud del texto en caracteres

La función len() devuelve el tamaño (length) del contenido de una variable. En el caso de que la variable contenga texto el resultado es el número de caracteres.


In [ ]:
len(text)

segmentación en palabras

NLTK contiene muchas funciones para trabajar con datos textuales. Primero tokenizamos el texto: el resultado es la lista de palabras de este texto (que guardamos en la variable words).


In [ ]:
words = nltk.word_tokenize(text)

Podemos ver las el resultado:


In [ ]:
words

longitud del texto en palabras

El tamaño de una lista es el número de elementos que contiene, en este caso el número de palabras (incluyendo puntuación).


In [ ]:
len(words)

longitud media de las palabras (incluyendo espacios)


In [ ]:
len(text)/len(words)

segmentación en oraciones

NLTK también permite separar el texto en oraciones:


In [ ]:
sents = nltk.sent_tokenize(text)

que podemos ver aquí:


In [ ]:
sents

Y podemos contar el número de oraciones:


In [ ]:
len(sents)

número medio de palabras por oración (incluyendo puntuación)

Python permite hacer todo tipo de cálculos matemáticos. Dividiendo el número de palabras por el número de oraciones obtenemos el número medio de palabras por oración:


In [ ]:
len(words)/len(sents)

Anotación con part-of-speech

NLTK también nos permite anotar el texto con información adicional:


In [ ]:
tagged = nltk.pos_tag(words)

El resultado es una lista que contiene pares de tipo (forma,etiqueta):


In [ ]:
tagged

Podemos extraer de esta lista la información que nos interesa, p.ej. solo la forma (lo que nos da una lista idéntica a la lista de palabras que teníamos antes):


In [ ]:
[form for form,pos in tagged]

o solo la etiquetas:


In [ ]:
[pos for form,pos in tagged]

También podemos aplicar filtros a nuestra lista:


In [ ]:
[form for form,pos in tagged if pos=='NNP']

Y siempre podemos elegir qué debe contener el resultado, en este caso los pares (forma,etiqueta) completos, pero solo si la etiqueta empieza por "V" (es decir los verbos):


In [ ]:
[(form,pos) for form,pos in tagged if pos.startswith('V')]

Lematización

El lematizador usa un tagset diferente del que nos da el POS-tagger, hay que convertirlo. Si no hay etiqueta correspondiente, ponemos el valor por defecto del lematizador: wn.NOUN


In [ ]:
from nltk.corpus import wordnet as wn
def penn_to_wn(tag):
    if tag in ['JJ', 'JJR', 'JJS']: # los adjetivos
        return wn.ADJ
    elif tag in ['NN', 'NNS', 'NNP', 'NNPS']: # los sustantivos
        return wn.NOUN
    elif tag in ['RB', 'RBR', 'RBS']: # los adverbios
        return wn.ADV
    elif tag in ['VB', 'VBD', 'VBG', 'VBN', 'VBP', 'VBZ']: # los verbos
        return wn.VERB
    else:
        return wn.NOUN

Función para aplicar la lematización con el tagset convertido


In [ ]:
from nltk.stem import WordNetLemmatizer
def lemma(form,pos):
    return WordNetLemmatizer().lemmatize(form,penn_to_wn(pos))

Y finalmente lo aplicamos a nuestro texto. Al contrario del pos-tagging no se aplica al texto completo (lista de palabras) pero a cada palabra por separado:


In [ ]:
[(form,pos,lemma(form,pos)) for form,pos in tagged]

También se puede iterar más explícitamente sobre la lista de palabras etiquetadas:


In [ ]:
for form,pos in tagged:
    print(lemma(form,pos))