Vous êtes sur la page 1sur 70

UNIVERSIDAD

POLITÉCNICA SALESIANA
Agosto de 2018

Jorge Soria

EDITORIAL
UNIVERSITAT POLITÈCNICA DE VALÈNCIA
Resumen

Es fácil tener en nuestras manos millones de palabras de texto. Qué podemos


hacer con eso, suponiendo que podamos escribir algunos programas simples ?
En este capítulo abordaremos las siguientes preguntas:

1. Qué podemos lograr al combinar técnicas simples de programación con


grandes cantidades de texto ?
2. Cómo podemos extraer automáticamente palabras clave y frases que
resumen el estilo y el contenido de un texto ?
3. Qué herramientas y técnicas proporciona el lenguaje de programación de
Python para dicho trabajo ?
4. Cuáles son algunos de los desafíos interesantes del procesamiento del len-
guaje natural ?

Este capítulo está dividido en secciones que saltan entre dos estilos bastante
diferentes. En las secciones de informática con lenguaje realizaremos algunas
tareas de programación motivadas linguística-mente sin explicar necesariamen-
te cómo funcionan. En las secciones de mirar más de cerca a Python, revisa-
remos sistemáticamente los conceptos clave de programación. Marcaremos los
dos estilos en los títulos de la sección, pero los capítulos posteriores mezclarán
ambos estilos sin ser tan directos al respecto. Esperamos que este estilo de
presentación le brinde un sabor auténtico de lo que vendrá después, mientras
cubre una variedad de conceptos elementales en lingà 14 ística e informática.

iii
Si tiene familiaridad básica con ambas áreas, puede saltar a 5; repetiremos
cualquier punto importante en capítulos posteriores, y si pierde algo, puede
consultar fácilmente el material de referencia en línea en la web:
https://www.nltk.org/book/ch01.html

Esperamos que te sea útil este documento de ejemplo.

Jorge Soria
jsoria@est.ups.edu.ec

iv
ï¿ 12 ndice general

Resumen iii

ï¿ 12 ndice general v

1 Computación con lenguaje: textos y palabras 1


1.1 Primeros pasos con Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Comenzando con NLTK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Búsqueda de texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4 Contando Vocabulario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2 Una mirada más de cerca a Python:


textos como listas de palabras 15
2.1 Listas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2 Listas de indexación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.3 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.4 Cuerdas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

v
ï¿ 12 ndice general

3 Computación con lenguaje:


estadísticas simples 25
3.1 Distribuciones de frecuencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.2 SelecciÃ3 nf inadepalabras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3 Colocaciones y Bigrams. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.4 Contando otras cosas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

4 Volver a Python:
tomar decisiones y tomar el control 35
4.1 Condicionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.2 Operando en cada elemento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.3 Bloques de código anidados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.4 Bucle con condiciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

5 Comprensión automática del lenguaje natural 43


5.1 Desambiguación de sentido de palabra . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.2 Resolución del pronombre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.3 Generación de salida de idioma. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.4 Traducción automática . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.5 Sistemas de diálogo hablado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.6 Entailment textual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.7 Limitaciones de NLP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

6 Resumen 53

7 Lectura adicional 55

8 Ejercicios 57

vi
Capítulo 1

Computación con lenguaje:


textos y palabras

Todos estamos muy familiarizados con el texto, ya que lo lee-


mos y escribimos todos los días. Aquí trataremos el texto como
datos en bruto para los programas que escribimos, programas que
lo manipulan y lo analizan en una variedad de formas interesantes.
Pero antes de que podamos hacer esto, tenemos que comenzar con
el intérprete de Python.

1.1 Primeros pasos con Python

Una de las cosas más amigables de Python es que te permite escribir directa-
mente en el intérprete interactivo , el programa que ejecutará tus programas de
Python. Puede acceder al intérprete de Python utilizando una interfaz gráfica
simple llamada Interactive DeveLopment Environment (IDLE). En una Mac,
puede encontrar esto en Aplicaciones = MacPython, y en Windows en Todos
los programas = Python. En Unix, puede ejecutar Python desde el shell al
escribir inactivo (si no está instalado, intente escribir Python ). El intérprete
imprimirá una propaganda sobre su versión de Python; simplemente comprue-
be que está ejecutando Python 3.2 o posterior (aquí está para 3.4.2):

1
Capítulo 1. Computación con lenguaje: textos y palabras

Python 3.4.2 (predeterminado, 15deoctubrede2014, 22 : 01 : 37)


[GCC4,2,1AppleLLV M 5,1compatible(clang − 503,0,40)] endarwin
Escriba”ayuda”, ”derechosdeautor”, ”crditos”o”licencia”paraobtener
msinf ormacin. >>>

Nota
Si no puede ejecutar el intérprete de Python, probablemente no tenga
instalado Python correctamente. Visite http://python.org/ para obtener
instrucciones detalladas. NLTK 3.0 funciona para Python 2.6 y 2.7. Si
está utilizando una de estas versiones anteriores, tenga en cuenta que el
operador / redondea los resultados fraccionarios hacia abajo (por lo que
1/3 le dará 0 ). Para obtener el comportamiento esperado de la división,
debe escribir: desde la división de importación –future–

El indicador  indicaqueelintrpretedeP ythonestesperandolaentrada.


Alcopiarejemplosdeestelibro, noescriba”  ”ustedmismo.Ahora,
comencemosusandoP ythoncomounacalculadora :

 1 + 5 ∗ 2 − 3
8


Una vez que el intérprete ha terminado de calcular la respuesta y mostrarla,


vuelve a aparecer el mensaje. Esto significa que el intérprete de Python está
esperando otra instrucción.

Nota
Tu turno: ingresa algunas expresiones máás tuyas. Puede usar el as-
terisco ( * ) para la multiplicación y la barra inclinada ( / ) para la
división, y los paréntesis para las expresiones de horquillado.

Los ejemplos anteriores demuestran cómo puede trabajar interactivamente con


el intérprete de Python, experimentando con diversas expresiones en el idioma
para ver lo que hacen. Ahora probemos una expresión sin sentido para ver
cómo lo maneja el intérprete:

2
1.2 Comenzando con NLTK

 1 +
Archivo” < stdin > ”, lnea1
1+
SintaxisError:sintaxisnovlida

Esto produjo un error de sintaxis . En Python, no tiene sentido terminar una


instrucción con un signo más. El intérprete de Python indica la línea donde
ocurrió el problema (línea 1 de <stdin>, que significa .entrada estándar").
Ahora que podemos usar el intérprete de Python, estamos listos para comenzar
a trabajar con los datos del lenguaje.

1.2 Comenzando con NLTK

Antes de continuar, debe instalar NLTK 3.0, que se puede descargar de manera
gratuita desde http://nltk.org/ . Siga las instrucciones allí para descargar la
versión requerida para su plataforma.
Una vez que haya instalado NLTK, inicie el intérprete de Python como antes e
instale los datos necesarios para el libro escribiendo los dos comandos siguien-
tes en el indicador de Python, luego seleccione la colección de libros como se
muestra en secciï¿ 12 n 1.1.

 importnltk
 nltk.download()

Una vez que los datos se descargan en su máquina, puede cargar algunos usando
el intérprete de Python. El primer paso es escribir un comando especial en el
indicador de Python que le dice al intérprete que cargue algunos textos para
que podamos explorar: desde nltk.book import * . Esto dice "del módulo de
libros de NLTK , cargue todos los artículos". El módulo del libro contiene
todos los datos que necesitará mientras lee este capítulo. Después de imprimir
un mensaje de bienvenida, carga el texto de varios libros (esto llevará unos
segundos). Aquí está el comando nuevamente, junto con la salida que verá.
Tenga cuidado de obtener la ortografía y la puntuación correctas, y recuerde
que no escribe  .

3
Capítulo 1. Computación con lenguaje: textos y palabras

Figura 1.1: Descarga de la colección de libros NLTK: explore los paquetes disponibles usan-
do nltk.download () . La pestania Colecciones en el descargador muestra cómo se agrupan
los paquetes en conjuntos, y debe seleccionar la línea etiquetada como libro para obtener
todos los datos necesarios para los ejemplos y ejercicios de este libro. Consiste en aproxi-
madamente 30 archivos comprimidos que requieren aproximadamente 100Mb de espacio en
disco. La colección completa de datos (es decir, todo en el programa de descarga) es casi diez
veces más grande (en el momento de redactar este documento) y continúa expandiéndose.

 f romnltk.bookimport ∗
∗ ∗ ∗ Ejemplosdeintroducci3 nparaellibroN LT K ∗ ∗ ∗
Cargandotexto1, ..., texto9yenviado1, ..., enviado9
Escribaelnombredeltextoof raseparaverlo.
Escriba :0 texts()0 o0 sents()0 paraenumerarlosmateriales.
texto1 : M obyDickdeHermanM elville1851
texto2 : SentidoysensibilidaddeJaneAusten1811
text3 : EllibrodelGnesis
texto4 : DiscursoinauguralCorpus
text5 : ChatCorpus
text6 : Loscaballerosdelamesacuadrada
text7 : W allStreetJournal
text8 : ContactosCorpus
text9 : Elhombrequef uejuevesporG.K.Chesterton1908


Siempre que deseamos conocer estos textos, solo debemos ingresar sus nombres
en el indicador de Python:

4
1.3 Búsqueda de texto

 text1
< T exto : M obyDickporHermanM elville1851 >
 text2
< T ext : sentidoysensibilidadporJaneAusten1811 >


Ahora que podemos usar el intérprete de Python y tener algunos datos para
trabajar, estamos listos para comenzar.

1.3 Búsqueda de texto

Hay muchas maneras de examinar el contexto de un texto además de sim-


plemente leerlo. Una vista de concordancia nos muestra cada ocurrencia de
una palabra dada, junto con algún contexto. Aquí buscamos la palabra mons-
truosa en Moby Dick al ingresar texto1 seguido de un punto, luego el término
concordancia , y luego colocamos "monstruoso.entre paréntesis:

5
Capítulo 1. Computación con lenguaje: textos y palabras

 text1.concordance(”monstrous”)
M ostrando11de11coincidencias :
onglaprimera, unaeradeuntama ± oms
monstruoso....Estovinohacianosotros,
ON OF T HEP SALM S.”T ocandoesemonstruosobultode
laballenauorco, hemos
terminadoconunapandillapaganademonstruosos
garrotesylanzas.Algunosestabangruesos
mientrasmirabas, ytepreguntabasqu
monstruoso
canbalysalvajepodrahaber
sobrevividoalainundacin; monstruosoyms
monta ± oso!P araHimmal
podranexploraraM obyDickcomounaf bula
monstruosa, opeoranymsde
Radney”.CAP T U LO55Delasmonstruosas
ImgenesdelasBallenas.Estarerel
ingEscenas.Enrelacinconlasimgenes
monstruosasdelasballenas, estoymuy
dispuestoaentrarenaquellashistoriasan
msmonstruosasdelasquese
handescubiertoquehansidosacadasdeeste
monstruosogabinete.P ero
deW hale − Bones; porquelasballenasdeuntamanio
monstruososonamenudoarrojadasmuertas


La primera vez que usa una concordancia en un texto en particular, toma


unos segundos más construir un índice para que las búsquedas posteriores
sean rápidas

6
1.3 Búsqueda de texto

Nota
Su turno: intente buscar otras palabras; para guardar el reescrito, es
posible que pueda utilizar la flecha hacia arriba, la flecha hacia arriba o
Alt-p para acceder al comando anterior y modificar la palabra que se bus-
ca. También puede intentar buscar en algunos de los otros textos que he-
mos incluido. Por ejemplo, busque Sense and Sensibility para la palabra
afecto , usando text2.concordance ( .afecto") . Busque el libro de Génesis
para saber cuánto vivieron algunas personas, usando text3.concordance
( "vivido") . Puedes ver el texto 4 , el Corpus Inaugural Address Corp
, para ver ejemplos de inglés que data de 1789, y buscar palabras como
nation ,terror , dios para ver cómo estas palabras se han usado de manera
diferente a lo largo del tiempo. También hemos incluido text5 , el NPS
Chat Corpus : busque palabras poco convencionales como im , ur , lol .
(Tenga en cuenta que este corpus no tiene censura!)

Una vez que haya dedicado un poco de tiempo a examinar estos textos, espe-
ramos que tenga un nuevo sentido de la riqueza y la diversidad del lenguaje.
En el siguiente capítulo, aprenderá cómo acceder a un rango más amplio de
texto, incluido el texto en otros idiomas además del inglés.
Una concordancia nos permite ver palabras en contexto. Por ejemplo, vimos
que lo monstruoso ocurría en contextos como las – imágenes y un – tamano .
Qué otras palabras aparecen en un rango similar de contextos ?
Podemos averiguar agregando el término similar al nombre del texto en cues-
tión, luego insertando la palabra relevante entre paréntesis:

 text1.similar(”monstrous”)
meanpartemaddensdolef ulgamesomesutilmentepoco
comedidocuidadosoadverso
exasperatelovingpassingmohosocristianopocostruemistif ying
imperialmodif icadespreciable
 text2.similar(”monstrous”)
muycordialmentetanextraordinariamentetan
grandecomoungranincreblemente
extremadamentebuenodulce


Observe que obtenemos diferentes resultados para diferentes textos. Austen


usa esta palabra bastante diferente de Melville; para ella, monstruoso tiene

7
Capítulo 1. Computación con lenguaje: textos y palabras

connotaciones positivas, y a veces funciona como un intensificador como la pa-


labra muy .
El término common-contexts nos permite examinar solo los contextos que com-
parten dos o más palabras, como monstruoso y muy . Tenemos que incluir estas
palabras entre corchetes y paréntesis, y separarlas con una coma:

 text2.commonc ontexts([”monstrous”, ”very”]))


ap rettyisp rettyamg ladbeg ladal ucky


Nota
Su turno: elija otro par de palabras y compare su uso en dos textos
diferentes, usando las funciones similar () y common-contexts () .

Una cosa es detectar automáticamente que una palabra en particular ocurre en


un texto y mostrar algunas palabras que aparecen en el mismo contexto. Sin
embargo, también podemos determinar la ubicación de una palabra en el tex-
to: cuántas palabras aparecen desde el principio. Esta información posicional
puede mostrarse utilizando un diagrama de dispersión . Cada franja represen-
ta una instancia de una palabra, y cada fila representa el texto completo. En
figura 3.2 vemos algunos patrones llamativos de uso de la palabra en los últi-
mos 220 anos (en un texto artificial construido al unir los textos del Corpus
Inaugural Address Corp de extremo a extremo). Puede producir esta gráfica
como se muestra a continuación. Puede intentar más palabras (por ejemplo,
libertad , constitución) y diferentes textos. ¿Puedes predecir la dispersión de
una palabra antes de verla? Como antes, tenga cuidado de obtener las comillas,
comas, corchetes y paréntesis exactamente correctos.

 text4.dispersionp lot([”ciudadanos”, ”democracia”, ”libertad”, ”deberes”, ”Amrica




Nota
Importante: debe tener instalados los paquetes NumPy y Matplotlib
de Python para generar los gráficos utilizados en este libro. Por favor,
consulte http://nltk.org/ para obtener instrucciones de instalación.

8
1.3 Búsqueda de texto

Figura 1.2: Gráfico de dispersión léxica para palabras en las direcciones iniciales presiden-
ciales de EE. UU .: Esto se puede utilizar para investigar los cambios en el uso del lenguaje
a lo largo del tiempo.

Nota
También puede trazar la frecuencia del uso de las palabras a través del
tiempo utilizando https://books.google.com/ngrams

Ahora, solo por diversión, intentemos generar texto aleatorio en los diversos
estilos que acabamos de ver. Para hacer esto, escribimos el nombre del texto
seguido del término generar . (Necesitamos incluir los paréntesis, pero no hay
nada que los interrumpa).

9
Capítulo 1. Computación con lenguaje: textos y palabras

 text3.generate()
Enelcomienzodesuhermanoesunhombrepeludo, cuyacimapuedellegar
alcielo; ysembrarslatierradeEgipto, nohubopanen
todoloquef uesacadodelmes, sobrelatierra.Entonces, sertu
salario?Ehicieronasupadre; eIsaaceraviejo, y
lo
bes, yLabnconsuganadoenmediodelasmanosdeEsatuprimognito, yF icol, elprincipal
mayordomodesuhijoIsaac, ella


Nota
El método generate () no está disponible en NLTK 3.0, pero se restable-
cerá en una versión posterior.

1.4 Contando Vocabulario

El hecho más obvio sobre textos que surge de los ejemplos anteriores es que
difieren en el vocabulario que usan. En esta sección veremos cómo usar la
computadora para contar las palabras en un texto en una variedad de formas
útiles. Como antes, saltará directamente y experimentará con el intérprete de
Python, aunque es posible que todavía no haya estudiado Python sistemática-
mente. Ponga a prueba su comprensión modificando los ejemplos y probando
los ejercicios al final del capítulo.
Comencemos por conocer la longitud de un texto de principio a fin, en términos
de las palabras y los símbolos de puntuación que aparecen. Usamos el término
len para obtener la longitud de algo, que aplicaremos aquí al libro de Génesis:

 len(text3)
44764


Así que Génesis tiene 44,764 palabras y símbolos de puntuación, o "tokens".


Un token es el nombre técnico de una secuencia de caracteres, como hairy ,
his o :) , que queremos tratar como un grupo. Cuando contamos el número de
tokens en un texto, por ejemplo, la frase ser o no ser , estamos contando las
ocurrencias de estas secuencias. Por lo tanto, en nuestro ejemplo la frase hay

10
1.4 Contando Vocabulario

dos ocurrencias de a , dos de estar , y uno cada uno de o y no. Pero solo hay
cuatro elementos distintos de vocabulario en esta frase. ¿Cuántas palabras
distintas contiene el libro de Génesis? Para resolver esto en Python, tenemos
que plantear la pregunta de forma ligeramente diferente. El vocabulario de un
texto es solo el conjunto de tokens que utiliza, ya que en un conjunto, todos los
duplicados se contraen juntos. En Python podemos obtener los elementos de
vocabulario de text3 con el comando: set (text3) . Cuando hagas esto, pasarán
muchas pantallas de palabras. Ahora prueba lo siguiente:

 ordenado(conjunto(texto3))[1]
[0 !0 , ”0 ”,0 (0 ,0 )0 ,0 ,0 ,0 , )0 ,0 .0 ,0 .)0 ,0 :0 ,0 ;0 ,0 ; )0 ,0 ?0 ,0 ?)0 , 0 A0 ,0 Abel0 ,0 Abelmizraim0 ,0 Abidah0 ,0 A
 len(set(text3))[2]
2789


Envolviendo ordenados () en torno a la expresión de Python establecido (text3)


[1] , se obtiene una lista ordenada de elementos de vocabulario, a partir de va-
rios signos de puntuación y continuando con palabras que empiecen con A .
Todas las palabras en mayúscula preceden a las minúsculas. Descubrimos el
tama±o del vocabulario indirectamente, preguntando por el número de ele-
mentos en el conjunto, y de nuevo podemos usar len para obtener este número
[2]. A pesar de que tiene 44,764 fichas, este libro tiene solo 2,789 palabras dis-
tintas, o "tipos de palabras". Un tipo de palabra es la forma u ortografía de
la palabra independientemente de sus ocurrencias específicas en un texto, es
decir, la palabra considerada como un elemento único de vocabulario. Nuestro
recuento de 2.789 ítems incluirá símbolos de puntuación, por lo que general-
mente llamaremos a estos tipos de ítems exclusivos en lugar de a los tipos de
palabras.
Ahora, calculemos una medida de la riqueza léxica del texto. El siguiente ejem-
plo nos muestra que el número de palabras distintas es solo el 6 por-ciento del
número total de palabras, o equivalentemente que cada palabra se usa 16 veces
en promedio(recuerde que si está usando Python 2, empiece desde –future–
división de importación)

 len(set(text3))/len(text3)
0,06230453042623537


11
Capítulo 1. Computación con lenguaje: textos y palabras

Luego, centrémonos en palabras particulares. Podemos contar la frecuencia con


que aparece una palabra en un texto y calcular qué porcentaje del texto toma
una palabra específica:

 text3.count(”smote”)
5
 100 ∗ text4.count(0 a0 )/len(text4)
1,4643016433938312


Nota
Tu turno: Cuántas veces aparece la palabra jaja en el texto5 ? Cuánto
es esto como un porcentaje de la cantidad total de palabras en este texto
?

Es posible que desee repetir dichos cálculos en varios textos, pero es tedio-
so seguir volviendo a escribir la fórmula. En su lugar, puede crear su propio
nombre para una tarea, como "lexical-diversity.o "percentage", y asociarlo con
un bloque de código. Ahora solo tiene que escribir un nombre corto en lugar
de una o más líneas completas de código Python, y puede volver a utilizarlo
tantas veces como desee. El bloque de código que nos hace una tarea se llama
función , y definimos un nombre corto para nuestra función con la palabra
clave def . El siguiente ejemplo muestra cómo definir dos nuevas funciones,
lexical-diversity () y percentage () :

 def lexicald iversity(texto) : [1]


...devolverlen(set(texto))/len(texto)[2]
...
 def porcentaje(recuento, total) : [3]
...devuelve100 ∗ cuentas/total
...

Precaución!
El intérprete de Python cambia la solicitud de 
adespusdeencontrarlosdospuntosalf inaldelaprimeralnea.ElindicaqueP ythonesperaquea

12
1.4 Contando Vocabulario

En la definición de lexical-diversity () [1] , especificamos un parámetro llama-


do text . Este parámetro es un "marcador de posición"para el texto real cuya
diversidad léxica queremos calcular, y vuelve a aparecer en el bloque de código
que se ejecutará cuando se use la función[2] . De forma similar, el porcentaje
() se define para tomar dos parámetros, llamados count y total [3] .
Una vez que Python sabe que lexical-diversity () y percentage () son los nom-
bres para bloques específicos de código, podemos seguir adelante y usar estas
funciones:

 lexicald iversity(text3)


0,06230453042623537
 lexicald iversity(text5)
0,13477005109975562
 porcentaje(4, 5)
80,0
 porcentaje(text4.count(0 a0 ), len(text4))
1,4643016433938312


Para recapitular, usamos o llamamos a una función como lexicaldiversity ()


escribiendo su nombre, seguido de un paréntesis abierto, el nombre del texto y
luego un paréntesis de cierre. Estos paréntesis aparecerán a menudo; su función
es separar el nombre de una tarea, como lexicaldiversity () , de los datos en los
que se realizará la tarea, como text3 . El valor de datos que colocamos entre
paréntesis cuando llamamos a una función es un argumento para la función.
Ya ha encontrado varias funciones en este capítulo, como len () , set () y sorted
() . Por convención, siempre agregaremos un par de paréntesis vacíos después
de un nombre de función, como en len () , solo para aclarar que estamos ha-
blando de una función en lugar de algún otro tipo de expresión de Python.
Las funciones son un concepto importante en la programación, y solo las men-
cionamos desde el principio para dar a los recién llegados una idea del poder
y la creatividad de la programación. No se preocupe si lo encuentra un poco
confuso en este momento.
Más adelante veremos cómo usar funciones al tabular datos, como ensecciï¿ 12 n 1.1
. Cada fila de la tabla implicará el mismo cálculo pero con diferentes datos, y
haremos este trabajo repetitivo usando una función.
Tabla1.1 Diversidad léxica de varios géneros en el corpus marrón

13
Capítulo 1. Computación con lenguaje: textos y palabras

Género Tokens Tipos Diversidad léxica


