https://relopezbriega.github.io/blog/2017/09/23/procesamiento-del-lenguaje-natural-con-python/
“El lenguaje sirve no sólo para expresar el pensamiento, sino para hacer posibles pensamientos que no podrían existir sin él.”
Bertrand Russell
Introducción
El lenguaje es una de las herramientas centrales en nuestra vida social y profesional. Entre otras cosas, actúa como un medio para transmitir ideas, información, opiniones y sentimientos; así como para persuadir, pedir información, o dar ordenes. Asimismo, el lenguaje humano es algo que esta en constante cambio y evolución; y que puede llegar a ser muy ambiguo y variable. Tomemos por ejemplo la frase “comí una pizza con amigos” comparada con “comí una pizza con aceitunas”; su estructura es la misma, pero su significado es totalmente distinto. De la misma manera, un mismo mensaje puede ser expresado de formas diferentes; “comí una pizza con amigos” puede también ser expresado como “compartí una pizza con amigos”.
Los seres humanos somos muy buenos a la hora de producir e interpretar el lenguaje, podemos expresar, percibir e interpretar significados muy elaborados en fracción de segundos casi sin dificultades; pero al mismo tiempo, somos también muy malos a la hora de entender y describir formalmente las reglas que lo gobiernan. Por este motivo, entender y producir el lenguaje por medio de una computadora es un problema muy difícil de resolver. Éste problema, es el campo de estudio de lo que en inteligencia artificial se conoce como Procesamiento del Lenguaje Natural o NLP por sus siglas en inglés.
¿Qué es el Procesamiento del Lenguaje Natural?
El Procesamiento del Lenguaje Natural o NLP es una disciplina que se encuentra en la intersección de varias ciencias, tales como las Ciencias de la Computación, la Inteligencia Artificial y Psicología Cognitiva. Su idea central es la de darle a las máquinas la capacidad de leer y comprender los idiomas que hablamos los humanos. La investigación del Procesamiento del Lenguaje Natural tiene como objetivo responder a la pregunta de cómo las personas son capaces de comprender el significado de una oración oral / escrita y cómo las personas entienden lo que sucedió, cuándo y dónde sucedió; y las diferencias entre una suposición, una creencia o un hecho.
En general, en Procesamiento del Lenguaje Natural se utilizan seis niveles de comprensión con el objetivo de descubrir el significado del discurso. Estos niveles son:
Nivel fonético: Aquí se presta atención a la fonética, la forma en que las palabras son pronunciadas. Este nivel es importante cuando procesamos la palabra hablada, no así cuando trabajamos con texto escrito.
Nivel morfológico: Aquí nos interesa realizar un análisis morfológico del discurso; estudiar la estructura de las palabras para delimitarlas y clasificarlas.
Nivel sintáctico: Aquí se realiza un análisis de sintaxis, el cual incluye la acción de dividir una oración en cada uno de sus componentes.
Nivel semántico: Este nivel es un complemente del anterior, en el análisis semántico se busca entender el significado de la oración. Las palabras pueden tener múltiples significados, la idea es identificar el significado apropiado por medio del contexto de la oración.
Nivel discursivo: El nivel discursivo examina el significado de la oración en relación a otra oración en el texto o párrafo del mismo documento.
Nivel pragmático: Este nivel se ocupa del análisis de oraciones y cómo se usan en diferentes situaciones. Además, también cómo su significado cambia dependiendo de la situación.
Todos los niveles descritos aquí son inseparables y se complementan entre sí. El objetivo de los sistemas de NLP es incluir estas definiciones en una computadora y luego usarlas para crear una oración estructurada y sin ambigüedades con un significado bien definido.
Aplicaciones del Procesamiento del Lenguaje Natural
Los algoritmos de Procesamiento del Lenguaje Natural suelen basarse en algoritmos de aprendizaje automático. En lugar de codificar manualmente grandes conjuntos de reglas, el NLP puede confiar en el aprendizaje automático para aprender estas reglas automáticamente analizando un conjunto de ejemplos y haciendo una inferencia estadística. En general, cuanto más datos analizados, más preciso será el modelo. Estos algoritmos pueden ser utilizados en algunas de las siguientes aplicaciones:
Resumir texto: Podemos utilizar los modelos de NLP para extraer las ideas más importantes y centrales mientras ignoramos la información irrelevante.
Crear chatbots: Podemos utilizar las técnicas de NLP para crear chatbots que puedan interactuar con las personas.
Generar automáticamente etiquetas de palabras clave: Con NLP también podemos realizar un análisis de contenido aprovechando el algoritmo de LDA para asignar palabras claves a párrafos del texto.
Reconocer entidades: Con NLP podemos identificar a las distintas entidades del texto como ser una persona, lugar u organización.
Análisis de sentimiento: También podemos utilizar NLP para identificar el sentimiento de una cadena de texto, desde muy negativo a neutral y a muy positivo.
Librerías de Python para Procesamiento del Lenguaje Natural
Actualmente, Python es uno de los lenguajes más populares para trabajar en el campo la Inteligencia Artificial. Para abordar los problemas relacionados con el Procesamiento del Lenguaje Natural Python nos proporciona las siguientes librerías:
NLTK: Es la librería líder para el Procesamiento del Lenguaje Natural. Proporciona interfaces fáciles de usar a más de 50 corpus y recursos léxicos, junto con un conjunto de bibliotecas de procesamiento de texto para la clasificación, tokenización, el etiquetado, el análisis y el razonamiento semántico.
TextBlob: TextBlob simplifica el procesamiento de texto proporcionando una interfaz intuitiva a NLTK. Posee una suave curva de aprendizaje al mismo tiempo que cuenta con una sorprendente cantidad de funcionalidades.
Stanford CoreNLP: Paquete desarrollado por la universidad de Stanford, para muchos constituye el estado del arte sobre las técnicas tradicionales de Procesamiento del Lenguaje Natural. Si bien esta escrita en Java, posee una interface con Python.
Spacy: Es una librería relativamente nueva que sobresale por su facilidad de uso y su velocidad a la hora de realizar el procesamiento de texto.
Textacy: Esta es una librería de alto nivel diseñada sobre Spacy con la idea de facilitar aun más las tareas relacionadas con el Procesamiento del Lenguaje Natural.
Gensim: Es una librería diseñada para extraer automáticamente los temas semánticos de los documentos de la forma más eficiente y con menos complicaciones posible.
pyLDAvis: Esta librería está diseñado para ayudar a los usuarios a interpretar los temas que surgen de un análisis de tópicos. Nos permite visualizar en forma muy sencilla cada uno de los temas incluidos en el texto.
Como veremos, el NLP también se está sumando a la popularidad del Deep Learning, por lo que muchos de los frameworks que se utilizan en Deep Learning pueden ser aplicados para realizar modelos de NLP.
Corpus lingüístico
Hoy en día, es indispensable el uso de buenos recursos lingüísticos para el desarrollo de los sistemas de NLP. Estos recursos son esenciales para la creación de gramáticas, en el marco de aproximaciones simbólicas; o para llevar a cabo la formación de módulos basados en el aprendizaje automático.
Un corpus lingüístico es un conjunto amplio y estructurado de ejemplos reales de uso de la lengua. Estos ejemplos pueden ser textos (los más comunes), o muestras orales (generalmente transcritas). Un corpus lingüístico es un conjunto de textos relativamente grande, creado independientemente de sus posibles formas o usos. Es decir, en cuanto a su estructura, variedad y complejidad, un corpus debe reflejar una lengua, o su modalidad, de la forma más exacta posible; en cuanto a su uso, preocuparse de que su representación sea real. La idea es que representen al lenguaje de la mejor forma posible para que los modelos de NLP puedan aprender los patrones necesarios para entender el lenguaje. Encontrar un buen corpus sobre el cual trabajar no suele ser una tarea sencilla; un corpus que se suele utilizar para entrenar modelos es el que incluye la información extraída de wikipedia.
Procesamiento del Lenguaje Natural con Python
Hasta aquí la introducción, ahora llegó el momento de ensuciarse un poco las manos y comenzar a explorar algunos ejemplos de las herramientas que nos ofrece Python para trabajar con problemas de Procesamiento del Lenguaje Natural. Comencemos por ejemplo, descargando el corpus de wikipedia en español. Esto lo podemos hacer fácilmente utilizando Textacy.
In [1]:
Ver Código
In [2]:
wp = Wikipedia(data_dir=’/home/raul/Documents/data’, lang=‘es’, version=‘latest’)
wp.download()
In [3]:
wp.info
Out[3]:
{‘data_dir’: ‘/home/raul/Documents/data’,
‘description’: ‘All articles for a given language- and version-specific Wikipedia site snapshot.’,
‘name’: ‘wikipedia’,
‘site_url’: ‘https://meta.wikimedia.org/wiki/Data_dumps’}
In [4]:
for text in wp.texts(min_len=1000, limit=2):
print(text[:375], “\n”)
Andorra
Andorra, oficialmente Principado de Andorra , es un pequeño país soberano del suroeste de Europa. Constituido en Estado independiente, de derecho, democrático y social, cuya forma de gobierno es el coprincipado parlamentario. Su territorio está organizado en siete parroquias, con una población total en 2016 de 78.264 habitantes. Su capital es Andorra la Vieja.
Ti
Argentina
La República Argentina, conocida simplemente como Argentina, es un país soberano de América del Sur, ubicado en el extremo sur y sudeste de dicho subcontinente. Adopta la forma de gobierno republicana, representativa y federal.
El Estado argentino es un Estado federal descentralizado, integrado por un Estado nacional y veintitrés estados provinciales autónomos
Como podemos ver, con la ayuda de Textacy es muy fácil descargar la información de wikipedia para luego poder utilizarla de base para nuestro corpus. Veamos otros problemas que también podemos resolver con la ayuda de Textacy; como ser los casos de detectar el idioma o de procesar todo un texto y analizarlo.
In [5]:
<h1>Detectando el idioma con taxtacy</h1>saludos = [“Hola”, “Hello”, “Bonjour”, “Guten Tag”, “Buon giorno”, “Bom dia”]
for saludo in saludos:
print(textacy.text_utils.detect_language(saludo))
es
en
fr
de
it
pt
In [6]:
nlp = textacy.data.spacy.load(‘es_core_web_md’)
In [7]:
stop = list(textacy.data.spacy.es.STOP_WORDS)
stop[:15]
Out[7]:
[‘cuanto’,
‘sera’,
‘trabajo’,
‘tan’,
‘ya’,
‘claro’,
‘encuentra’,
‘arriba’,
‘despacio’,
‘primero’,
‘pocas’,
‘tiempo’,
‘aquéllos’,
‘días’,
‘enseguida’]
In [8]:
texto = leer_texto(‘ORWELL_1984.txt’)
texto_procesado = nlp(texto)
In [9]:
sentencias = [s for s in texto_procesado.sents]
print(len(sentencias))
8114
In [10]:
print(sentencias[1:11])
[Winston Smith, con la barbilla clavada en el pecho en su esfuerzo por burlar el molestísimo viento, se deslizó rápidamente por entre las puertas de cristal de las Casas de la Victoria, aunque, no con la suficiente rapidez para evitar que una ráfaga polvorienta se colara con él.
, El vestíbulo olía a legumbres cocidas y a esteras viejas., Al fondo, un cartel de colores, demasiado grande para hallarse en un interior, estaba pegado a la pared., Representaba sólo un enorme rostro de más de un metro de anchura: la cara de un hombre de unos cuarenta y cinco años con un gran bigote negro y facciones hermosas y endurecidas., Winston se dirigió hacia las escaleras., Era inútil intentar subir en el ascensor., No funcionaba con frecuencia y en esta época la corriente se cortaba durante las horas de día., Esto era parte de las restricciones con que se preparaba la Semana del Odio., Winston tenía que subir a un séptimo piso.]
In [11]:
[sent for sent in texto_procesado.sents if ‘Gran Hermano’ in sent.string][-10:]
Out[11]:
[—¿Morirá el Gran Hermano?,
ael Gran Hermano.,
Pensó en el Gran Hermano.,
¿Cuáles eran sus verdaderos sentimientos hacia el Gran Hermano?,
Dime: ¿cuáles son los verdaderos sentimientos que te inspira el Gran Hermano?,
Tienes que amar ael Gran Hermano.,
l Gran Hermano.,
l Gran Hermano.,
Amaba ael Gran Hermano.
,
Hubiera sido posible, por ejemplo, decir el «Gran Hermano inbueno».]
In [12]:
Ver Código
In [13]:
print(encontrar_personajes(texto_procesado)[:20])
[(‘winston’, 686), (“o’brien”, 135), (‘julia’, 85), (‘partido’, 85), (‘parsons’, 36), (‘syme’, 29), (‘goldstein’, 29), (‘pensamiento’, 22), (‘odio’, 13), (‘ministerio’, 13), (’’, 11), (‘katharine’, 11), (‘winston ?’, 10), (‘rutherford’, 9), (‘ogilvy’, 8), (‘aaronson’, 8), (‘charrington’, 8), (’—la’, 7), (‘withers’, 6), (‘ingsoc’, 6)]
In [14]:
Ver Código
In [15]:
print(obtener_adj_pers(texto_procesado, “winston”))
[‘superior’, ‘separado’, ‘fuertes’, ‘abierto’, ‘oscura’, ‘dirigiéndose’, ‘negro’, ‘saltones’, ‘tristes’, ‘burlones’, ‘solo’, ‘humano’, ‘sostenemos’, ‘dubitativo’, ‘completa’, ‘definitiva’, ‘sobresaltado’, ‘fascinado’, ‘extraña’, ‘sobrado’, ‘propio’, ‘solos’, ‘joven’, ‘sorprendido’, ‘sorprendido’, ‘hermosa’, ‘breve’, ‘cortante’, ‘primera’, ‘junto’, ‘obediente’, ‘metafísico’, ‘blanca’, ‘sonriente’, ‘sentado’, ‘irresoluto’, ‘sumergido’, ‘feliz’]
In [16]:
Ver Código
In [17]:
personaje_verbo(texto_procesado, “dijo”)
Out[17]:
[(‘Winston’, 7),
(‘Julia’, 4),
(‘Syme’, 2),
(‘Julia—. Espera’, 1),
(‘Parsons’, 1),
(’—le’, 1)]
In [18]:
set(ent.label_ for ent in texto_procesado.ents)
Out[18]:
{‘CARDINAL’, ‘LOC’, ‘MISC’, ‘ORDINAL’, ‘ORG’, ‘PERSON’}
In [19]:
[ent for ent in texto_procesado.ents if ent.label_ == ‘ORG’][:10]
Out[19]:
[INGSOC,
Partido:,
ES LA,
Departamento de Registro,
Dos Minutos de Odio,
Departamento de Novela,
Partido Interior,
Partido Interior,
Departamento de Registro,
Dos Minutos]
In [20]:
set(token.pos_ for token in texto_procesado)
Out[20]:
{‘ADJ’,
‘ADP’,
‘ADV’,
‘AUX’,
‘CONJ’,
‘DET’,
‘INTJ’,
‘NOUN’,
‘NUM’,
‘PART’,
‘PRON’,
‘PROPN’,
‘PUNCT’,
‘SCONJ’,
‘SPACE’,
‘SYM’,
‘VERB’}
In [21]:
[token.orth_ for token in texto_procesado if token.pos_ == ‘ADJ’][1:11]
Out[21]:
[‘frío’,
‘clavada’,
‘molestísimo’,
‘suficiente’,
‘polvorienta’,
‘cocidas’,
‘viejas’,
‘grande’,
‘pegado’,
‘enorme’]
In [22]:
[token.orth_ for token in texto_procesado if token.pos_ == ‘PROPN’][1:11]
Out[22]:
[‘GEORGE’,
‘ORWELL’,
‘PARTE’,
‘CAPITULO’,
‘Winston’,
‘Smith’,
‘Casas’,
‘Victoria’,
‘Winston’,
‘Semana’]
Como demuestran estos ejemplos Textacy / Spacy son herramientas muy poderosas que nos pueden ayudar a analizar y obtener información valiosa de un texto en forma rápida y sencilla.
Deep Learning y Procesamiento del Lenguaje Natural
Durante mucho tiempo, las técnicas principales de Procesamiento del Lenguaje Natural fueron dominadas por métodos de aprendizaje automático que utilizaron modelos lineales como las máquinas de vectores de soporte o la regresión logística, entrenados sobre vectores de características de muy alta dimensional pero muy escasos. Recientemente, el campo ha tenido cierto éxito en el cambio hacia modelos de deep learning sobre entradas más densas.
Las redes neuronales proporcionan una poderosa maquina de aprendizaje que es muy atractiva para su uso en problemas de lenguaje natural. Un componente importante en las redes neuronales para el lenguaje es el uso de una capa de word embedding, una asignación de símbolos discretos a vectores continuos en un espacio dimensional relativamente bajo. Cuando se utiliza word embedding, se transforman los distintos símbolos en objetos matemáticos sobre los que se pueden realizar operaciones. En particular, la distancia entre vectores puede equipararse a la distancia entre palabras, facilitando la generalización del comportamiento de una palabra sobre otra. Esta representación de palabras como vectores es aprendida por la red como parte del proceso de entrenamiento. Subiendo en la jerarquía, la red también aprende a combinar los vectores de palabras de una manera que es útil para la predicción. Esta capacidad alivia en cierta medida los problemas de dispersión de los datos. Hay dos tipos principales de arquitecturas de redes neuronales que resultan muy útiles en los problemas de Procesamiento del Lenguaje Natural: las Redes neuronales prealimentadas y las Redes neuronales recurrentes.
Para ejemplificar, veamos como podemos utilizar word embedding utilizando el modelo word2vec de Gensim.
In [23]:
Ver Código
Using TensorFlow backend.
In [24]:
texto = [[str(palabra).lower() for palabra in sent if str(palabra) not in stop ]
for sent in sentencias]
diccionario = gensim.corpora.Dictionary(texto)
In [25]:
modelo = gensim.models.Word2Vec(texto, workers=4, size=100,
min_count=5, window=10, sample=1e-3)
In [26]:
modelo[‘hermano’]
Out[26]:
array([-0.22692642, -0.08890257, -0.12868501, -0.17392403, 0.22627664,
0.10127033, -0.09027202, 0.10692301, -0.30289358, 0.06429829,
0.17862263, 0.20448232, -0.54694331, -0.40681064, 0.61438572,
0.0217872 , 0.080202 , 0.46306548, 0.09076022, -0.02869571,
-0.46194851, 0.28670114, 0.38570273, 0.32555154, 0.13098474,
-0.03134775, -0.09577781, 0.06859019, -0.15935177, 0.61558241,
0.07509102, -0.24245416, -0.44668666, -0.77279037, 0.84581488,
-0.54047441, -0.18756895, -0.12506978, -0.52870399, 0.1898849 ,
-0.00930689, 0.36932173, 0.22370262, -0.67407966, -0.45509291,
-0.00848365, 0.62967575, 0.16172817, 0.09978516, 0.15064637,
-0.34957823, 0.20686783, 0.1038606 , -0.09155462, 0.08276461,
0.31154567, -0.3129864 , -0.45181432, -0.12060832, 0.30541465,
-0.37994722, 0.13566031, 0.16380484, 0.32732216, 0.15746659,
0.69340295, -0.25527388, 0.37333885, 0.23317885, -0.4710786 ,
-0.22506852, 0.14103019, -0.30253953, 0.00573605, -0.14745024,
-0.50815731, -0.37789851, -0.3400358 , 0.62753612, 0.04747195,
-0.07443633, 0.4276363 , -0.28931141, 0.29784235, -0.07251735,
-0.07709371, -0.1003265 , -0.29098341, 0.47159177, 0.41372281,
-0.10831725, -0.04670507, 0.07489309, 0.00146162, -0.02867368,
-0.2771121 , 0.37281424, -0.53325164, 0.19094327, 0.51455575], dtype=float32)
In [27]:
modelo.most_similar_cosmul(‘persona’)
Out[27]:
[(‘mano’, 0.9999627470970154),
(‘se’, 0.9999592304229736),
(‘mesa’, 0.9999556541442871),
(‘lo’, 0.999954879283905),
(‘podía’, 0.9999546408653259),
(‘personas’, 0.9999545812606812),
(‘habría’, 0.9999533891677856),
(‘sitio’, 0.9999532103538513),
(‘no’, 0.999953031539917),
(‘pero’, 0.999951958656311)]
In [28]:
vocab = list(modelo.wv.vocab)
X = modelo[vocab]
tsne = TSNE(n_components=2)
X_tsne = tsne.fit_transform(X)
df = pd.concat([pd.DataFrame(X_tsne),
pd.Series(vocab)],
axis=1)
df.columns = [‘x’, ‘y’, ‘palabra’]
In [29]:
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(1, 1, 1)
df_e = df.head(15)
ax.scatter(df_e[‘x’], df_e[‘y’])
for i, txt in enumerate(df_e[‘palabra’]):
ax.annotate(txt, (df_e[‘x’].iloc[i], df_e[‘y’].iloc[i]))
plt.show()
Aquí termina este artículo, obviamente el Procesamiento del Lenguaje Natural es un campo muy amplio y quedaron muchas cosas sin desarrollar. Espero que esta introducción les haya sido de utilidad.
Te recomiendo revisar: