Ir al contenido
elmoyer

Natural Language Toolkit Python

Recommended Posts

                                                                                  gdGPOFX.png

 

El kit de herramientas de lenguaje natural, o más comúnmente NLTK, es un conjunto de bibliotecas y programas para el procesamiento del lenguaje natural (PLN) simbólico y estadísticos para el lenguaje de programación Python. NLTK incluye demostraciones gráficas y datos de muestra. Se acompaña de un libro que explica los conceptos subyacentes a las tareas de procesamiento del lenguaje compatibles el toolkit, además de programas de ejemplo.


NLTK está destinado a apoyar la investigación y la enseñanza en PLN o áreas muy relacionadas, que incluyen la lingüística empírica, las ciencias cognitivas, la inteligencia artificial, la recuperación de información, y el aprendizaje de la máquina. NLTK se ha utilizado con éxito como herramienta de enseñanza, como una herramienta de estudio individual, y como plataforma para los sistemas de investigación de prototipos y construcción.

 

Por ejemplo, se puede emplear para ver el Ordenamiento por mezcla, es un algoritmo de ordenamiento externo estable basado en la técnica divide y vencerás. Es de complejidad O(n log n):

 DcqQh5s.png

 

También se emplea para trabajar con grandes corpus:

 

 

lJA9eCl.png

En su web podéis leer tanto el libro como ver el manual de instalación (http://www.nltk.org/). La instalación de NLTK es bastante sencilla:


1.- Instalar el Setuptools: http://pypi.python.org/pypi/setuptools
2.- Instalar Pip: sudo easy_install pip (código)
3.- Instalar nltk: sudo pip install -U nltk (código)
[Opcional:
-Instalar Numpy: sudo apt-get install python-numpy
-Instalar Matlab: sudo apt-get install python-matplotlib
-Instalar tkinter: sudo apt-get install python-tk
Yo recomiendo instalarlo si queremos ver gráficos o estadísticas.
]


Para comprobar si lo hemos instalado bien, abrimos un terminal y tecleamos:

 

python
import nltk

Si no nos da nigún error enhorabuena, ya tendremos instalado nltk en nuestro equipo :D


Ahora solo falta descargar lo que necesitemos de nltk. Tenemos la opción de descargarnos el libro(entendiendo como libro unos de corpus, herramientas y varias funciones interesantes), herramientas específicas o todo. Yo me descargué todo, ya que si me aburro ya que si me aburro puedo toquetear un poco xD. Para descargarnos lo que queramos introducimos esto:

 

nltk.download()

Si hemos descargado en el python tkinter y el matlab podremos verlo en modo gráfico:


VcmkmXM.png


Si no hemos instalado el tkinter, tendremos que hacerlo por el terminal y nos aparecerá algo como:

 

nltk.download()
NLTK Downloader
---------------------------------------------------------------------------
d) Download l) List u) Update c) Config h) Help q) Quit
---------------------------------------------------------------------------
Downloader> d

Download which package (l=list; x=cancel)?
Identifier> punkt
Downloading package 'punkt' to D:\python27\nltk_data...
Unzipping tokenizers\punkt.zip.

---------------------------------------------------------------------------
d) Download l) List u) Update c) Config h) Help q) Quit
---------------------------------------------------------------------------
Downloader> q  

Trabajando con textos:

 

Una vez descargados los datos, solo hace falta importar lo que necesitemos. Por ejemplo la carga de txts:

 

Los textos que tenemos a nuestra disposición son:

-text1:Moby Dick by Herman Melville 1851
-text2:Sense and Sensibility by Jane Austen 1811
-text3: The Book of Genesis
-text4: Inaugural Address Corpus
-text5: Chat Corpus
-text6: Monty Python and the Holy Grail
-text7: Wall Street Journal
-text8: Personals Corpus
-text9: The Man Who Was Thursday by G . K . Chesterton 1908

from nltk.book import *

Los textos importados pertenecen a la clase "text" de la librería nltk, e incorporan diferentes funciones. Las funciones más útiles para el análisis semántico son:

concordance: Devuelve las líneas del texto “text1” en las que aparece “monstrous”.

sintaxis: text1.concordance("monstrous") 
 

>>> text1.concordance("monstrous")
Displaying 11 of 11 matches:
ong the former , one was of a most monstrous size . ... This came towards us ,
ON OF THE PSALMS . " Touching that monstrous bulk of the whale or ork we have r
ll over with a heathenish array of monstrous clubs and spears . Some were thick
d as you gazed , and wondered what monstrous cannibal and savage could ever hav
that has survived the flood ; most monstrous and most mountainous ! That Himmal
they might scout at Moby Dick as a monstrous fable , or still worse and more de
th of Radney .'" CHAPTER 55 Of the monstrous Pictures of Whales . I shall ere l
ing Scenes . In connexion with the monstrous pictures of whales , I am strongly
ere to enter upon those still more monstrous stories of them which are to be fo
ght have been rummaged out of this monstrous cabinet there is no telling . But
of Whale - Bones ; for Whales of a monstrous size are oftentimes cast up dead u
>>>

similar -> Devuelve palabras usadas de forma similar en el texto.

sintaixs: text1.similar("monstrous")
 

>>> text1.similar("monstrous")
mean part maddens doleful gamesome subtly uncommon careful untoward
exasperate loving passing mouldy christian few true mystifying
imperial modifies contemptible

common_contexts-> Encuentra contextos comparTdos por dos o más palabras. Los "_" que obtenemos como resultado, es donde iría la palabra.

sintaxis: text2.common_contexts(["monstrous", "very"]) 
 

 	
>>> text2.common_contexts(["monstrous", "very"])
a_pretty is_pretty am_glad be_glad a_lucky

Todas estas funciones, juegan bastante con otras funciones útiles de python como son:

len(text1)
set(text1)
sorted(set(text1))

Por ejemplo, queremos tener una variable que contenga el vocabulario (por orden alfabético) de un texto: words=sorted(set(text1))

 

También podemos hacer uso de los operadores matemáticos:

def percentage(count,total):
       return 100*count/total
#calcula la frecuencia de aparición de una palabra.

Ya que estamos trabajando con textos, tenemos que saber que los textos están formados por palabras, números, signos de puntuación...pero todo es un string. Por eso cuando trabajamos con el procesamiento de textos, tenemos que tener claras las herramientas que podemos utilizar:

-s.startswith(t): test if s starts with t 
-s.endswith(t): test if s ends with t 
-t in s: test if t is contained inside s 
-s.islower(): test if all cased characters in s are lowercase 
-s.isupper(): test if all cased characters in s are uppercase
-s.isalpha(): test if all characters in s are alphabetic 
-s.isalnum(): test if all characters in s are alphanumeric 
-s.isdigit(): test if all characters in s are digits 
-s.isTtle(): test if s is Ttlecased (all words in s have have iniTal capitals)
-s.find(t): index of first instance of string t inside s (-­‐1 if not found)
-s.rfind(t): index of last instance of string t inside s (-­‐1 if not found)
-s.index(t):like s.find(t) except it raises ValueError if not found
-s.rindex(t):like s.rfind(t) except it raises ValueError if not found
-s.join(text):combine the words of the text into a string using s as the glue
-s.split(t):split s into a list wherever a t is found (whitespace by default)
-s.splitlines():split s into a list of strings, one per line
-s.lower():a lowercased version of the string s
-s.upper():an uppercased version of the string s
-s.title():a titlecased version of the string s
-s.strip():a copy of s without leading or trailing whitespace
-s.replace(t, u):replace instances of t with u inside s