habilidad y pasatiempos 82345 11935 0.145
humor 21695 5017 0.231
ficción: ciencia 14470 3233 0.223
prensa: reportaje 100554 14394 0.143
ficción: romance 70022 8452 0.121
religión 39399 6373 0.162

14
Capítulo 2

Una mirada más de cerca a


Python:
textos como listas de palabras

Has visto algunos elementos importantes del lenguaje de programación Python.


Tomemos unos momentos para revisarlos sistemáticamente.

2.1 Listas

Qué es un texto? En un nivel, es una secuencia de símbolos en una página


como esta. En otro nivel, es una secuencia de capítulos, compuesta por una
secuencia de secciones, donde cada sección es una secuencia de párrafos, y así
sucesivamente. Sin embargo, para nuestros propósitos, pensaremos en un texto
como nada más que una secuencia de palabras y signos de puntuación. Así es
como representamos el texto en Python, en este caso, la frase de apertura de
Moby Dick :

15
Capítulo 2. Una mirada más de cerca a Python:
textos como listas de palabras

 sent1 = [0 Llamar0 ,0 m0 ,0 Ishmael0 ,0 .0 ]




Después del mensaje que hemos dado, inventamos send1 , seguido del signo
igual y luego algunas palabras entre comillas, separadas por comas y rodeadas
de corchetes. Este material entre corchetes se conoce como una lista en Python:
es la forma en que almacenamos un texto. Podemos inspeccionarlo escribiendo
el nombre[1] . Podemos preguntar su longitud [2]. Incluso podemos aplicar
nuestra propia lexical-diversity () la función a ella [3].

 sent1[1]
Llamar’, ’mÃ’, ’Ishmael’, ’.’

 len(sent1)[2]
4
 lexicald iversity(sent1)[3]
1,0


Se han definido algunas listas más para usted, una para la frase inicial de cada
uno de nuestros textos, sent2 ... sent9 . Inspeccionamos dos de ellos aquí; puede
ver el resto usted mismo usando el intérprete de Python (si obtiene un error que
dice que sent2 no está definido, primero debe escribir desde nltk.book import
∗ ).

 sent2
The’, ’family’, ’of’, ’Dashwood’, ’had’, ’long’,
’been’, ’settle’, ’in’, ’Sussex’, ’.’

 sent3
’, ’the’, ’beginning’, ’God’, ’created’, ’the’,
’heaven’, ’y’, ’the’, ’earth’, ’.’



16
2.1 Listas

Nota
Su Turno: Haga algunas oraciones propias, escribiendo un nombre, signo
igual y una lista de palabras, como esta: ex1 = [ ’Monty’ , ’Python’ , ’y’
, ’el’ , ’Santo ’ , ’ Grail ’ ] . Repite algunas de las otras operaciones de
Python que vimos anteriormente en 1 , por ejemplo, ordenadas (ex1) ,
len (set (ex1)) , ex1.count ( ’the’ ) .

Una agradable sorpresa es que podemos usar el operador de adición de Python


en las listas. Al agregar dos listas, se [1]crea una nueva lista con todo de la
primera lista, seguido de todo de la segunda lista:

 [0 M onty 0 ,0 P ython0 ] + [0 y 0 ,0 el0 ,0 Santo0 ,0 Grail0 ][1]


Monty Python y el Santo Grial’



Nota
Este uso especial de la operación de adición se denomina concatenación ;
combina las listas en una sola lista. Podemos concatenar oraciones para
construir un texto.

No tenemos que escribir literalmente las listas tampoco; podemos usar nombres
cortos que hacen referencia a listas predefinidas.

 enviado4 + enviado1


Companero’, ’-’, ’Ciudadanos’, ’de’, ’el’, ’Senado’, ’y’, ’de’, ’el’,
’Casa’, ’de’ , ’Representantes’, ’:’, ’Llamar’, ’mÃ’, ’Ismael’, ’.’



Qué sucede si queremos agregar un solo elemento a una lista? Esto se conoce
como agregar . Cuando agregamos () a una lista, la lista se actualiza como
resultado de la operación.

17
Capítulo 2. Una mirada más de cerca a Python:
textos como listas de palabras

 sent1.append(”Some”)
 sent1
Call’, ’me’, ’Ishmael’, ’.’, ’Some’



2.2 Listas de indexación

Como hemos visto, un texto en Python es una lista de palabras, representadas


mediante una combinación de corchetes y comillas. Al igual que con una página
ordinaria de texto, podemos contar el número total de palabras en texto1 con
len (texto1) y contar las ocurrencias en un texto de una palabra particular,
digamos, çielo", usando text1.count ( ’ cielo ’ ) .

Con un poco de paciencia, podemos elegir la primera, 173Âa o incluso 14.278Âa


palabra en un texto impreso. Análogamente, podemos identificar los elementos
de una lista de Python por su orden de aparición en la lista. El número que
representa esta posición es el índice del artículo . Instruimos a Python para
que nos muestre el elemento que aparece en un índice como 173 en un texto al
escribir el nombre del texto seguido del índice entre corchetes:

 text4[173]
0
despertar0


Podemos hacer lo contrario; dada una palabra, encuentre el índice de cuándo


aparece por primera vez:

 text4(0 despertar0 )


173


Los índices son una forma común de acceder a las palabras de un texto o, más
en general, a los elementos de cualquier lista. Python también nos permite
acceder a sublistas, extrayendo fragmentos de lenguaje manejables a partir de
textos grandes, una técnica conocida como cortar .

18
2.2 Listas de indexación

Los índices tienen algunas sutilezas, y las exploraremos con la ayuda de una
oración artificial:

 enviado = [0 palabra10 ,0 palabra20 ,0 palabra30 ,0 palabra40 ,0 palabra50 ,


...0 palabra60 ,0 palabra70 ,0 palabra80 ,0 palabra90 ,0 palabra100 ]
 enviado[0]
0
word10
 enviado[9]
0
word100


Observe que nuestros índices comienzan desde cero: el elemento enviado cero,
escrito enviado [0] , es la primera palabra, ’palabra1’ , mientras que el elemento
enviado 9 es ’palabra10’ . La razón es simple: en el momento en que Python
accede al contenido de una lista desde la memoria de la computadora, ya está
en el primer elemento; tenemos que decirle cuántos elementos avanzará. Por lo
tanto, cero pasos hacia delante lo deja en el primer elemento.

Nota
Esta práctica de contar desde cero es inicialmente confusa, pero típica
de los lenguajes de programación modernos. Lo dominará rápidamente si
domina el sistema de contar siglos en los que 19XY es un ano en el siglo
XX, o si vive en un país donde los pisos de un edificio están numerados
de 1, y así caminar hasta n-1 tramos de escaleras lo llevan al nivel n .

Ahora, si accidentalmente usamos un índice que es demasiado grande, obtene-


mos un error:

 enviado[10]
T raceback(o ltimallamadamsreciente) :
Archivo” < stdin > ”, lnea1, en?
IndexError : listaelndicef ueraderango


Esta vez no es un error de sintaxis, porque el fragmento del programa es sintác-


ticamente correcto. En cambio, es un error de tiempo de ejecución y produce un

19
Capítulo 2. Una mirada más de cerca a Python:
textos como listas de palabras

mensaje de seguimiento que muestra el contexto del error, seguido del nombre
del error, error de índice y una breve explicación.
Echemos un vistazo más de cerca a cortar, usando nuestra oración artificial
nuevamente. Aquí verificamos que la porción 5: 8 incluye elementos enviados
en los índices 5, 6 y 7:

 enviado[5 : 8]
word6’, ’word7’, ’word8’

 enviado[5]
0
word60
 enviado[6]
0
word70
 enviado[7]
0
word80


Por convención, m: n significa elementos m ... n-1 . Como muestra el siguiente


ejemplo, podemos omitir el primer número si el segmento comienza al comienzo
de la lista[1] , y podemos omitir el segundo número si el segmento se va al final
[2]:

 enviado[: 3][1]


word1’, ’word2’, ’word3’

>>> text2[141525 :][2]


entre’, ’el’, ’mà ritos’,
c ’y’, ’el’, ’felicidad’, ’de’, ’Elinor’, ’y’, ’Marianne’,
’,’, ’dejar’, ’ it ’,’ not ’,’ be ’,’ rank ’,’ as ’,’ the ’,’ least ’,’ considerable
’,’, ’,
’ that ’,’ though ’,’ sisters ’,’, ’ , ’y’, ’vivir’, ’casi’, ’dentro’, ’vista’, ’de’,
’cada’, ’otro’, ’,’, ’ellos’, ’podrÃan’, ’vivir’, ’ sin ’,’ desacuerdo ’,’ entre ’,
’ ellos mismos ’,’, ’,’ o ’,’ productores ’,’ frialdad ’,’ entre ’,’ sus ’,’ maridos
’,’.’,
’THE’, ’END’



20
2.3 Variables

Podemos modificar un elemento de una lista asignando uno de sus valores de


índice. En el siguiente ejemplo, ponemos enviado [0] a la izquierda del signo
igual [1]. También podemos reemplazar una porción entera con material nuevo
[2]. Una consecuencia de este último cambio es que la lista solo tiene cuatro
elementos, y el acceso a un valor posterior genera un error [3].

 enviado[0] =0 P rimero0 [1]


 enviado[9] =0 ltimo0
 len(enviado)
10
 enviado[1 : 9] = [0 Segundo0 ,0 T ercero0 ][2]
 enviado
Primero’, ’Segundo’, ’Tercero’, ’Ãltimo’

 enviado[9][3]
Rastreo(o ltimallamadamsreciente) :
Archivo” < stdin > ”, lnea1, en?
IndexError : listaelndicef ueraderango


Nota
Tu turno: tómate unos minutos para definir tu propia oración y modi-
ficar palabras individuales y grupos de palabras (rebanadas) usando los
mismos métodos que antes. Compruebe su comprensión al intentar los
ejercicios en las listas al final de este capítulo.

2.3 Variables

Desde el comienzo de 1 , ha tenido acceso a textos llamados text1 , text2 ,


etc. Se guardó una gran cantidad de tipeo para poder referirse a un libro de
250,000 palabras con un nombre corto como este
!

En general, podemos inventar nombres para cualquier cosa que nos interese
calcular. Lo hicimos nosotros mismos en las secciones anteriores, por ejemplo,
definiendo una variable enviada1 , de la siguiente manera:

21
Capítulo 2. Una mirada más de cerca a Python:
textos como listas de palabras

 sent1 = [0 Llamar0 ,0 m0 ,0 Ishmael0 ,0 .0 ]




Tales líneas tienen la forma: variable = expresión . Python evaluará la expresión


y guardará su resultado en la variable. Este proceso se llama asignación .
No genera ninguna salida; debe escribir la variable en una línea propia para
inspeccionar su contenido. El signo igual es ligeramente enganoso, ya que la
información se mueve del lado derecho al izquierdo. Podría ayudar pensar en
ello como una flecha izquierda. El nombre de la variable puede ser lo que
quieras, por ejemplo, my-sent , sentence , xyzzy . Debe comenzar con una
letra, y puede incluir números y guiones bajos. Aquí hay algunos ejemplos de
variables y asignaciones:

0
 mys ent = [0 Bravely 0 ,0 bold0 ,0 Sir0 ,0 Robin0 ,0 ,0 ,0 mont3 ,
...0 f orth0 ,0 f rom0 ,0 Camelot0 ,0 .0 ]
 nounp hrase = mys ent[1 : 4]
 nounp hrase
bold’, ’Sir’, ’Robin’

 wOrDs = ordenado(nounp hrase)


 wOrDs
Robin’, ’Sir’, ’bold’



Recuerde que las palabras en mayúscula aparecen antes que las minúsculas en
las listas ordenadas.

Nota
Observe en el ejemplo anterior que dividimos la definición de my-sent en
dos líneas. Las expresiones de Python se pueden dividir en varias líneas,
siempre que esto ocurra dentro de cualquier tipo de corchetes. Python
usa el indicador "... "para indicar que se espera más entrada. No importa
cuánta indentación se use en estas líneas de continuación, pero algunas
sangrías generalmente las hacen más fáciles de leer.

Es bueno elegir nombres de variables significativos para recordarle a usted, y


para ayudar a cualquier persona que lea su código de Python, qué debe hacer

22
2.3 Variables

su código. Python no intenta dar sentido a los nombres; sigue ciegamente tus
instrucciones y no se opone si haces algo confuso, como uno = ’dos’ o dos = 3
. La única restricción es que un nombre de variable no puede ser ninguna de
las palabras reservadas de Python, como def , if , not e import . Si usa una
palabra reservada, Python producirá un error de sintaxis:

 no =0 Camelot0
Archivo” < stdin > ”, lnea1
no =0 Camelot0
SintaxisError:sintaxisnovlida

A menudo usaremos variables para mantener los pasos intermedios de un cálcu-


lo, especialmente cuando esto hace que el código sea más fácil de seguir. Así
len (set (text1)) también podría escribirse:

 vocabulario = set(text1)


 vocabs ize = len(vocab)
 vocabs ize
19317


Precaución
!

Tenga cuidado con su elección de nombres (o identificadores ) para las


variables de Python. Primero, debe comenzar el nombre con una letra,
opcionalmente seguida de dígitos ( 0 a 9 ) o letras. Por lo tanto, abc23
está bien, pero 23abc causará un error de sintaxis. Los nombres distin-
guen entre mayúsculas y minúsculas, lo que significa que myVar y myvar
son variables distintas. Los nombres de variables no pueden contener es-
pacios en blanco, pero puede separar palabras usando un guión bajo, por
ejemplo, my-var . Tenga cuidado de no insertar un guión en lugar de un
guión bajo: my-var está mal, ya que Python interpreta el signo çomo un
signo menos.

23
Capítulo 2. Una mirada más de cerca a Python:
textos como listas de palabras

2.4 Cuerdas

Algunos de los métodos que usamos para acceder a los elementos de una lista
también funcionan con palabras individuales o cadenas . Por ejemplo, podemos
asignar una cadena a una variable[1] , indexar una cadena [2]y cortar una
cadena [3]:

 name =0 M onty 0 [1]


 nombre[0][2]
0
M ET RO0
 nombre[: 4][3]
0
M ont0


También podemos realizar la multiplicación y la adición con cadenas:

 nombre ∗ 2
0
M ontyM onty 0
 nombre+0 !0
0
M onty!0 7


Podemos unir las palabras de una lista para hacer una sola cadena, o dividir
una cadena en una lista, de la siguiente manera:

00 .join([0 M onty 0 ,0 P ython0 ])


0
M ontyP ython0
0 M ontyP ython0 .split()
Monty’, ’Python’



Volveremos al tema de las cadenas en Capítulo 3 . Por el momento, tenemos


dos bloques de construcción importantes, listas y cadenas, y estamos listos
para volver a algún análisis de lenguaje.

24
Capítulo 3

Computación con lenguaje:


estadísticas simples

Volvamos a nuestra exploración de las formas en que podemos llevar nuestros


recursos computacionales a grandes cantidades de texto. Comenzamos esta
discusión en 1 , y vimos cómo buscar palabras en contexto, cómo compilar el
vocabulario de un texto, cómo generar texto aleatorio en el mismo estilo, y así
sucesivamente.
En esta sección recogemos la pregunta de qué hace que un texto sea distinto,
y usamos métodos automáticos para encontrar palabras y expresiones carac-
terísticas de un texto. Como en 1 , puede probar nuevas características del
lenguaje Python copiándolas en el intérprete, y obtendrá información sobre
estas características sistemáticamente en la siguiente sección.
Antes de continuar, le recomendamos verificar su comprensión de la última
sección al predecir el resultado del siguiente código. Puede usar el intérprete
para verificar si lo hizo bien. Si no está seguro de cómo hacer esta tarea, sería
una buena idea revisar la sección anterior antes de continuar.

25
Capítulo 3. Computación con lenguaje:
estadísticas simples

3.1 Distribuciones de frecuencia

Cómo podemos identificar automáticamente las palabras de un texto que son


más informativas sobre el tema y el género del texto? Imagine cómo puede
encontrar las 50 palabras más frecuentes de un libro. Un método sería mantener
un recuento para cada elemento de vocabulario, como el que se muestra en
3.1 . La cuenta necesitaría miles de filas, y sería un proceso extremadamente
laborioso, tan laborioso que preferiríamos asignar la tarea a una máquina.

Figura 3.1: Palabras de conteo que aparecen en un texto (una distribución de frecuencia)

La tabla en 3.1 se conoce como distribución de frecuencia , y nos dice la fre-


cuencia de cada elemento de vocabulario en el texto. (En general, podría contar
cualquier tipo de evento observable). Es una "distribución"porque nos dice có-
mo se distribuye el número total de tokens de palabras en el texto a través de
los elementos de vocabulario. Como a menudo necesitamos distribuciones de
frecuencia en el procesamiento del lenguaje, NLTK brinda soporte integrado
para ellos. Usemos un FreqDist para encontrar las 50 palabras más frecuentes
de Moby Dick :

Cuando llamamos por primera vez a FreqDist , pasamos el nombre del texto
como un argumento[1] . Podemos inspeccionar el número total de palabras (-
esultados") que se han contabilizado [2], 260.819 en el caso de Moby Dick .
La expresión most-common (50) nos proporciona una lista de los 50 tipos más
frecuentes del texto [3].

26
3.1 Distribuciones de frecuencia

Nota
Su Turno: Pruebe el ejemplo anterior de distribución de frecuencia para
usted mismo, para texto2 . Tenga cuidado de usar los paréntesis correctos
y las letras mayúsculas. Si obtiene un mensaje de error NameError: el
nombre ’FreqDist’ no está definido , debe comenzar su trabajo desde
nltk.book import ∗

Alguna de las palabras producidas en el último ejemplo nos ayuda a captar


el tema o el género de este texto? Solo una palabra, ballena , es ligeramente
informativa! Ocurre más de 900 veces. El resto de las palabras no nos dicen
nada sobre el texto; son solo "fontanería.en inglés. Qué proporción del texto se
utiliza con tales palabras? Podemos generar un gráfico de frecuencia acumu-
lativo para estas palabras, usando fdist1.plot (50, acumulativo = Verdadero)
, para producir el gráfico en 3.2 . Estas 50 palabras representan casi la mitad
del libro!

Figura 3.2: Gráfico de frecuencia acumulado para 50 palabras más frecuentes en Moby Dick
: estos representan casi la mitad de los tokens.)

Si las palabras frecuentes no nos ayudan, qué hay de las palabras que ocurren
una sola vez, los llamados hapax ? Visualícelos escribiendo fdist1.hapaxes () .
Esta lista contiene lexicógrafos , cetológicos , contrabandistas , expostulations
y alrededor de 9,000 más. Parece que hay demasiadas palabras raras, y sin ver
el contexto, probablemente no podamos adivinar qué significa la mitad de los
hapaxes en cualquier caso. Como ni palabras frecuentes ni infrecuentes ayudan,
tenemos que intentar algo más.

27
Capítulo 3. Computación con lenguaje:
estadísticas simples

3.2 SelecciÃ3 nf inadepalabras

A continuación, veamos las palabras largas de un texto; quizás estos serán


más característicos e informativos. Para esto, adaptamos algunas anotaciones
de la teoría de conjuntos. Nos gustaría encontrar las palabras del vocabulario
del texto que tienen más de 15 caracteres. Llamemos a esta propiedad P , de
modo que P (w) sea verdadera si y solo si w tiene más de 15 caracteres. Ahora
podemos expresar las palabras de interés utilizando la notación de conjunto
matemático como se muestra en (1a) . Esto significa .el conjunto de todas las
w tal que w es un elemento de V (el vocabulario) y w tiene la propiedad P ".

a. w | w â V P (w)
segundo [w para w en V si p (w)]

La expresión de Python correspondiente se da en (1b) . (Tenga en cuenta


que produce una lista, no un conjunto, lo que significa que los duplicados son
posibles). Observe cuán similares son las dos notaciones. Avancemos un paso
más y escriba el código de Python ejecutable:

 V = set(text1)
 longw ords = [wparawenV silen(w) > 15]
 sorted(longw ords)
CIRCUMNAVIGATION’, ’Physiognomically’, ’aprehensiÃ3 n0 ,0 canibal-
stico0 ,
0
caractersticamente0 ,0 circunnavegaci3 n0 ,0 circunnavegaci3 n0 ,0 circunnavegaciones0 ,
0
integralidad0 ,0 hermaf rodita0 ,0 indiscriminadamente0 ,0 indispensabilidad0 ,
0
irresistibilidad0 ,0 f ison3 micamente0 ,0 sobrenaturalidad0 ,0 responsabilidades0 ,
0
simultaneidad0 ,0 subterraneidad0 ,0 sobrenaturalidad0 ,0 superstici3 n0 ,
0
incomodidad0 ,0 intransigencia0 ,0 indiscriminado0 ,0 nointerpenetrante0



Para cada palabra w en el vocabulario V , verificamos si len (w) es mayor que


15; todas las demás palabras serán ignoradas. Discutiremos esta sintaxis con
más cuidado más adelante.

28
3.2 SelecciÃ3 nf inadepalabras

Nota
Su Turno: Pruebe las declaraciones anteriores en el intérprete de Pyt-
hon, y experimente cambiando el texto y cambiando la condición de la
longitud.

Cambia la diferencia en los resultados si cambias los nombres de las


variables, por ejemplo, usando [palabra por palabra en vocab si ] ?

Volvamos a nuestra tarea de encontrar palabras que caractericen un texto. Ob-


serve que las palabras largas en texto4 reflejan su enfoque nacional - constitu-
cionalmente , transcontinental - mientras que las de texto5 reflejan su contenido
informal: boooooooooooglyyyyyy y yuuuuuuuuuuuummmmmmmmmmmm .

Hemos tenido éxito en la extracción automática de palabras que tipifican un


texto? Bueno, estas palabras muy largas son a menudo hapax (es decir, úni-
cas) y tal vez sería mejor encontrar palabras largas frecuentes . Esto parece
prometedor, ya que elimina las palabras cortas frecuentes (por ejemplo, la ) y
las palabras largas poco frecuentes (por ejemplo, antifilosophists)) Aquí están
todas las palabras del corpus de chat que tienen más de siete caracteres, que
ocurren más de siete veces:

 f dist5 = F reqDist(text5)


 ordenado(wparawenconjunto(texto5)silen(w) > 7yf dist5[w] > 7)