Otra función bastante útil es FreqDist(Frequency Distributions), que muestra la frecuencia de aparación de cada elemento.

fdist1=FreqDist()

fdist1 es una función que genera una variable de la clase nltk.probability.freqdist. Incorpora diferentes funciones que permiten generar el vocabulario del texto y la frecuencia de aparación de cada elemento (en orden decreciente):

>>> fdist1 = FreqDist(text1)
>>> print(fdist1)
<FreqDist with 19317 samples and 260819 outcomes>

>>> fdist1.most_common(50)
[(',', 18713), ('the', 13721), ('.', 6862), ('of', 6536), ('and', 6024),
('a', 4569), ('to', 4542), (';', 4072), ('in', 3916), ('that', 2982),
("'", 2684), ('-', 2552), ('his', 2459), ('it', 2209), ('I', 2124),
('s', 1739), ('is', 1695), ('he', 1661), ('with', 1659), ('was', 1632),
('as', 1620), ('"', 1478), ('all', 1462), ('for', 1414), ('this', 1280),
('!', 1269), ('at', 1231), ('by', 1137), ('but', 1113), ('not', 1103),
('--', 1070), ('him', 1058), ('from', 1052), ('be', 1030), ('on', 1005),
('so', 918), ('whale', 906), ('one', 889), ('you', 841), ('had', 767),
('have', 760), ('there', 715), ('But', 705), ('or', 697), ('were', 680),
('now', 646), ('which', 640), ('?', 637), ('me', 627), ('like', 624)]
>>> fdist1['whale']
906
>>>

Incluye, entre otras, las siguientes funciones:

-fdist.samples(): Genera una lista con el vocabulario 
-fdist.values(): Devuelve el no de veces que aparece cada palabra 
-fdist.N(): No total de palabras en el texto 
-fdist.freq(word): Devuelve la frecuencia de aparación de word 
-fdist.inc(palabra): Incrementa la cuenta para una palabra 
-fdist.max(): Palabra con máxima frecuencia 
-fdist.tabulate(): Tabula la distribución de frecuencia 
-fdist.plot(): Representación gráfica

Si no queremos cargar todos los textos de NLTK, podemos importar el corpus que nos interese a nosotros. Tenemos dos formas de hacerlo:

 

1.- Vemos los textos que hay disponibles:

nltk.corpus.gutenberg.fileids()
>>>​['austen-­‐emma.txt', 'austen-­‐persuasion.txt', ...

Y seleccionamos uno de ellos:

emma = nltk.corpus.gutenberg.words('austen-­‐emma.txt')

2.- Directamente:

from nltk.corpus import gutenberg 
emma = gutenberg.words('austen-­‐emma.txt')

Las métodos que se pueden emplear en los corpus son:

fileids(): the files of the corpus
fileids([categories]): the files of the corpus corresponding to these categories
categories(): the categories of the corpus 
categories([fileids]): the categories of the corpus corresponding to these files 
raw(): the raw content of the corpus 
raw(fileids=[f1,f2,f3]):the raw content of the specified files 
raw(categories=[c1,c2]): the raw content of the specified categories 
words(): the words of the whole corpus
words(fileids=[f1,f2,f3]): the words of the specified fileids
words(categories=[c1,c2]): the words of the specified categories 
sents(): the sentences of the whole corpus 
sents(fileids=[f1,f2,f3]): the sentences of the specified fileids
sents(categories=[c1,c2]): the sentences of the specified categories 
abspath(fileid): the locaTon of the given file on disk 
encoding(fileid): the encoding of the file (if known) 
open(fileid): open a stream for reading the given corpus file
root(): the path to the root of locally installed corpus 
readme(): the contents of the README file of the corpus

Ejemplos de algunos métodos para trabajar con los corpus:

 

fileids():

>>> import nltk
>>> nltk.corpus.gutenberg.fileids()
['austen-emma.txt', 'austen-persuasion.txt', 'austen-sense.txt', 'bible-kjv.txt','blake-poems.txt', 'bryant-stories.txt', 'burgess-busterbrown.txt','carroll-alice.txt', 'chesterton-ball.txt', 'chesterton-brown.txt','chesterton-thursday.txt', 'edgeworth-parents.txt', 'melville-moby_dick.txt','milton-paradise.txt', 'shakespeare-caesar.txt', 'shakespeare-hamlet.txt','shakespeare-macbeth.txt', 'whitman-leaves.txt']

categories():

>>> from nltk.corpus import brown
>>> brown.categories()
['adventure', 'belles_lettres', 'editorial', 'fiction', 'government', 'hobbies','humor', 'learned', 'lore', 'mystery', 'news', 'religion', 'reviews', 'romance','science_fiction']

words():

>>> nltk.corpus.udhr.words('Javanese-Latin1')[11:]
['Saben', 'umat', 'manungsa', 'lair', 'kanthi', 'hak', ...]

>>> nltk.corpus.cess_esp.words()
['El', 'grupo', 'estatal', 'Electricit\xe9_de_France', ...]

>>> nltk.corpus.floresta.words()
['Um', 'revivalismo', 'refrescante', 'O', '7_e_Meio', ...]

sents():

>>> macbeth_sentences = gutenberg.sents('shakespeare-macbeth.txt')
>>> macbeth_sentences
[['[', 'The', 'Tragedie', 'of', 'Macbeth', 'by', 'William', 'Shakespeare',
'1603', ']'], ['Actus', 'Primus', '.'], ...]

Objetivos:

 

ULSbBcC.png

 

 

Trabajando con documentos:

 

 

Textos planos:

 

Se puede importar cualquier texto plano. La descarga desde un repositorio web puede hacerse así:

>>> from __future__ import division  # Python 2 users only
>>> import nltk, re, pprint
>>> from nltk import word_tokenize
>>>from urllib import urlopen 
>>>url = "h{p://www.gutenberg.org/files/2554/2554.txt" 
>>>raw = urlopen(url).read()
>>>from urllib import * 
>>> url = "http://www.gutenberg.org/files/2554/2554.txt"
>>> response = urlopen(url)
>>> raw = response.read().decode('utf8')
>>> len(raw)
1176893
>>> raw[:75]
'The Project Gutenberg EBook of Crime and Punishment, by Fyodor Dostoevsky\r\n'

En la variable “raw” se encuentra texto sin procesar. Antes de proceder a su procesado hay que formatearlo (tokenizaton). El formato consiste simplemente en convertirlo en una lista de elementos (palabras, frases, bigramas,trigramas...):

tokens = nltk.word_tokenize(raw)

Páginas Web:

 

Resulta bastante interesante la importación de páginas web:

>>> from __future__ import division  # Python 2 users only
>>> import nltk, re, pprint
>>> from nltk import word_tokenize
>>>from urllib import *
>>> url = "http://news.bbc.co.uk/2/hi/health/2284783.stm"
>>> html = urlopen(url).read().decode('utf8')
>>> html[:60]
'<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN'

El problema que nos encontramos es también obtenemos todas las etiquetas HTML, perco contamos con un método para eliminar automáticamente las etiquetas antes de la "tokenización":

>>> from bs4 import BeautifulSoup
>>> raw = BeautifulSoup(html).get_text()
>>> tokens = word_tokenize(raw)
>>> tokens
['BBC', 'NEWS', '|', 'Health', '|', 'Blondes', "'to", 'die', 'out', ...]

RSS:

>>> import feedparser
>>> llog = feedparser.parse("http://languagelog.ldc.upenn.edu/nll/?feed=atom")
>>> llog['feed']['title']
'Language Log'
>>> len(llog.entries)
15
>>> post = llog.entries[2]
>>> post.title
"He's My BF"
>>> content = post.content[0].value
>>> content[:70]
'<p>Today I was chatting with three of our visiting graduate students f'
>>> raw = BeautifulSoup(content).get_text()
>>> word_tokenize(raw)
['Today', 'I', 'was', 'chatting', 'with', 'three', 'of', 'our', 'visiting','graduate', 'students', 'from', 'the', 'PRC', '.', 'Thinking', 'that', 'I', 'was', 'being', 'au', 'courant', ',', 'I', 'mentioned', 'the', 'expression', 'DUI4XIANG4', '\u5c0d\u8c61', '("', 'boy', '/', 'girl', 'friend', '"', ...]

Contenido local:

 

-Cargar datos locales:

>>>path = nltk.data.find('corpora/gutenberg/melville-­‐ moby_dick.txt') #Busca el texto
>>>raw = open(path,'rU').read() #Carga el texto 
>>>tokens = nltk.word_tokenize(raw) #Formato
>>>raw[1:29]
'Moby Dick by Herman Melville’

**Otra forma de seleccionar el archivo sería:

>>>file = os.path.join('carpeta', 'subcarpeta','archivo') #Es necesario importar os (import os)

Procesamiento del contenido de los documentos:

 

 

Después de haber trabajado con los documentos el siguiente paso sería dedicarnos a su procesamiento. Dentro del procesamiento del contenido de los archivos, podemos trabajar con:

 

-Tokenización:

Uno de los procesos que puede llevar a cabo la tokenización es el paso de texto a frases, es decir, el programa reconoce que una frase nueva empieza despues de cada punto. Por ejemplo:
 

>>> from nltk.tokenize import sent_tokenize
>>> frase = 'Esto es una prueba para GNU Linux Vagos. Y no se me ocurre mucho mas que poner en esta frase de prueba. Se me olvidaba, Linux rules!' 
>>> sent_tokenize(frase)
['Esto es una prueba para GNU Linux Vagos.', 'Y no se me ocurre mucho mas que poner en esta frase de prueba.', 'Se me olvidaba, Linux rules!']

Como vemos, cada vez que encuentra un punto da por termiada la frase encerrandola entre comillas y devolviendonos una lista con todas las frases distintas que encuentra este método. Esto se debe a la instancia PunktSentenceTokenizer, que funciona para una gran cantidad de idiomas.

 

Sin embargo si queremos formatear muchas frases en un determinado idioma se recomienda cargar su módulo correspondiente. Disponemos de los siguientes tokenizers: danés, esloveno, finés, alemán, noruego, checo, italiano, español, polaco, griego, estonio, inglés, turco, sueco, holandés, portugues y francés.
 
Para poder importar el módulo que queramos tendremos que escribir lo siguiente:
 
>>> import nltk.data
>>> tokenizer = nltk.data.load('tokenizers/punkt/german.pickle')
#Donde sustituiremos german.pickle por uno de los idiomas que se encuentran disponibles.pickle,

Sin embargo, da un poco "igual" importar un idioma u otro ya que antes hemos escrito: "frase = 'Esto es una prueba para GNU Linux Vagos. Y no se me ocurre mucho mas que poner en esta frase de prueba. Se me olvidaba, Linux rules!' " y acabamos de importar el idioma alemán pero el resultado que obtenemos es el mismo:

>>> tokenizer.tokenize(frase)
['Esto es una prueba para GNU Linux Vagos.', 'Y no se me ocurre mucho mas que poner en esta frase de prueba.', 'Se me olvidaba, Linux rules!']
#Esto se debe a que se emplea un sistema bastante sencillo que hemos explicado ante. Un punto, una frase nueva
#(parece primaria esto xD )

Otra posibilidad que nos ofrece la tokenización es el paso de texto a tokens, es decir, de frases a palabras:

>>> from nltk.tokenize import word_tokenize
>>> word_tokenize('Hola, GNU Linux Vagos.')
['Hola', ',', 'GNU', 'Linux', 'Vagos', '.']
#Como podemos observar, un token es tanto una palabra como un signo de puntuación. Sin 
#embargo en idiomas como el inglés en el que hay contracciones estas son reconocidas y no 
#son valoradas como un token extra.

Después de haber comentado un poco como funciona seguramente mas de uno se habrá quedado pensando en la utilidad de todo esto, de que sirve separar una frase en tokens y que me los devuelva en un string? Visto así pues puede resultar poco útil, pero que os parece si jugamos un poco con las expresiones regulares? :D :D :D

 

Una expresión regular, a menudo llamada también regex, es una secuencia de caracteres que forma un patrón de búsqueda, principalmente utilizada para la búsqueda de patrones de cadenas de caracteres u operaciones de sustituciones. Por ejemplo, el grupo formado por las cadenas Handel, Händel y Haendel se describe con el patrón "H(a|ä|ae)ndel". La mayoría de las formalizaciones proporcionan los siguientes constructores: una expresión regular es una forma de representar a los lenguajes regulares (finitos o infinitos) y se construye utilizando caracteres del alfabeto sobre el cual se define el lenguaje.
En informática, las expresiones regulares proveen una manera muy flexible de buscar o reconocer cadenas de texto.
 
Y dejando a un lado la teoría, vamos con la practica. Seguímos utilizando los módulos de tokenización pero ahora solo hace falta importar el módulo de RegEx:
 
>>> from nltk.tokenize import regexp_tokenize

Y ahora a jugar con las RegEx:

>>> regexp_tokenize("i can't breathe.","[\S']+")
['i', "can't", 'breathe.']

>>> regexp_tokenize("i can't breathe.","[\w']+")
['i', "can't", 'breathe']
Si os habeís fijado bien, en la primera frase al hacer la tokenización el punto no ha sido considerado como un token y en la segunda directamente ni se tiene en cuenta. Eso se debe a "[\S']+"
y "[\S']+" respectivamente. El "+" que tienen en común indica que puede haber 1 o más de un item X; la w, indica que solo se tienen en cuenta los caractéres alfanuméricos. 
 
Os dejo por aquí la sintaxis de las expresiones regulares:
 
. => Wildcard 
^abc => Encuentra un patrón abc al inicio de una cadena 
abc$ => Encuentra abc al final de una cadena 
[abc] =>  Encuentra uno de un conjunto de caracteres
[A-­‐Z0-­‐9] => Encuentra uno de un rango de caracteres 
ed|ing|s => Encuentra una de las cadenas especificadas (disjuncTon)
* => Cero o más de los ítems previos. Ej.: a*, [a-­‐z]* (Kleene Closure) 
+ => Uno o más de los ítems previos, Ej.: a+, [a-­‐z]+ 
? => Opcional, ej.: a?, [a-­‐z]? 
{n} => Exactamente n repeTciones 
{n,} => Al menos n repeticiones
{,n} => No más de n repeticones
{m,n} => Al menos m y no más de m 
a(b|c)+ => Paréntesis que indica el objeto de las operaciones

\b => Word boundary (zero width)
\d => Cualquier decimal (equivalente a [0-­‐9]) 
\D => Cualquier no decimal (equivalente a [^0-­‐9]) 
\s => Cualquier espacio (equivalente a [ \t\n\r\f\v] 
\S => Cualquier no espacio (equivalente a [^ \t\n\r\f\v]) 
\w => Cualquier alfanumérico (equivalente a [a-­‐zA-­‐Z0-­‐9_]) 
\W => Cualquier no alfanumérico (equivalente a [^a-­‐zA-­‐Z0-­‐9_]) 
\t => Tabulador 
\n => Nueva línea 
\r => Retorno de carro
\f => Form feed (página nueva)
\v => Tabulador vertical

Otra utilidad de las expresiones regulares es la búsqueda de palabras que contengan por ejemplo un sufijo, prefijo, afijo o lo que queramos:

>>>import re
>>> wordlist = [w for w in nltk.corpus.words.words('en') if w.islower()]#Carga del vocabulario
>>> words = [w for w in wordlist if re.search('ed$',w)]#todas las parabras que terminen en -ed
>>> print words[:25]
[u'abaissed', u'abandoned', u'abased', u'abashed', u'abatised', u'abed', u'aborted', u'abridged', u'abscessed', u'absconded', u'absorbed', u'abstracted', u'abstricted', u'accelerated', u'accepted', u'accidented', u'accoladed', u'accolated', u'accomplished', u'accosted', u'accredited', u'accursed', u'accused', u'accustomed', u'acetated']

Más ejemplos:

>>> words = [w for w in wordlist if re.search('^..j..t..$', w)]
>>> words [:15]
[u'abjectly', u'adjuster', u'dejected', u'dejectly', u'injector', u'majestic', u'objectee', u'objector', u'rejecter', u'rejector', u'unjilted', u'unjolted', u'unjustly']

En este ejemplo estamos buscando una palabra que tenga 8 letras en las que aparezca en tercera posición una j y en sexta posición una t.

 

-Lematización o lo que es lo mismo, la extracción de las raíces de las palabras. NLTK trabaja con 3 lematizadores, el de Porter, Lancaster y Snowball. 

>>> raw= "Each character in a regular expression is either understood to be a metacharacter with its special meaning, or a regular character with its literal meaning. Together, they can be used to identify textual material of a given pattern, or process a number of instances of it that can vary from a precise equality to a very general similarity of the pattern."

>>> tokens = nltk.word_tokenize(raw)

Porter:

>>> porter = nltk.PorterStemmer()
>>> [porter.stem(t) for t in tokens]
[u'Each', u'charact', u'in', u'a', u'regular', u'express', u'is', u'either', u'understood', u'to', u'be', u'a', u'metacharact', u'with', u'it', u'special', u'mean', u',', u'or', u'a', u'regular', u'charact', u'with', u'it', u'liter', u'mean', u'.', u'Togeth', u',', u'they', u'can', u'be', u'use', u'to', u'identifi', u'textual', u'materi', u'of', u'a', u'given', u'pattern', u',', u'or', u'process', u'a', u'number', u'of', u'instanc', u'of', u'it', u'that', u'can', u'vari', u'from', u'a', u'precis', u'equal', u'to', u'a', u'veri', u'gener', u'similar', u'of', u'the', u'pattern', u'.']

Lancaster:

>>> lancaster=nltk.LancasterStemmer()
>>> [lancaster.stem(t) for t in tokens]
['each', 'charact', 'in', 'a', 'regul', u'express', 'is', 'eith', 'understood', 'to', 'be', 'a', 'metacharact', 'with', 'it', 'spec', 'mean', ',', 'or', 'a', 'regul', 'charact', 'with', 'it', 'lit', 'mean', '.', 'togeth', ',', 'they', 'can', 'be', 'us', 'to', 'ident', 'text', 'mat', 'of', 'a', 'giv', 'pattern', ',', 'or', 'process', 'a', 'numb', 'of', u'inst', 'of', 'it', 'that', 'can', 'vary', 'from', 'a', 'prec', 'eq', 'to', 'a', 'very', 'gen', 'simil', 'of', 'the', 'pattern', '.']
Lematizador Snowball:
Funciona con varias lenguas entre las que encontramos: inglés, frances, espanol, portugés, italiano, alemán, dutch, swedish, norwegian, danish, ruso y finés.
 
>>> from nltk.stem import SnowballStemmer
>>> spanish_stemmer = SnowballStemmer("spanish")
>>> frase = "Estoy escribiendo un poco sobre NLTK mientras estoy tomandome un cafe, tengo bastante cansancio acumulado quizas deberia dormir mas."
>>> tokens = nltk.word_tokenize(frase)
>>> [spanish_stemmer.stem(t) for  t in tokens]
[u'estoy', u'escrib', u'un', u'poc', u'sobr', u'nltk', u'mientr', u'estoy', u'tom', u'un', u'caf', u',', u'teng', u'bastant', u'cansanci', u'acumul', u'quiz', u'deberi', u'dorm', u'mas', u'.']

Lo que estamos hacieno es utilizar un lematizador que extrae la auténtica raíz de cada palabra a partir de un diccionario. NLTK utiliza WordNet(explicaré otro día un poco mas sobre esta herramienta), una base de datos léxica en inglés.

>>>from nltk.stem import WordNetLemmatizer
>>> frase = "the French stemmer turns out to be the most complicated, whereas the Russian stemmer, despite its large number of suffixes, is very simple. In fact it is interesting that English, with its minimal use of i-suffixes, has such a complex stemmer."
>>> tokens = nltk.word_tokenize(frase)
>>>lemmatizer = WordNetLemmatizer()
>>>[lemmatizer.lemmatize(t) for t in tokens]
['the', 'French', 'stemmer', u'turn', 'out', 'to', 'be', 'the', 'most', 'complicated', ',', 'whereas', 'the', 'Russian', 'stemmer', ',', 'despite', u'it', 'large', 'number', 'of', u'suffix', ',', 'is', 'very', 'simple', '.', 'In', 'fact', 'it', 'is', 'interesting', 'that', 'English', ',', 'with', u'it', 'minimal', 'use', 'of', 'i-suffixes', ',', u'ha', 'such', 'a', 'complex', 'stemmer', '.']

Con Lancaster lo que obtenemos es la palabra con los sufijos extraidos:

>>> lancaster = nltk.LancasterStemmer()
>>> [lancaster.stem(t) for t in frase]
['t', 'h', 'e', ' ', 'f', 'r', 'e', 'n', 'c', 'h', ' ', 's', 't', 'e', 'm', 'm', 'e', 'r', ' ', 't', 'u', 'r', 'n', 's', ' ', 'o', 'u', 't', ' ', 't', 'o', ' ', 'b', 'e', ' ', 't', 'h', 'e', ' ', 'm', 'o', 's', 't', ' ', 'c', 'o', 'm', 'p', 'l', 'i', 'c', 'a', 't', 'e', 'd', ',', ' ', 'w', 'h', 'e', 'r', 'e', 'a', 's', ' ', 't', 'h', 'e', ' ', 'r', 'u', 's', 's', 'i', 'a', 'n', ' ', 's', 't', 'e', 'm', 'm', 'e', 'r', ',', ' ', 'd', 'e', 's', 'p', 'i', 't', 'e', ' ', 'i', 't', 's', ' ', 'l', 'a', 'r', 'g', 'e', ' ', 'n', 'u', 'm', 'b', 'e', 'r', ' ', 'o', 'f', ' ', 's', 'u', 'f', 'f', 'i', 'x', 'e', 's', ',', ' ', 'i', 's', ' ', 'v', 'e', 'r', 'y', ' ', 's', 'i', 'm', 'p', 'l', 'e', '.', ' ', 'i', 'n', ' ', 'f', 'a', 'c', 't', ' ', 'i', 't', ' ', 'i', 's', ' ', 'i', 'n', 't', 'e', 'r', 'e', 's', 't', 'i', 'n', 'g', ' ', 't', 'h', 'a', 't', ' ', 'e', 'n', 'g', 'l', 'i', 's', 'h', ',', ' ', 'w', 'i', 't', 'h', ' ', 'i', 't', 's', ' ', 'm', 'i', 'n', 'i', 'm', 'a', 'l', ' ', 'u', 's', 'e', ' ', 'o', 'f', ' ', 'i', '-', 's', 'u', 'f', 'f', 'i', 'x', 'e', 's', ',', ' ', 'h', 'a', 's', ' ', 's', 'u', 'c', 'h', ' ', 'a', ' ', 'c', 'o', 'm', 'p', 'l', 'e', 'x', ' ', 's', 't', 'e', 'm', 'm', 'e', 'r', '.']

El lematizador también nos ayuda a encontrar un lema para una palabra. En el caso de no encontrar un lema, devuelve la palabra:
 
>>> lemmatizer.lemmatize("tokens")
u'token'

Además el lemmatizer reconoces adjetivos(pos ='a'), sustantivos(pos='n'), adverbios(pos='r') y verbos(pos='v')

>>> lemmatizer.lemmatize('readings', pos='n')
u'reading'
>>> lemmatizer.lemmatize('readings', pos='v')
u'read'
>>> lemmatizer.lemmatize('readings', pos='r')
'readings' # como hemos dicho, si no encuentra un lema devuelve la palabra introducida

 

 

-Eliminación de stopwords:
Eliminación de palabras irrelevantes. NLTK tiene una librería para eliminar las stopwords, es decir, aquellas que no contribuyen al significado como serían "de", "la", "el", "que", "en"...
La librería soporta los siguientes idiomas: noruego, italiano, portugués, francés, español, holandés, danés, finlandés, alemán, húngaro, Inglés, sueco, turco y ruso.
 
>>> from nltk.corpus import stopwords
>>> stopwords.words('spanish')
#sustituir el idioma por el que queramos.
[u'de', u'la', u'que', u'el', u'en', u'y', u'a', u'los', u'del', u'se', u'las', u'por', u'un', u'para', u'con', u'no', u'una', u'su', u'al', u'lo', u'como', u'más', u'pero', u'sus', u'le', u'ya', u'o', u'este', u'sí', u'porque', u'esta', u'entre', u'cuando', u'muy', u'sin', u'sobre', u'también', u'me', u'hasta', u'hay', u'donde', u'quien', u'desde', u'todo', u'nos', u'durante', u'todos', u'uno', u'les', u'ni', u'contra', u'otros', u'ese', u'eso', u'ante', u'ellos', u'e', u'esto', u'mí', u'antes', u'algunos', u'qué', u'unos', u'yo', u'otro', u'otras', u'otra', u'él', u'tanto', u'esa', u'estos', u'mucho', u'quienes', u'nada', u'muchos', u'cual', u'poco', u'ella', u'estar', u'estas', u'algunas', u'algo', u'nosotros', u'mi', u'mis', u'tú', u'te', u'ti', u'tu', u'tus', u'ellas', u'nosotras', u'vosostros', u'vosostras', u'os', u'mío', u'mía', u'míos', u'mías', u'tuyo', u'tuya', u'tuyos', u'tuyas', u'suyo', u'suya', u'suyos', u'suyas', u'nuestro', u'nuestra', u'nuestros', u'nuestras', u'vuestro', u'vuestra', u'vuestros', u'vuestras', u'esos', u'esas', u'estoy', u'estás', u'está', u'estamos', u'estáis', u'están', u'esté', u'estés', u'estemos', u'estéis', u'estén', u'estaré', u'estarás', u'estará', u'estaremos', u'estaréis', u'estarán', u'estaría', u'estarías', u'estaríamos', u'estaríais', u'estarían', u'estaba', u'estabas', u'estábamos', u'estabais', u'estaban', u'estuve', u'estuviste', u'estuvo', u'estuvimos', u'estuvisteis', u'estuvieron', u'estuviera', u'estuvieras', u'estuviéramos', u'estuvierais', u'estuvieran', u'estuviese', u'estuvieses', u'estuviésemos', u'estuvieseis', u'estuviesen', u'estando', u'estado', u'estada', u'estados', u'estadas', u'estad', u'he', u'has', u'ha', u'hemos', u'habéis', u'han', u'haya', u'hayas', u'hayamos', u'hayáis', u'hayan', u'habré', u'habrás', u'habrá', u'habremos', u'habréis', u'habrán', u'habría', u'habrías', u'habríamos', u'habríais', u'habrían', u'había', u'habías', u'habíamos', u'habíais', u'habían', u'hube', u'hubiste', u'hubo', u'hubimos', u'hubisteis', u'hubieron', u'hubiera', u'hubieras', u'hubiéramos', u'hubierais', u'hubieran', u'hubiese', u'hubieses', u'hubiésemos', u'hubieseis', u'hubiesen', u'habiendo', u'habido', u'habida', u'habidos', u'habidas', u'soy', u'eres', u'es', u'somos', u'sois', u'son', u'sea', u'seas', u'seamos', u'seáis', u'sean', u'seré', u'serás', u'será', u'seremos', u'seréis', u'serán', u'sería', u'serías', u'seríamos', u'seríais', u'serían', u'era', u'eras', u'éramos', u'erais', u'eran', u'fui', u'fuiste', u'fue', u'fuimos', u'fuisteis', u'fueron', u'fuera', u'fueras', u'fuéramos', u'fuerais', u'fueran', u'fuese', u'fueses', u'fuésemos', u'fueseis', u'fuesen', u'sintiendo', u'sentido', u'sentida', u'sentidos', u'sentidas', u'siente', u'sentid', u'tengo', u'tienes', u'tiene', u'tenemos', u'tenéis', u'tienen', u'tenga', u'tengas', u'tengamos', u'tengáis', u'tengan', u'tendré', u'tendrás', u'tendrá', u'tendremos', u'tendréis', u'tendrán', u'tendría', u'tendrías', u'tendríamos', u'tendríais', u'tendrían', u'tenía', u'tenías', u'teníamos', u'teníais', u'tenían', u'tuve', u'tuviste', u'tuvo', u'tuvimos', u'tuvisteis', u'tuvieron', u'tuviera', u'tuvieras', u'tuviéramos', u'tuvierais', u'tuvieran', u'tuviese', u'tuvieses', u'tuviésemos', u'tuvieseis', u'tuviesen', u'teniendo', u'tenido', u'tenida', u'tenidos', u'tenidas', u'tened']

Como podéis ver la herramienta de NLTK es muy útil y se puede emplear para hacer bastantes cosas. Esto ha sido una pequeña introducción, a medida que yo también vaya avanzando con NLTK iré comentando que he aprendido nuevo, algún que otro ejercicio...

 

 

Oos recomiendo que busquéis algo mas sobre python para trabajar con mas soltura  :D

http://gnulinuxvagos.es/topic/68-manual-python-para-todos-creative-commons/

http://gnulinuxvagos.es/topic/1915-pep-gu%C3%ADa-de-estilo-de-programaci%C3%B3n-en-python/

 

 

Editado por elmoyer

Compartir este post


Enlace al post
Compartir en otros sitios

Un poco de español en NLTK, para ser un poco mas exacto algo relacionado con CCG(Combinatory Categorial Grammar). Para poneros un poco en situación, CCG es un formalismo gramatical que nos permite ver la estructura sintáctica y semántica de una frase. La teoría aburre un poco, sobre todo si no se es muy fan de la sintaxis o semánticas así que vamos a lo practico :D :

 

Como sabéis todo esto funciona con NLTK, por lo tanto lo primero que tenemos que hacer abrir un terminal y escribir python e importar los módulos necesarios:

elmoyer@laptop: python
Python 2.7.3 (default, Mar 13 2014, 11:03:55) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import nltk
>>> from nltk.ccg import chart, lexicon
>>> from nltk.ccg.chart import printCCGDerivation

Tecleado esto, ya podemos introducir las reglas gramaticales que queramos para poder parsear la frase posteriormente. Así que vamos a ello:

>>> lex = lexicon.parseLexicon(u'''
...        :- S, N, NP, PP
...
...        AdjI :: N\\N
...        AdjD :: N/N
...        AdvD :: S/S
...        AdvI :: S\\S
...        Det :: NP/N
...        PrepNPCompl :: PP/NP
...        PrepNAdjN :: S\\S/N
...        PrepNAdjNP :: S\\S/NP
...        VPNP :: S\\NP/NP
...        VPPP :: S\\NP/PP
...        VPser :: S\\NP/AdjI
...
...        auto => N
...        bebidas => N
...        cine => N
...        ley => N
...        libro => N
...        ministro => N
...        panadería => N
...        presidente => N
...        super => N
...
...        el => Det
...        la => Det
...        las => Det
...        un => Det
...
...        Ana => NP
...        Pablo => NP
...
...        y => var\\.,var/.,var
...
...        pero => (S/NP)\\(S/NP)/(S/NP)
...
...        anunció => VPNP
...        compró => VPNP
...        cree => S\\NP/S[dep]
...        desmintió => VPNP
...        lee => VPNP
...        fueron => VPPP
...
...        es => VPser
...
...        interesante => AdjD
...        interesante => AdjI
...        nueva => AdjD
...        nueva => AdjI
...
...        a => PrepNPCompl
...        en => PrepNAdjN
...        en => PrepNAdjNP
...
...        ayer => AdvI
...
...        que => (NP\\NP)/(S/NP)
...        que => S[dep]/S
...     ''')

Vocabulario y gramática introducido en la variable lex. Si se trabaja con una lengua que requiera soporte de unicode se tiene que escribir una "u" cuando se vaya a definir el lex, tal y como hemos hecho:

lex = lexicon.parseLexicon(u'''
...   #Reglas gramaticales
...   #Diccionario

Una vez que hemos definido todo, creamos nuestro parser:

>>> parser = chart.CCGChartParser(lex, chart.DefaultRuleSet)

Como podéis ver, el parser el llama al modulo chart y específicamente al método "CCGChartParser" que toma como valores el diccionario creado anteriormente(lex) y las reglas por defecto del chart.

Una vez definido el parser, nos tocará decirle a NLTK que trabaje con la frase de la que queramos obtener la información semántica y sintáctica. Para ello haremos referencia al la variable parser(recordad que únicamente es el CCGchartParser) y también al método parse:

>>> for parse in parser.parse(u"el ministro anunció pero el presidente desmintió la nueva ley".split()):

Y tras escribir esto ya sólo nos faltaría hacer un print para que nos devolviese la frase con las anotaciones semánticas y sintácticas:

...     printCCGDerivation(parse)
...     break

Y obtenemos como resultado:

el    ministro    anunció              pero              el    presidente   desmintió     la    nueva  ley
 (NP/N)     N      ((S\NP)/NP)  (((S/NP)\(S/NP))/(S/NP))  (NP/N)      N       ((S\NP)/NP)  (NP/N)  (N/N)   N
--------Leaf
 (NP/N)
        ----------Leaf
            N
------------------>
        NP
------------------>T
    (S/(S\NP))
                  -------------Leaf
                   ((S\NP)/NP)
                               --------------------------Leaf
                                (((S/NP)\(S/NP))/(S/NP))
                                                         --------Leaf
                                                          (NP/N)
                                                                 ------------Leaf
                                                                      N
                                                         -------------------->
                                                                  NP
                                                         -------------------->T
                                                              (S/(S\NP))
                                                                             -------------Leaf
                                                                              ((S\NP)/NP)
                                                         --------------------------------->B
                                                                      (S/NP)
                               ----------------------------------------------------------->
                                                     ((S/NP)\(S/NP))
                                                                                          --------Leaf
                                                                                           (NP/N)
                                                                                                  -------Leaf
                                                                                                   (N/N)
                                                                                                         -----Leaf
                                                                                                           N
                                                                                                  ------------>
                                                                                                       N
                                                                                          -------------------->
                                                                                                   NP
                                                                                          --------------------<T
                                                                                               (S\(S/NP))
                               -------------------------------------------------------------------------------<B
                                                                 (S\(S/NP))
                  --------------------------------------------------------------------------------------------<B
                                                             (S/NP)
-------------------------------------------------------------------------------------------------------------->
                                                      S

Os pongo otro ejemplo con la frase el "el ministró compró la panadería":

 

Es todo igual, lo único que hay que cambiar es la frase a parsear.

>>> parser = chart.CCGChartParser(lex, chart.DefaultRuleSet)
>>> for parse in parser.parse(u"el ministro compró la panadería".split()):
...     printCCGDerivation(parse)
...     break
... 

Obteniendo como resultado:

 el    ministro    compró       la    panadería 
 (NP/N)     N      ((S\NP)/NP)  (NP/N)      N     
--------Leaf
 (NP/N)
        ----------Leaf
            N
------------------>
        NP
                  -------------Leaf
                   ((S\NP)/NP)
                               --------Leaf
                                (NP/N)
                                       -----------Leaf
                                            N
                               ------------------->
                                       NP
                  -------------------------------->
                               (S\NP)
--------------------------------------------------<
                        S

Ya podéis poneros a parsear que se que lo estáis deseando :P

Un saludo!

Editado por elmoyer

Compartir este post


Enlace al post
Compartir en otros sitios

Después de la entrada de CCG, vamos a pasar hoy a las DRT(discourse representation theory). El discourse representation theory es un formalismo lingüístico que intenta explorar el significado de las frases desde un enfoque semántico. Lo curioso es que se realiza de una forma visual y por ello es más cómodo trabajar con las DRT en NLTK. 

 

Vamos a comenzar. Como me imagino que sabéis, necesitamos abrir un terminal, escribir python e importar los módulos necesarios:

>>> import nltk
>>> from nltk.sem.drt import *
>>> from nltk.sem import logic
>>> from nltk.inference import TableauProver

Una vez importado todo, vamos a centrarnos en nuestra frase de ejemplo: "If a farmer owns a donkey, he beats it". Podríamos decir que la frase se puede dividir en dos partes:

  1. If a farmer owns a donkey
  2. he beats it.

Una vez que tenemos claro que podemos dividir la frase en dos, comenzamos a trabajar con NLTK. Importados los módulos necesarios, comenzamos a definir las propiedades o características de las palabras que contiene nuestra frase. Pero antes tenemos que decirle a NLTK que la DRT se leerá mediante un string: 

>>> dexpr = DrtExpression.fromstring

#Comienza la declaración de las propiedades de las palabras 

>>> farmer_x=dexpr('farmer(x)') #granjero definido
>>> donkey_y=dexpr('donkey(y)') #burro definido
>>> owns_xy=('owns(x, y)')	#posesión definida
>>> x = dexpr('x')		#x = nombre de entidad (granjero)
>>> y = dexpr('y')		#y = nombre de entidad (burro)
Tenemos que tener en cuenta que en las DRT "sólo" nos interesan los sustantivos, verbos, adjetivos y adverbios. Por lo tanto podríamos decir que tenemos una serie de "bag of words list"(bolsa de lista de palabras?) que son nuestras stop words o palabras que carecen de importancia. Por lo tanto ni el condicional "if", ni los determinantes "un" y artículos nos sirven para nada. 
 
Una vez definido todo, podríamos obtener el DRT de la primera parte de la frase, "si un granjero tiene un burro". Es algo tan sencillo como añadir un print y ya lo tenemos:
 
>>> print(DRS([x, y], [farmer_x, donkey_y, owns_xy]))
([x, y],[farmer(x), donkey(y), owns(x, y)])

Para que nos sea más fácil el trabajar con la frase, vamos a dividirla en 2. Ya tenemos la primera parte, así que vamos a guardarla en la variable drs1:

>>> drs1 = dexpr('([x, y], [farmer(x), donkey(y), owns(x, y)])')

Sin embargo muchas veces, cuando se habla de DRT, solemos referirnos a la función que acabamos de imprimir en pantalla pero en una caja. Y resulta bastante curioso el método usado por NLTK para incrustarlo en la caja, ya que la función que se encarga de eso es pretty_format() o sea imprimir en un formato bonito:

>>> print(drs1.pretty_format())
 ___________ 
| x y       |	
|-----------|	
| farmer(x) |
| donkey(y) |
| owns(x,y) |
|___________|

Vamos ahora a por la segunda parte de la frase!. La segunda parte es la de "lo golpea". Tenemos que tener en cuenta 2 cosas:
1) con he nos estamos refiriendo a farmer.
2) con it nos estamos refiriendo a donkey.
 
 
Sin embargo tenemos que darle otros valores que no sean X e Y para que en la caja no ponga en la parte superio "X Y" ya que si pusiese eso, la DRT sería incorrecta. Comenzamos con lo mismo, definimos valores:
>>> he_z= dexpr('(x=z)')	
>>> it_u = dexpr('(y=u)')
>>> beats_zu = ('beats(z, u)')

Ahora definimos los nombres de las nuevas entidades:

>>> z = dexpr('z')
>>> u = dexpr('u')

Imprimimos para comprobar si esta bien y para poder guardarlo como drs2:

>>> print (DRS([z, u], [he_z, it_u, beats_zu]))
([u,z],[(x = z), (y = u), beats(z, u)])

Guardamos el resultado como la variable drs2:

>>> drs2 = dexpr('([u,z],[(x = z), (y = u), beats(z, u)])')

Imprimimos para ver si tiene algún fallo con el método pretty_format():

>>> print(drs2.pretty_format())
 ____________ 
| u z        |
|------------|
| (x = z)    |
| (y = u)    |
| beats(z,u) |
|____________|


Ahora solo queda unir las dos DRS que tenemo, por lo tanto lo lógico sería pensar que algo como esto uniría la frase y serviría:
 
>>> drs3 = drs1 + drs2
>>> print(drs3.pretty_format())
  ___________     ____________  
 | x y       |   | u z        | 
(|-----------| + |------------|)
 | farmer(x) |   | (x = z)    | 
 | donkey(y) |   | (y = u)    | 
 | owns(x,y) |   | beats(z,u) | 
 |___________|   |____________| 

Sin embargo al ser todo una misma frase tiene que estar dentro de otra caja que recoja las dos cajas. Además tendremos que quitar el mas y sustituirlo por un simbolo de implicacion. Para ello haremos lo siguiente:
 
>>> drs_final = dexpr(r"([],[([x, y], [farmer(x), donkey(y), owns(x, y)]) -> ([u,z],[(x = z), (y = u), beats(z, u)])])").pretty_print()

 ___________________________________ 
|                                   |
|-----------------------------------|
|   ___________      ____________   |
|  | x y       |    | u z        |  |
| (|-----------| -> |------------|) |
|  | farmer(x) |    | (x = z)    |  |
|  | donkey(y) |    | (y = u)    |  |
|  | owns(x,y) |    | beats(z,u) |  |
|  |___________|    |____________|  |
|___________________________________|

Y fin de la historia, no hay mas que hacer :D

 

Compartir este post


Enlace al post
Compartir en otros sitios

Buenas tarde, hoy vamos a trabajar con uno de los campos más interesantes(a mi parecer) de la lingüística computacional, word-sense disambiguation(desambiguación del significado de la palabra). Para ello vamos a usar nuestro querido NLTK y su módulo de WordNet así que vamos a ello!

 

WordNet es una base de datos léxica del idioma inglés. Agrupa palabras en inglés en conjuntos de sinónimos llamados synsets, proporcionando definiciones cortas y generales, y almacena las relaciones semánticas entre los conjuntos de sinónimos. Su propósito es doble: producir una combinación de diccionario y tesauro cuyo uso sea más intuitivo, y soportar análisis automático de texto y a aplicaciones de Inteligencia Artificial. La base de datos y las herramientas del software se han liberado bajo una licencia BSD y pueden ser descargadas y usadas libremente. Además la base de datos puede consultarse en línea.
 
Sinónimos y significados[senses and Synonyms]:
Consideremos las siguientes frases:
1) Raquel tuvo un accidente con el coche. [\*Ya que WordNet es para inglés sustituiremos coche por motorcar*/]
2) Raquel tuvo un accidente con el automovil. [\*Ya que WordNet es para inglés sustituiremos coche por automobile*/]
 
Las frases 1) y 2) tienen el mimos significado, por lo tanto podemos decir que son sinónimos. Gracias a NLTK y a su módulo de WordNet, podemos explorar la palabra "motorcar". Para ello iniciaremos como siempre nuestro querido python desde terminal e importaremos NLTK:
 
elmoyer@tutorial:~$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import nltk
 
Tras importar NLTK, ya solo nos queda importar también el módulo de WordNet para poder trabajar con él:
 
>>> from nltk.corpus import wordnet as wn 
 
Ese "as wn" es para que no tengamos que escribir siempre wordnet cuando vayamos a usar el módulo y se puede sustituir por wn o por lo que queramos. Una vez importado ya podemos empezar a jugar con los synsets:
>>> wn.synsets('motorcar')
[Synset('car.n.01')]
 
Como vemos, motorcar solo tiene un significado posible que esta designado como "car.n.01", es decir el primer sustantivo con el significado coche. La entidad "car.n.01" se denomina "synset" o "set de sinónimos"(colección de palabras sinónimas o lemas). Para poder ver que palabras entran dentro de este synset, lo único que tenemos que escribir es:
 
>>> wn.synsets('dry') \\Cambiamos de ejemplo y usamos "dry"
[Synset('dry.n.01'), Synset('dry.v.01'), Synset('dry.v.02'), Synset('dry.a.01'), Synset('dry.s.02'), Synset('dry.a.03'), Synset('dry.a.04'), Synset('dry.a.05'), Synset('dry.a.06'), Synset('dry.a.07'), Synset('dry.s.08'), Synset('dry.s.09'), Synset('dry.s.10'), Synset('dry.s.11'), Synset('dry.s.12'), Synset('dry.s.13'), Synset('dry.s.14'), Synset('dry.s.15'), Synset('dry.s.16')]
>>> wn.synset('dry.n.01').lemma_names() \\Vemos que palabras están dentro de este synset 
[u'dry', u'prohibitionist']
 
 
Cada synstes de una palabra puede tener distintos significados. Sin embargo a nosotros lo que nos interesa es el significado de cada palabra que forma el synstet. Estaría bien saber que significa cada palabra, ¿no?:
 
>>> wn.synset('dry.n.01').definition()
u'a reformer who opposes the use of intoxicating beverages'
 
¿Y qué tal un ejemplo también?:
 
>>> wn.synset('dry.v.01').examples()
[u'dry clothes', u'dry hair']
 
Como veís he tenido que migrar al synster de "dry" como verbo(v) y que el synset "dry.n.01" no tenía ejemplos:
>>> wn.synset('dry.n.01').examples()
[]
 
Otra posibilidad que nos ofrece el módulo de WordNet, es obtener todos los lemas de un synset:
 
>>> wn.synset('dry.n.01').lemmas()
[Lemma('dry.n.01.dry'), Lemma('dry.n.01.prohibitionist')]
 
O incluso buscar un lema en concreto:
>>> wn.lemma('dry.n.01.dry')
Lemma('dry.n.01.dry')
 
O obtener el synset correspondiente a un lema:
 
>>> wn.lemma('dry.n.01.dry').synset()
Synset('dry.n.01')
 
U obtener el "nombre"/"designación" de un lema:
 
>>> wn.lemma('dry.n.01.dry').name()
u'dry'
Sin embargo, hay palabras que se podrían considerar ambiguas. En el campo de la lingüística, para ser más concretos en la sintaxis, decimos que una frase es ambigua cuando tienes mas de un árbol(distintas formas en las que se puede anañizar una frase). Esto se puede extrapolar también en este caso a las palabras de WordNet, es decir, decimos que una palabra puede ser ambigua cuando tiene distintos synsets. Así que volvemos a cambiar de ejemplo y vamos otra vez con "car":
 
>>> wn.synsets('car')
[Synset('car.n.01'), Synset('car.n.02'), Synset('car.n.03'), Synset('car.n.04'),
Synset('cable_car.n.01')]
 
Como vemos, tenemos 5 synsets que se diferencian notablemente unos de otros. Llegados a este punto, podríamos pensar que nos hemos quedado atascados y que nos llevaría mucho tiempo saber cual es el synset con el que queremos trabajar. Sin embargo la solución es muy sencilla, lo único que tenemos qu hacer es ver que palabras están dentro de los synsets y de esta forma elegir aquel con el que queríamos trabajar:
 
>>> for synset in wn.synsets('car'):
...     print(synset.lemma_names())
...
['car', 'auto', 'automobile', 'machine', 'motorcar']
['car', 'railcar', 'railway_car', 'railroad_car']
['car', 'gondola']
['car', 'elevator_car']
['cable_car', 'car']
 
La jerarquia de WordNet:
 
                    UdDGtt4.png?1
 
WordNet intenta facilitar la navegación entre los conceptos. para ser más especificos estos conceptos pueden ser:
 
Sustantivos:
  • hiperonimia (hypernymy, can hiperónimo de perro).
  • hiponimia (hyponymy, perro es un hipónimo de can).
  • términos coordinados (coordinate terms, lobo y perro son términos coordinados puesto que ambos son cánidos).
  • holonimia (holonymy, edificio es un holónimo de ventana).
 
Verbos:
  • hiperonimia (hypernymy)
  • troponimia (troponym)
  • consecuencia lógica (entailment)
  • términos coordinados (coordinate terms)
 
Adjetivos:
  • sustantivos relacionados
  • similar a
  • participios de verbos
 
Adverbios
  • La raíz de los adjetivos
 
Un ejemplo de hyponyms con NLTK sería:
 
>>> wn.synsets('sky')
[Synset('sky.n.01'), Synset('flip.v.06')]
>>> sky = wn.synset('sky.n.01')
>>> types_of_sky = sky.hyponyms()
>>> types_of_sky[0]
Synset('blue_sky.n.01')
>>> sorted(lemma.name() for synset in types_of_sky for lemma in synset.lemmas())
[u'blue', u'blue_air', u'blue_sky', u'mackerel_sky', u'wild_blue_yonder']
 
Un ejemplo de hypernyms con NLTK sería:
 
>>> sky.hypernyms()
[Synset('atmosphere.n.05')]
Como se puede ver en la imagen, WordNet tiene distintas jerarquía y el root sería la "entidad".  Pero podemos "navergar" por todos sus recorrido y ver el "largo" de la jerarquia de una palabra en concreto:
 
>>> paths = sky.hypernym_paths()
>>> len(paths)
1
>>> [synset.name() for synset in paths[0]]
[u'entity.n.01', u'physical_entity.n.01', u'matter.n.03', u'fluid.n.02', u'gas.n.02', u'atmosphere.n.05', u'sky.n.01']


También podemos ir al "root", que sería la entidad que encontramos arriba del todo en la imagen:
 
>>> sky.root_hypernyms()
[Synset('entity.n.01')]
Ahora vamos con meronimias y holonimias:
 
>>> wn.synset('sky.n.01').part_meronyms()
[Synset('cloud.n.02'), Synset('rainbow.n.01')]
 
Por hoy eso es todo, espero poder hacer algo para la semana que viene con similitud semántica :D
 
Un saludo!
Editado por elmoyer

Compartir este post


Enlace al post
Compartir en otros sitios

Hola.

Primero que nada Gracias por el aporte, Leía acerca WordNet y es una lastima que no se pueda trabajar la parte de lematización y synsets para sinonimos      en español , veo una serie de recursos en el sitio: http://grial.uab.es/ pero no se si esta ya todo integrado en nltk pero pareciera que si es posible trabajarlo en español, aquí estan algunos ejemplos http://www.nltk.org/howto/wordnet.html pero no hay ninguno que tome palabras en español, mi pregunta es si todos los recursos de la pagina grial.uab.es ya están integrados o bueno la forma cual seria la forma de integrarlos apenas estoy iniciando con NLTK pero me quede justo en la parte de lematización y synsets para trabajar sinonimos.? cualquier ayuda muchas gracias. 

Compartir este post


Enlace al post
Compartir en otros sitios

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Invitado
Responder en este tema...

×   Has incluido contenido con formato.   Eliminar formato

  Sólo se permiten 75 emoticonos como máximo.

×   Tu enlace ha sido insertado automáticamente.   Deshacer y mostrar como enlace

×   Su contenido anterior ha sido restaurado.   Limpiar editor

×   No puedes pegar imágenes directamente. Súbelas a algún hosting de imágenes y pega la dirección URL


×
×
  • Crear Nuevo...