14-19teens’, ’talkcitya dults0 ,0 ((((((((((0 ,0 ........0 ,0 P regunta0 ,
0
enrealidad0 ,0 cualquiercosa0 ,0 computadora0 ,0 lindo −
culo0 ,0 todos0 ,0 f o tbol0 ,
0
inocente0 ,0 escuchar0 ,0 recordar0 ,0 enserio0 ,0 algo0 ,0 juntos0 ,
0
ma ± ana0 ,0 mirar0



Observe cómo hemos usado dos condiciones: len (w)>7 asegura que las pa-
labras tienen más de siete letras, y fdist5 [w]>7 asegura que estas palabras
ocurren más de siete veces. Por fin hemos logrado identificar automáticamente
las palabras del texto que contienen contenido con frecuencia. Es un hito mo-
desto pero importante: una pequena porción de código, que procesa decenas
de miles de palabras, produce una salida informativa.

29
Capítulo 3. Computación con lenguaje:
estadísticas simples

3.3 Colocaciones y Bigrams

Una colocación es una secuencia de palabras que ocurren juntas inusualmente


a menudo. Por lo tanto, el vino tinto es una colocación, mientras que el vino
no. Una característica de las colocaciones es que son resistentes a la sustitución
con palabras que tienen sentidos similares; por ejemplo, el vino granate suena
definitivamente extrano.
Para manejar las colocaciones, comenzamos extrayendo de un texto una lista de
pares de palabras, también conocidos como bigrams . Esto se logra fácilmente
con la función bigrams () :

 list(bigrams([0 ms0 ,0 es0 ,0 dicho0 ,0 que0 ,0 hecho0 ]))


(’más’, ’es’), (’es’, ’dicho’) , (’dicho’, ’que’), (’que’, ’hecho’)



Nota
Si omitiste list () arriba, y acabas de escribir bigrams ([ ’more’ , ...])
, habrías visto el resultado de la forma <generator object bigrams en
0x10fb8b3a8>. Esta es la manera en que Python dice que está listo para
calcular una secuencia de elementos, en este caso, bigrams. Por ahora,
solo necesita saber decirle a Python que lo convierta en una lista, usando
list () .

Aquí vemos que el par de palabras than-done es un bigram, y lo escribimos en


Python como ( ’than’ , ’done’ ) . Ahora bien, las colocaciones son básicamente
birrams frecuentes, excepto que queremos prestar más atención a los casos que
involucran palabras raras. En particular, queremos encontrar los birams que
ocurren con más frecuencia de lo que esperaríamos según la frecuencia de las
palabras individuales. La función de collocations () hace esto por nosotros.
Veremos cómo funciona más tarde.

30
3.4 Contando otras cosas

 text4.collocations() Las


EstadosU nidos; companerosciudadanos; cuatroanos; haceanosque;
Gobierno
F ederal; Gobiernogeneral; Genteamericana; V icepresidente; V iejo
mundo; DiosT odopoderoso; Companerosciudadanos; M agistradojef e;
P residentedelT ribunalSupremo;
Diosbendiga; cadaciudadano; T ribusindias; ladeudapblica; unosyotros;
nacionesextranjeras; partidospolticos
 text8.collocations()
quisiera; Construccinmediana; bebedorsocial; nochestranquilas; nof umador;
alargoplazo; edadabierta; Gustara; detratof cil; f inancieramenteseguro;
tiempos
divertidos; interesessimilares; Edadabierta; f inesdesemana; possrship;
bienpresentado; nuncacasado; madresoltera; relacinpermanente;
construccindelgada

colocaciones que surgen son muy específicas del género de los textos. Para en-
contrar el vino tinto como una colocación, tendríamos que procesar un cuerpo
de texto mucho más grande.

3.4 Contando otras cosas

Contar palabras es útil, pero también podemos contar otras cosas. Por ejemplo,
podemos ver la distribución de las longitudes de palabra en un texto, creando
un FreqDist a partir de una larga lista de números, donde cada número es la
longitud de la palabra correspondiente en el texto:

 [len(w)parawentexto1][1]
4, 4, 2, 6, 8, 4, 1, 9, 1, 1, 8, 2, 1, 4, 11, 5, 2, 1, 7, 6, 1, 3, 4, 5 , 2, ...

 f dist = F reqDist(len(w)parawentexto1)[2]


 print(f dist)[3]
< F reqDistcon19muestrasy260819resultados >
 f dist
F reqDist(3 : 50223, 1 : 47933, 4 : 42345, 2 : 38513, 5 : 26597, 6 : 17111, 7 : 14399, 8 : 9


31
Capítulo 3. Computación con lenguaje:
estadísticas simples

Comenzamos derivando una lista de las longitudes de palabras en texto1 [1] , y


FreqDist luego cuenta el número de veces que ocurre cada una de estas [2]. El
resultado [3]es una distribución que contiene un cuarto de millón de elementos,
cada uno de los cuales es un número correspondiente a un token de palabra en
el texto. Pero, como mucho, solo se cuentan 20 elementos distintos, los números
del 1 al 20, porque solo hay 20 diferentes longitudes de palabra. Es decir, hay
palabras que constan de un solo carácter, dos caracteres, ..., veinte caracteres,
pero ninguno con veinte uno o más caracteres. Uno podría preguntarse qué
tan frecuentes son las diferentes longitudes de palabra (por ejemplo, cuántas
palabras de longitud cuatro aparecen en el texto, hay más palabras de longitud
cinco que longitud cuatro, etc.). Podemos hacer esto de la siguiente manera:

 f dist.mostc ommon()


(3, 50223), (1, 47933), (4, 42345), (2, 38513), (5, 26597), (6, 17111), (7,
14399) ,
(8, 9966), (9, 6428), (10, 3528), (11, 1873), (12, 1053), (13, 567), (14,
177),
(15, 70), ( 16, 22), (17, 12), (18, 1), (20, 1)

 f dist.max()
3
 f dist[3]
50223
 f dist.f req(3)
0,19255882431878046


De esto vemos que la longitud de palabra más frecuente es 3, y que las palabras
de longitud 3 representan aproximadamente 50,000 (o 20 por ciento) de las
palabras que componen el libro. Aunque no vamos a continuar aquí, un análisis
más detallado de la longitud de las palabras puede ayudarnos a comprender
las diferencias entre autores, géneros o idiomas.
3.1 resume las funciones definidas en las distribuciones de frecuencia.
Nuestra discusión sobre la distribución de frecuencias ha introducido algunos
conceptos importantes de Python, y los analizaremos sistemáticamente en 4 .

32
3.4 Contando otras cosas

Ejemplo Descripción
fdist = FreqDist (muestras) crear una distribución de frecuencia
que contenga las muestras dadas
fdist [muestra] + = 1 incrementar el conteo para esta muestra
fdist [ ’monstruo’ ] recuento del número de veces que se
produjo una muestra determinada
fdist.freq ( ’monstruoso’ ) frecuencia de una muestra dada
fdist.N () número total de muestras
fdist.most_common (n) las n muestras más comunes y
sus frecuencias
para la muestra en fdist: iterar sobre las muestras
fdist.max () muestra con el mayor recuento
fdist.tabulate () tabular la distribución de frecuencia
fdist.plot () gráfica gráfica de la
distribución de frecuencia
fdist.plot (acumulativo = verdadero) diagrama acumulativo de la distribución de
frecuencia
fdist1 | = fdist2 actualiza fdist1 con conteos de fdist2
fdist1 <fdist2 probar si las muestras en fdist1 ocurren con m
frecuencia que en fdist2

33
Capítulo 4

Volver a Python: tomar


decisiones y tomar el control

Hasta ahora, nuestros pequenos programas han tenido algunas cualidades in-
teresantes: la capacidad de trabajar con el lenguaje y el potencial para ahorrar
esfuerzo humano a través de la automatización. Una característica clave de
la programación es la capacidad de las máquinas para tomar decisiones en
nuestro nombre, la ejecución de instrucciones cuando se cumplen ciertas con-
diciones, o el bucle repetido a través de datos de texto hasta que se cumpla
alguna condición. Esta característica se conoce como control y es el foco de
esta sección.

4.1 Condicionales

Python admite una amplia gama de operadores, como <y >= , para probar la
relación entre valores. El conjunto completo de estos operadores relacionales
se muestra en 4.1 .
Podemos usar estos para seleccionar diferentes palabras de una oración de texto
de noticias. Aquí hay algunos ejemplos: solo el operador cambia de una línea
a la siguiente. Todos usan sent7 , la primera oración de text7 ( Wall Street

35
Capítulo 4. Volver a Python:
tomar decisiones y tomar el control

Operador Relación
< menos que
<= Menos que o igual a
== igual a (tenga en cuenta que esto es dos signos "= ", no uno)
!= no igual a
> mas grande que
>= Mayor qué o igual a

Journal ). Como antes, si recibe un error que dice que sent7 no está definido,
primero debe escribir: from nltk.book import ∗

 sent7
Pierre’, ’Vinken’, ’,’, ’61’, ’años0 ,0 viejo0 ,0 ,0 ,0 will0 ,0 join0 ,0 the0 ,
0
board0 ,0 como0 ,0 a0 ,0 noejecutivo0 ,0 director0 ,0 N ov.0 ,0 290 ,0 .0

 [wparawensent7silen(w) < 4]


,’, ’61’, ’old’, ’,’, ’the’, ’as’, ’a’, ’29’, ’.’

 [wparawensent7silen(w) <= 4]


,’, ’61’, ’old’, ’,’, ’will’, ’join’, ’the’, ’as’ , ’a’, ’Nov.’, ’29’, ’.’

 [wparawensent7silen(w) == 4]
will’, ’join’, ’Nov.’

 [wparawensent7silen(w)! = 4]
Pierre’, ’Vinken’, ’,’, ’61’, ’años0 ,0 viejo0 ,0 ,0 ,0 el0 ,0 junta0 ,
0
como0 ,0 a0 ,0 noejecutivo0 ,0 director0 ,0 290 ,0 .0



Hay un patrón común para todos estos ejemplos: [w para w en texto si condición
] , donde condición es una "prueba"de Python que arroja verdadero o falso.
En los casos que se muestran en el ejemplo de código anterior, la condición
siempre es una comparación numérica. Sin embargo, también podemos probar
varias propiedades de palabras, usando las funciones enumeradas en 4.2 .
———————————————————————

36
4.2 Operando en cada elemento

4.2 Operando en cada elemento

En 3, vimos algunos ejemplos de contar elementos que no sean palabras. Eche-


mos un vistazo más de cerca a la notación que usamos:

 [len(w)parawentexto1]
4, 4, 2, 6, 8, 4, 1, 9, 1, 1, 8, 2, 1, 4, 11, 5, 2, 1, 7, 6, 1, 3, 4, 5, 2, ...

 [w.upper()parawentext1]
[’, ’MOBY’, ’DICK’, ’BY’, ’HERMAN’, ’MELVILLE’, ’1851’, ’
0 0
, ET IM OLOGA0 ,0 .0 , ...]


Estas expresiones tienen la forma [f (w) para ...] o [wf () para ...] , donde f es
una función que opera en una palabra para calcular su longitud o convertirla a
mayúsculas. Por ahora, no necesita comprender la diferencia entre las notacio-
nes f (w) y wf () . En su lugar, simplemente aprende este modismo de Python
que realiza la misma operación en cada elemento de una lista. En los ejemplos
anteriores, pasa por cada palabra en texto1 , asignando cada una a la variable
w y realizando la operación especificada en la variable.

Nota
La notación que acabamos de describir se llama "lista de comprensión".
Este es nuestro primer ejemplo de un modismo de Python, una notación
fija que usamos habitualmente sin molestarnos en analizar cada vez. Do-
minar dichos modismos es una parte importante de convertirse en un
programador de Python fluido.

Volvamos a la cuestión del tamanio del vocabulario, y apliquemos el mismo


modismo aquí:

 len(text1)
260819
 len(set(text1))
19317
 len(set(word.lower()parapalabraentexto1))
17231


37
Capítulo 4. Volver a Python:
tomar decisiones y tomar el control

Ahora que no estamos contando dos palabras como Esto y esto , que difieren
solo en mayúsculas, hemos eliminado 2,000 del recuento de vocabulario! Pode-
mos ir un paso más allá y eliminar los números y la puntuación del recuento
de vocabulario filtrando los elementos no alfabéticos:

 len(set(word.lower()parawordentext1if word.isalpha()))


16948


Este ejemplo es un poco complicado: minúscula todos los elementos puramen-


te alfabéticos. Quizás hubiera sido más simple simplemente contar los ítems
minúsculos, pero esto da la respuesta incorrecta (por qué?).
No se preocupe si todavía no se siente seguro con las listas de comprensión,
ya que verá muchos más ejemplos junto con explicaciones en los siguientes
capítulos.

4.3 Bloques de código anidados

La mayoría de los lenguajes de programación nos permiten ejecutar un bloque


de código cuando se cumple una expresión condicional , o una declaración
if . Ya vimos ejemplos de pruebas condicionales en código como [w para w
en sent7 si len (w) <4] . En el siguiente programa, hemos creado una variable
llamada palabra que contiene el valor de cadena ’cat’ . La instrucción if verifica
si la prueba len (palabra) <5 es verdadera. Es así que se invoca el cuerpo de la
instrucción if y se ejecuta la declaración de impresión , mostrando un mensaje al
usuario. Recuerde sangrar elimprimir declaración escribiendo cuatro espacios.

 palabra=0 gato0


 silen(palabra) < 5 :
...imprimir(0 longituddepalabraesmenorque50 )
...[1]
lalongituddelapalabraesmenosde5


Cuando usamos el intérprete de Python, tenemos que agregar una línea[1] en


blanco adicional para que detecte que el bloque anidado está completo.

38
4.3 Bloques de código anidados

Nota Si
Si está utilizando Python 2.6 o 2.7, necesita incluir la siguiente línea para
que se reconozca la función de impresión anterior :

 desde − −f uture − −importprint − f unction

cambiamos la prueba condicional a len (palabra)>= 5 , para verificar que la


longitud de la palabra sea mayor o igual que 5 , entonces la prueba ya no
será verdadera. Esta vez, el cuerpo de la declaración if no se ejecutará y no se
mostrará ningún mensaje al usuario:

 silen(palabra) >=5 :


...print(0 longituddepalabraesmayoroigualque50 )
...


Una instrucción if se conoce como estructura de control porque controla si se


ejecutará el código en el bloque sangrado. Otra estructura de control es el ciclo
for . Intente lo siguiente, y recuerde incluir el colon y los cuatro espacios:

 porpalabraen[0 Llamar0 ,0 me0 ,0 Ishmael0 ,0 .0 ] :


...print(palabra)
...
Call
me
Ishmael
.


Esto se denomina bucle porque Python ejecuta el código de forma circular.


Comienza ejecutando la palabra de asignación = ’Llamar’ , utilizando efecti-
vamente la palabra variable para nombrar el primer elemento de la lista. Luego,
muestra el valor de la palabra para el usuario. A continuación, vuelve a la ins-
trucción for y realiza la asignación word = ’me’ , antes de mostrar este nuevo
valor al usuario, y así sucesivamente. Continúa de esta manera hasta que todos
los elementos de la lista hayan sido procesados.

39
Capítulo 4. Volver a Python:
tomar decisiones y tomar el control

4.4 Bucle con condiciones

Ahora podemos combinar las declaraciones if y for . Recorriremos cada elemen-


to de la lista e imprimiremos el ítem solo si termina con la letra l . Elegiremos
otro nombre para la variable para demostrar que Python no intenta dar sentido
a los nombres de las variables.

 sent1 = [0 Llamar0 ,0 m0 ,0 Ishmael0 ,0 .0 ]


 paraxyzzyensent1 :
...if xyzzy.endswith(0 l0 ) :
...print(xyzzy)
...
Llamaa
Ishmael

Usted se dará cuenta de que si y para los estados tienen dos puntos al final
de la línea, antes de que comience la sangría. De hecho, todas las estructuras
de control de Python terminan con dos puntos. Los dos puntos indican que la
instrucción actual se relaciona con el bloque sangrado que sigue.
También podemos especificar una acción a tomar si no se cumple la condición
de la declaración if . Aquí vemos la instrucción elif (else if) y la instrucción
else . Tenga en cuenta que estos también tienen dos puntos antes del código
sangrado.

 paratokenensent1 :
...if token.islower() :
...print(token,0 esunapalabraenmino scula0 )
...elif token.istitle() :
...print(token,0 esunapalabradettulo0 )
...else :
...print(token,0 eslapuntuacion0 )
...
Callesunapalabraporpalabraclave
meesunapalabraminscula
Ishmaelesunapalabradettulo
.espuntuaci3 n


40
4.4 Bucle con condiciones

Como puede ver, incluso con esta pequena cantidad de conocimiento de Pyt-
hon, puede comenzar a crear programas de Python de líneas múltiples. Es
importante desarrollar dichos programas en piezas, probando que cada pieza
haga lo que esperas antes de combinarlas en un programa. Esta es la razón
por la cual el intérprete interactivo de Python es tan valioso y por qué debería
sentirse cómodo al usarlo.
Finalmente, combinemos los modismos que hemos estado explorando. Prime-
ro, creamos una lista de palabras cie y cei , luego recorremos cada elemento e
imprimimos. Observe la información adicional dada en la declaración de im-
presión: end = ” . Esto le dice a Python que imprima un espacio (no la nueva
línea predeterminada) después de cada palabra.

 tricky=ordenado(wparawenset(text2)si0 cie0 enwo0 cei0 enw)


 parapalabraentricky :
...print(word, end=00 )
ancientceilingEngreimientoengredoconcibaconcienzuda
concienciaconcienzudaenganosaenganar...


41
Capítulo 5

Comprensión automática del


lenguaje natural

Hemos estado explorando el lenguaje de abajo hacia arriba, con la ayuda de


textos y el lenguaje de programación Python. Sin embargo, también estamos
interesados en explotar nuestro conocimiento de lenguaje y computación me-
diante el desarrollo de tecnologías de lenguaje útiles. Aprovecharemos la opor-
tunidad ahora para dar un paso atrás desde lo esencial del código a fin de
obtener una imagen más completa del procesamiento del lenguaje natural.
En un nivel puramente práctico, todos necesitamos ayuda para navegar por
el universo de información encerrado en el texto en la Web. Los motores de
búsqueda han sido cruciales para el crecimiento y la popularidad de la Web,
pero tienen algunas deficiencias. Se requiere habilidad, conocimiento y algo de
suerte para extraer respuestas a preguntas tales como:

Qué sitios turísticos puedo visitar entre Filadelfia y Pittsburgh con un pre-
supuesto limitado? Qué dicen los expertos sobre las cámaras digitales SLR?
Qué predicciones sobre el mercado del acero fueron hechas por comentaristas
creíbles la semana pasada? Conseguir que una computadora responda auto-
máticamente implica una variedad de tareas de procesamiento del lenguaje,
incluida la extracción de información, la inferencia y el resumen, y debería

43
Capítulo 5. Comprensión automática del lenguaje natural

llevarse a cabo en una escala y con un nivel de robustez que está aún más allá
de nuestras capacidades actuales.
En un nivel más filosófico, un desafío de larga data dentro de la inteligencia
artificial ha sido construir máquinas inteligentes, y una parte importante del
comportamiento inteligente es la comprensión del lenguaje. Durante muchos
anios este objetivo se ha visto como demasiado difícil. Sin embargo, a medida
que las tecnologías de PNL se vuelven más maduras y los métodos robustos
para analizar el texto no restringido se generalizan, la perspectiva de la com-
prensión del lenguaje natural ha resurgido como un objetivo plausible.
En esta sección describimos algunas tecnologías de comprensión del lenguaje,
para darle una idea de los desafíos interesantes que le esperan.

5.1 Desambiguación de sentido de palabra

En la desambiguación de los sentidos de las palabras queremos determinar qué


sentido de una palabra se pretende en un contexto dado. Considere las palabras
ambiguas servir y plato :
(2)
a. servir : ayuda con comida o bebida; sostener una oficina; pon la pelota en
juego

segundo. plato : plato; curso de una comida; dispositivo de comunicaciones

En una oración que contiene la frase: sirvió el plato , puedes detectar que tanto
el servicio como el plato se usan con los significados de los alimentos. Es poco
probable que el tema de discusión haya pasado de los deportes a la vajilla en
el espacio de tres palabras. Esto te obligaría a inventar imágenes extranas,
como un profesional del tenis que saca sus frustraciones en un juego de té de
porcelana dispuesto al lado de la cancha. En otras palabras, desambiguamos
palabras automáticamente usando el contexto, explotando el simple hecho de
que las palabras cercanas tienen significados estrechamente relacionados. Como
otro ejemplo de este efecto contextual, considere la palabra por , que tiene
varios significados, por ejemplo: el libro de Chesterton (agente - Chesterton
fue el autor del libro); la taza junto a la estufa (locativo - la estufa es donde
está la taza); y enviar antes del viernes (temporal - viernes es el momento de

44
5.2 Resolución del pronombre

la presentación). Observe en (3c) que el significado de la palabra en cursiva


nos ayuda a interpretar el significado de by .
(3)
a. Los ninos perdidos fueron encontrados por los buscadores (agente)

segundo. Los ninos perdidos fueron encontrados por la montana (locativo)

do. Los ninos perdidos fueron encontrados por la tarde (temporal)

5.2 Resolución del pronombre

Un tipo más profundo de comprensión del lenguaje es averiguar "quién hizo


qué para quién", es decir, para detectar los sujetos y los objetos de los verbos.
Aprendiste a hacer esto en la escuela primaria, pero es más difícil de lo que
piensas. En la oración, los ladrones robaron las pinturas , es fácil decir quién
realizó la acción de robo. Considere tres posibles oraciones siguientes en (4c)
y trate de determinar qué fue vendido, atrapado y encontrado (un caso es
ambiguo).
(4)
a. Los ladrones robaron las pinturas. Fueron vendidos posteriormente .

segundo. Los ladrones robaron las pinturas. Fueron atrapados posteriormente


.

do. Los ladrones robaron las pinturas. Ellos fueron posteriormente encontrados
.

Responder esta pregunta implica encontrar el antecedente del pronombre que


ellos , ya sea ladrones o pinturas. Las técnicas computacionales para abordar
este problema incluyen la resolución de la anáfora -identificando a qué se refiere
un pronombre o frase nominativa- y el etiquetado semántico del rol , identi-
ficando cómo un sintagma nominal se relaciona con el verbo (como agente,
paciente, instrumento, etc.).

45
Capítulo 5. Comprensión automática del lenguaje natural

5.3 Generación de salida de idioma

Si podemos resolver automáticamente tales problemas de comprensión del len-


guaje, podremos pasar a tareas que impliquen la generación de resultados del
lenguaje, como la respuesta a preguntas y la traducción automática . En el
primer caso, una máquina debería ser capaz de responder a las preguntas de
un usuario relacionadas con la recopilación de textos:
(5)
a. Texto: Los ladrones robaron las pinturas. Fueron vendidos posteriormente.

segundo. Humano: Quién o qué se vendió?


do. Máquina: las pinturas.
La respuesta de la máquina demuestra que ha funcionado correctamente que
se refieren a pinturas y no a ladrones. En el segundo caso, la máquina debería
poder traducir el texto a otro idioma, transmitiendo con precisión el significado
del texto original. Al traducir el texto de ejemplo al francés, nos vemos obli-
gados a elegir el género del pronombre en la segunda oración: ils (masculino)
si se encuentran los ladrones, y elles (femenino) si se encuentran las pinturas.
La traducción correcta en realidad depende de la correcta comprensión del
pronombre.
(6)
a. Los ladrones robaron las pinturas. Fueron encontrados posteriormente.

segundo. Les voleurs ont volé les peintures. Ils ont été trouvés plus tard. (los
ladrones)

do. Les voleurs ont volé les peintures. Elles ont été trouvées plus tard. (las
pinturas)

En todos estos ejemplos, trabajar el sentido de una palabra, el sujeto de un


verbo y el antecedente de un pronombre son pasos para establecer el significado
de una oración, cosas que esperaríamos que un sistema de comprensión del
lenguaje pudiera hacer.

46
5.4 Traducción automática

5.4 Traducción automática

Desde hace mucho tiempo, la traducción automática (MT) ha sido el santo


grial de la comprensión del lenguaje, en última instancia, busca proporcionar
traducción idiomática de alta calidad entre cualquier par de idiomas. Sus raíces
se remontan a los primeros días de la Guerra Fría, cuando la promesa de la
traducción automática condujo a un sustancial patrocinio gubernamental y,
con él, a la génesis de la propia PNL.
En la actualidad, existen sistemas de traducción prácticos para pares particu-
lares de idiomas, y algunos están integrados en motores de búsqueda web. Sin
embargo, estos sistemas tienen algunas deficiencias serias, que se revelan cla-
ramente al traducir una oración entre un par de idiomas hasta que se alcanza
el equilibrio, por ejemplo:
0>cuánto tiempo antes del próximo vuelo a Alice Springs?
1>wie lang vor dem folgenden Flug zu Alice Springs?
2>cuánto tiempo antes del siguiente vuelo a Alice saltar?
3>wie lang vor dem folgenden Flug zu Alice springen Sie?
4>Cuánto tiempo antes del siguiente vuelo a Alice, saltas?
5>wie lang, bevor der folgende Flug zu Alice tun, Sie springen?
6>Cuánto tiempo, antes del siguiente vuelo a Alice, saltas?
7>wie lang bevor der folgende Flug zu Alice tut, tun Sie springen?
8>Cuánto tiempo antes del siguiente vuelo a Alice, saltas?
9>wie lang, bevor der folgende Flug zu Alice tut, tun Sie springen?
10>Cuánto tiempo, antes de que el vuelo siguiente afecte a Alicia, saltas?
11>wie lang bevor der folgende Flug zu Alice tut, Sie tun Sprung?
12>cuánto tiempo antes de que el siguiente vuelo salte a Alice, verdad?

Observe que el sistema traduce correctamente Alice Springs de inglés a alemán


(en la línea que comienza en 1>), pero en el camino de regreso a inglés, esto
termina cuando Alice salta (línea 2 ). La preposición anterior se traduce ini-
cialmente en la preposición alemana correspondiente vor , pero más tarde en
la conjunción bevor (línea 5).
Después de la línea 5, las oraciones se vuelven absurdas (pero observe las
diversas frases indicadas por las comas, y el cambio de salto a salto) El sistema
de traducción no reconoció cuando una palabra era parte de un nombre propio
y malinterpretó la estructura gramatical.

47
Capítulo 5. Comprensión automática del lenguaje natural

Nota
Tu turno: prueba esto usando http://translationparty.com/

La traducción automática es difícil porque una palabra dada podría tener va-
rias traducciones posibles (dependiendo de su significado), y porque el orden
de las palabras debe cambiarse de acuerdo con la estructura gramatical del
idioma de destino. Hoy se enfrentan estas dificultades al recopilar cantidades
masivas de textos paralelos de sitios web de noticias y del gobierno que pu-
blican documentos en dos o más idiomas. Dado un documento en alemán e
inglés, y posiblemente un diccionario bilingà 14 e, podemos emparejar automá-
ticamente las oraciones, un proceso llamado alineación de texto . Una vez que
tenemos un millón o más pares de oraciones, podemos detectar las palabras
y frases correspondientes, y crear un modelo que se pueda usar para traducir
texto nuevo.

5.5 Sistemas de diálogo hablado

En la historia de la inteligencia artificial, la medida principal de la inteligencia


ha sido lingà 41 ística, es decir, la Prueba de Turing : puede un sistema de
diálogo, respondiendo al ingreso de texto de un usuario, funcionar de forma
tan natural que no podemos distinguirlo de una respuesta generada por el
ser humano? Por el contrario, los sistemas de diálogo comercial actuales son
muy limitados, pero aún realizan funciones útiles en dominios estrechamente
definidos, como vemos aquí:
S: Cómo puedo ayudarte? U: Cuándo está jugando Saving Private Ryan? S:
Para qué teatro? U: El teatro Paramount. S: Saving Private Ryan no está
jugando en el teatro Paramount, pero está sonando en el teatro Madison a las
3:00, 5:30, 8:00 y 10:30. No se podía pedir a este sistema que proporcionara
instrucciones de manejo o detalles de los restaurantes cercanos a menos que
la información requerida ya se haya almacenado y se hayan incorporado pares
adecuados de preguntas y respuestas en el sistema de procesamiento de idiomas.
Observe que este sistema parece comprender los objetivos del usuario: el usua-
rio pregunta cuándo se muestra una película y el sistema determina correcta-
mente que el usuario desea ver la película. Esta inferencia parece tan obvia
que probablemente no se dio cuenta de que se hizo, sin embargo, un sistema
de lenguaje natural necesita estar dotado de esta capacidad para interactuar
de forma natural. Sin él, cuando se le preguntó Sabes cuándo está jugando

48
5.5 Sistemas de diálogo hablado

Saving Private Ryan? , un sistema podría responder inútilmente con un sí frío


. Sin embargo, los desarrolladores de sistemas de diálogo comercial utilizan
suposiciones contextuales y lógica de negocios para garantizar que las diferen-
tes maneras en que un usuario puede expresar las solicitudes o proporcionar
información se manejan de una manera que tenga sentido para la aplicación
en particular. Entonces, si escribes Cuándo es ... , o quiero saber cuándo ...? O
Puede decirme cuándo ...? Las reglas simples siempre darán lugar a los tiempos
de revisión. Esto es suficiente para que el sistema brinde un servicio útil.

Figura 5.1: Arquitectura de interconexión simple para un sistema de diálogo hablado: se


analiza la entrada de voz (arriba a la izquierda), se reconocen las palabras, las oraciones
se analizan e interpretan en contexto, se llevan a cabo acciones específicas de la aplicación
(arriba a la derecha); se planifica una respuesta, se realiza como una estructura sintáctica,
luego para palabras adecuadamente inflexionadas, y finalmente para salida hablada; diferen-
tes tipos de conocimiento linguístico informan cada etapa del proceso.

Los sistemas de diálogo nos dan la oportunidad de mencionar la tubería co-


múnmente asumida para NLP. 5.1 muestra la arquitectura de un sistema de
diálogo simple. En la parte superior del diagrama, moverse de izquierda a de-
recha, es una "tubería"de algunos componentes de comprensión del lenguaje .
Estos mapas de entrada de voz a través de análisis sintáctico a algún tipo de
representación de significado. A lo largo del medio, moviéndose de derecha a
izquierda, está la tubería invertida de componentes para convertir conceptos
a voz. Estos componentes conforman los aspectos dinámicos del sistema. En
la parte inferior del diagrama hay algunos cuerpos representativos de infor-
mación estática: los repositorios de datos relacionados con el lenguaje que los
componentes de procesamiento utilizan para hacer su trabajo.

49
Capítulo 5. Comprensión automática del lenguaje natural

Nota
Su turno: para un ejemplo de un sistema de diálogo primitivo, trate
de tener una conversación con un chatbot NLTK. Para ver los chatbots
disponibles, ejecute nltk.chat.chatbots () . (Recuerde importar nltk pri-
mero).

5.6 Entailment textual

El desafío de la comprensión del lenguaje ha sido enfocado en los últimos anos


por una "tarea compartida"pública llamada Reconocimiento del Entaimiento
Textual (RTE). El escenario básico es simple. Supongamos que quiere encontrar
evidencia para sustentar la hipótesis: Sandra Goudie fue derrotada por Max
Purnell , y que tiene otro texto breve que parece ser relevante, por ejemplo,
Sandra Goudie fue elegida por primera vez para el Parlamento en las elecciones
de 2002, ganando por poco sede de Coromandel al derrotar al candidato labo-
rista Max Purnell y empujar a la actual diputada verde Jeanette Fitzsimons al
tercer lugar. El texto proporciona suficiente evidencia para que usted acepte
la hipótesis? En este caso particular, la respuesta será "No". Puede sacar esta
conclusión fácilmente, pero es muy difícil encontrar métodos automáticos para
tomar la decisión correcta. Los desafíos de RTE proporcionan datos que permi-
ten a los competidores desarrollar sus sistemas, pero no datos suficientes para
las técnicas de aprendizaje automático con "fuerza bruta"(un tema que trata-
remos en chap-data-intensive ). En consecuencia, algunos análisis lingà 14 ísticos
son cruciales. En el ejemplo anterior, es importante que el sistema note que
Sandra Goudie nombra a la persona que está siendo derrotada en la hipótesis,
no a la persona que está derrotando en el texto. Como otra ilustración de la
dificultad de la tarea, considere el siguiente par texto-hipótesis:
(7)
a. Texto: David Golinkin es el editor o autor de dieciocho libros, y más de 150
responsa, artículos, sermones y libros

segundo. Hipótesis: Golinkin ha escrito dieciocho libros

Para determinar si la hipótesis es respaldada por el texto, el sistema necesita


el siguiente conocimiento de fondo: (i) si alguien es autor de un libro, entonces
él / ella ha escrito ese libro; (ii) si alguien es editor de un libro, entonces él /

50
5.7 Limitaciones de NLP

ella no ha escrito (todo) ese libro; (iii) si alguien es editor o autor de dieciocho
libros, entonces no se puede concluir que él / ella es autor de dieciocho libros.

5.7 Limitaciones de NLP

A pesar de los avances liderados por la investigación en tareas como RTE, los
sistemas de lenguaje natural que se han implementado para aplicaciones del
mundo real aún no pueden realizar un razonamiento de sentido común o recurrir
al conocimiento del mundo de una manera general y robusta. Podemos espe-
rar a que se resuelvan estos difíciles problemas de inteligencia artificial, pero
mientras tanto es necesario vivir con algunas limitaciones severas en las capaci-
dades de razonamiento y conocimiento de los sistemas de lenguaje natural. En
consecuencia, desde el principio, un objetivo importante de la investigación de
PNL ha sido avanzar en la difícil tarea de construir tecnologías que .entienden
el lenguaje", utilizando técnicas superficiales pero poderosas en lugar de un
conocimiento irrestricto y capacidades de razonamiento. De hecho, este es uno
de los objetivos de este libro,

51
Capítulo 6

Resumen

Los textos están representados en Python usando listas: [ ’Monty’ , ’Pyt-


hon’ ] . Podemos usar indexación, división y la función len () en las listas.
Una palabra "token.es una apariencia particular de una palabra dada en
un texto; una palabra "tipo.es la forma única de la palabra como una
secuencia particular de letras. Contamos tokens de palabras usando len
(texto) y tipos de palabras usando len (set (texto)) .
Obtenemos el vocabulario de un texto t usando sorted (set (t)) .
Operamos en cada elemento de un texto usando [f (x) para x en el texto]
.
Para derivar el vocabulario, colapsando las distinciones entre mayúsculas
y minúsculas e ignorando la puntuación, podemos escribir set (w.lower ()
para w en el texto if w.isalpha ()) .
Procesamos cada palabra en un texto utilizando una de declaración, como
por w en t: o de palabra en el texto: . Esto debe ir seguido del carácter
de dos puntos y un bloque de código con sangría, que se ejecutará cada
vez a través del bucle.

53
Capítulo 6. Resumen

Probamos una condición usando un caso de declaración: si len (palabra)


<5: . Esto debe ir seguido del carácter de dos puntos y un bloque de
código con sangría, que se ejecutará solo si la condición es verdadera.
Una distribución de frecuencia es una colección de elementos junto con
sus recuentos de frecuencia (por ejemplo, las palabras de un texto y su
frecuencia de aparición).
Una función es un bloque de código al que se le ha asignado un nombre
y puede reutilizarse. Las funciones se definen usando la palabra clave def
, como en def mult (x, y) ; x y y son parámetros de la función, y actúan
como marcadores de posición para los valores de datos reales.
Se llama a una función especificando su nombre seguido de cero o más
argumentos dentro de paréntesis, como este: textos () , mult (3, 4) , len
(texto1) .

54
Capítulo 7

Lectura adicional

Este capítulo ha introducido nuevos conceptos en programación, procesamiento


del lenguaje natural y lingà 14 ística, todo mezclado en conjunto. Muchos de ellos
se consolidan en los siguientes capítulos. Sin embargo, también puede consultar
los materiales en línea proporcionados con este capítulo (en http://nltk.org/
), incluidos enlaces a materiales de antecedentes adicionales y enlaces a sis-
temas en línea de PNL. También es posible que desee leer algunos conceptos
lingà 14 ísticos y relacionados con la PNL en Wikipedia (por ejemplo, las colo-
caciones, la prueba de Turing, la distinción de tipo de token).
Debe familiarizarse con la documentación de Python disponible en http://docs.python.or
, incluidos los numerosos tutoriales y materiales de referencia integrales vin-
culados allí. Una guía para principiantes sobre Python está disponible en
http://wiki.python.org/moin/BeginnersGuide . Las preguntas misceláneas so-
bre Python pueden ser respondidas en las preguntas frecuentes en http://python.org/doc
.
A medida que profundiza en NLTK, es posible que desee suscribirse a la lista de
correo donde se anuncian las nuevas versiones del kit de herramientas. También
hay una lista de correo NLTK-Users, donde los usuarios se ayudan mutuamen-
te mientras aprenden a usar Python y NLTK para el trabajo de análisis de
idiomas. Los detalles de estas listas están disponibles en http://nltk.org/ .

55
Capítulo 7. Lectura adicional

Para obtener más información sobre los temas cubiertos en 5 , y sobre PNL en
general, le recomendamos consultar uno de los siguientes libros excelentes:

Indurkhya, Nitin y Fred Damerau (eds, 2010) Manual de procesamiento


del lenguaje natural (Segunda edición) Chapman Hall / CRC. 2010.
(Indurkhya y Damerau, 2010) (Dale, Moisl, y Somers, 2000)
Jurafsky, Daniel y James Martin (2008) Procesamiento del habla y el
lenguaje (Segunda edición). Prentice Hall. (Jurafsky Martin, 2008)
Mitkov, Ruslan (ed, 2003) The Oxford Handbook of Computational Lin-
guistics . Prensa de la Universidad de Oxford. (segunda edición esperada
en 2010). (Mitkov, 2002)

La Asociación para la Lingà 14 ística Computacional es la organización interna-


cional que representa el campo de la PNL. El sitio web de ACL ( http://www.aclweb.org/
) alberga muchos recursos útiles, que incluyen: información sobre conferencias
y talleres internacionales y regionales; la Wiki de ACL con enlaces a cientos
de recursos útiles; y la Antología de ACL , que contiene la mayoría de la lite-
ratura de investigación de PNL de los últimos 50 anos, totalmente indexada y
descargable libremente.
Algunos excelentes libros de texto introductorios de Linguística son: [Fine-
gan2007] - , (O’Grady et al, 2004) , (OSU, 2007) . Es posible que desee consul-
tar LanguageLog , un blog de linguística popular con publicaciones ocasionales
que utilizan las técnicas descritas en este libro.

56
Capítulo 8

Ejercicios

1. Intente utilizar el intérprete de Python como calculadora y escriba expre-


siones como 12 / (4 + 1).

 12/(4 + 1)
2,4


2. Dado un alfabeto de 26 letras, hay 26 para el poder 10, o 26 ** 10 , cadenas


de diez letras que podemos formar. Eso funciona en 141167095653376 .
Cuántas cadenas de cien letras son posibles?
3. La operación de multiplicación de Python se puede aplicar a las listas.
Qué sucede cuando escribe [ ’Monty’ , ’Python’ ] * 20 o 3 * send1 ?
4. Revise 1 en computación con lenguaje. Cuántas palabras hay en text2 ?
Cuántas palabras distintas hay?
5. Comparar los puntajes de diversidad léxica para el humor y la novela
romántica en 1.1 . Qué género es más léxico diverso?

57
Capítulo 8. Ejercicios

6. Producir un diagrama de dispersión de los cuatro protagonistas principa-


les en Sentido y sensibilidad : Elinor, Marianne, Edward y Willoughby.
Qué puedes observar sobre los diferentes roles que juegan los hombres y
las mujeres en esta novela? Puedes identificar a las parejas?
7. Encuentra las colocaciones en text5 .
8. Considere la siguiente expresión de Python: len (set (text4)) . Indique
el propósito de esta expresión. Describe los dos pasos involucrados en la
realización de este cálculo.
9. Revise 2 en listas y cadenas.

Defina una cadena y asígnela a una variable, por ejemplo, my-string


= ’My String’ (pero ponga algo más interesante en la cadena). Im-
prima el contenido de esta variable de dos maneras, primero sim-
plemente escribiendo el nombre de la variable y presionando enter,
luego usando la instrucción de impresión .
Intente agregar la cadena a sí mismo utilizando my-string + my-
string , o multiplicándolo por un número, por ejemplo, my-string *
3 . Observe que las cadenas están unidas sin espacios. Cómo puedes
arreglar esto?

10. Defina una variable my-sent para que sea una lista de palabras, usando
la sintaxis my-sent = [ "My", "sent"] (pero con sus propias palabras o un
dicho favorito).

Usa ” .join (my-sent) para convertir esto en una cadena.


Use split () para dividir la cadena nuevamente en el formulario de
lista con el que tuvo que comenzar.

11. Definir varias variables que contienen listas de palabras, por ejemplo,
PHRASE1 , PHRASE2 , y así sucesivamente. únelos en varias combina-
ciones (usando el operador más) para formar oraciones completas. Cuál es
la relación entre len (phrase1 + phrase2) y len (phrase1) + len (phrase2)
?
12. Considere las siguientes dos expresiones, que tienen el mismo valor. Cuál
será típicamente más relevante en NLP? Por qué?

"Monty Python"[6:12]

58
"Monty", "Python [1]

13. Hemos visto cómo representar una oración como una lista de palabras,
donde cada palabra es una secuencia de caracteres. Qué hace send1 [2]
[2] ? Por qué? Experimente con otros valores de índice.
14. La primera oración del texto3 se le proporciona en la variable enviada3 .
El índice de la en sent3 es 1, porque sent3 [1] nos da ’la’ . Cuáles son los
índices de las otras dos ocurrencias de esta palabra en sent3 ?
15. Revise la discusión de los condicionales en 4 . Encuentre todas las palabras
en el Chat Corpus ( texto5 ) comenzando con la letra b . Muéstrelos en
orden alfabético.
16. Escriba la lista de expresiones (rango (10)) en el indicador del intérprete.
Ahora prueba lista (rango (10, 20)) , lista (rango (10, 20, 2)) , y lista
(rango (20, 10, -2)) . Veremos una variedad de usos para esta función
incorporada en capítulos posteriores.

 list(range(10))
1, 2, 3, 4, 5, 6, 7, 8, 9


 list(range(10, 20))
11, 12, 13, 14, 15, 16, 17, 18, 19


 list(range(10, 20, 2))
12, 14, 16, 18


 list(range(20, 10, −2))

18, 16, 14, 12



17. Use text9.index () para encontrar el índice de la palabra sunset . Tendrá


que insertar esta palabra como argumento entre paréntesis. Por un pro-

59
Capítulo 8. Ejercicios

ceso de prueba y error, encuentre el corte para la oración completa que


contiene esta palabra.
18. Usando la adición de lista, y las operaciones establecidas y ordenadas ,
calcule el vocabulario de las oraciones enviadas1 ... enviado8 .
19. Cuál es la diferencia entre las dos líneas siguientes? Cuál dará un valor
mayor? Será este el caso para otros textos?

 ordenado(set(w.lower()parawentext1))
 ordenado(w.lower()parawenset(text1))

Cuál es la diferencia entre las siguientes dos líneas? :La


diferencia es que la primera línea nos da un conjunto ordenado de
todas las palabras del âtext1ây la segunda lÃnea nos da un conjunto
ordenado de todas las palabras que son únicas del âtext1â, por ende
nos devuelve un valor más alto en comparación del primero
Cuál dará un valor mayor?: Ejecutamos las siguientes líneas de código
para verificar de que sentencia nos dará un mayor valor.

 len(sorted(set([w.lower()f orwintext1])))


17231
 len(sorted([w.lower()f orwinset(text1)]))
19317

• Nos dará un mayor valor la segunda sentencia.

Será este el caso para otros textos?:

60
 len(sorted([w.lower()f orwinset(text2)]))
6833
 len(sorted(set([w.lower()f orwintext2])))
6403
N osdaunmayorvalorenlasentencia1.

 len(sorted([w.lower()f orwinset(text3)]))


2789
 len(sorted(set([w.lower()f orwintext3])))
2628
N osdaunmayorvalorenlasentencia1.

 len(sorted([w.lower()f orwinset(text4)]))


9754
 len(sorted(set([w.lower()f orwintext4])))
9070
N osdaunmayorvalorenlasentencia1.

 len(sorted([w.lower()f orwinset(text5)]))


6066
 len(sorted(set([w.lower()f orwintext5])))
5441
N osdaunmayorvalorenlasentencia1.

 len(sorted([w.lower()f orwinset(text6)]))


2166
 len(sorted(set([w.lower()f orwintext6])))
1855
N osdaunmayorvalorenlasentencia1.

 len(sorted([w.lower()f orwinset(text7)]))


12408
 len(sorted(set([w.lower()f orwintext7])))
11387
N osdaunmayorvalorenlasentencia1.

61
Capítulo 8. Ejercicios

 len(sorted([w.lower()f orwinset(text8)]))


1108
 len(sorted(set([w.lower()f orwintext8])))
882
N osdaunmayorvalorenlasentencia1.

 len(sorted([w.lower()f orwinset(text9)]))


6807
 len(sorted(set([w.lower()f orwintext9])))
6349

Nos da un mayor valor en la sentencia 1.


No es el mismo caso para los otros textos, ya que nos da un mayor valor
ejecutando la sentencia 1.
20. Cuál es la diferencia entre las dos pruebas siguientes: w.isupper () y no
w.islower () ?
21. Escribe la expresión de corte que extrae las dos últimas palabras de texto2
.
22. Encuentra todas las palabras de cuatro letras en el Chat Corpus ( texto5
). Con la ayuda de una distribución de frecuencias ( FreqDist ), muestre
estas palabras en orden decreciente de frecuencia.
23. Revise la discusión de bucle con las condiciones en 4 . Utilice una com-
binación de instrucciones para y si para recorrer las palabras del guión
de la película para Monty Python y el Santo Grial ( texto6 ) e imprimir
todas las palabras en mayúscula, una por línea.
24. Escriba expresiones para encontrar todas las palabras en el texto6 que
cumplan con las condiciones enumeradas a continuación. El resultado
debe ser en forma de una lista de palabras: [ ’word1’ , ’word2’ , ...] .

Finalizando en ize
Que contiene la letra z
Que contiene la secuencia de letras pt

62
Tener todas las letras minúsculas a excepción de un capital inicial
(es decir, título )

25. Define enviado como la lista de palabras [ ’ella’ , ’vende’ , ’mar’ , ’capara-
zón’ , ’por’ , ’el’ , ’mar’ , ’orilla’ ] . Ahora escribe el código para realizar
las siguientes tareas:
Imprimir todas las palabras que comienzan con sh

 [wf orwinsentif w[0 : 2]==0 sh0 ]  [0 she0 ,0 shells0 ,0 shore0 ]

Imprimir todas las palabras de más de cuatro caracteres

 [wf orwinsentif len(w) > 4]  [0 sells0 ,0 shells0 ,0 shore0 ]

Imprimir todas las palabras que comienzan con sh Imprimir todas las pa-
labras de más de cuatro caracteres
26. Qué hace el siguiente código de Python? sum (len (w) for w en text1) Se
puede usar para calcular la longitud de palabra promedio de un texto?
una función llamada vocab-size (texto) que tiene un único parámetro para
el texto y que devuelve el tamañodevocabulariodeltexto.
27. Defina un porcentaje de función (palabra, texto) que calcula la frecuencia con
que aparece una palabra determinada en un texto y expresa el resultado como
un porcentaje.
28. Hemos estado usando juegos para almacenar vocabularios. Pruebe la siguiente
expresión de Python: set (sent3) <set (text1) . Experimenta con esto usando
diferentes argumentos para set () . Qué hace? Puedes pensar en una aplicación
práctica para esto?

63