Você está na página 1de 51

8

Marcelo Celeghini

PROJETO SOBRE AS PRINCIPAIS TCNICAS PARA PROCESSAMENTO DE LINGUAGEM NATURAL (PLN), UTILIZANDO PYTHON E A BIBLIOTECA DE CDIGO ABERTO, NATURAL LANGUAGE TOOLKIT (NLTK)

SO PAULO 2012

Agradeo a todos e a tudo que direta ou indiretamente contriburam para a realizao deste trabalho.

RESUMO

O Processamento de Linguagem Natural (PLN) um campo da cincia da computao que se preocupa com o processamento da linguagem humana para a entrada e sada de dados em sistemas computacionais. Ao invs de usar uma linguagem de programao convencional, o usurio simplesmente pode usar a linguagem do seu dia-a-dia, como se ele estivesse se comunicando com outra pessoa. Um dos problemas mais desafiadores na rea de cincia da computao desenvolver computadores que possam entender a linguagem natural e devolver respostas corretas para ela. Neste trabalho, utilizaremos a linguagem de programao Python juntamente com a biblioteca de cdigo aberto, Natural Language Toolkit (NLTK) para: - Explicar como a linguagem Python trata um texto. - Extrair informaes de textos no estruturados. - Analisar a estrutura lingustica em um texto, incluindo anlise sinttica e semntica. - Escrever programas para acessar textos em arquivos. - Construir modelos de linguagem que possam ser usados em execuo automtica de tarefas de processamento de linguagem.

10

CONVENES ADOTADAS

Com o intuito de facilitar o entendimento desse trabalho, a fonte utilizada nos exemplos de cdigos ser a fonte Courier New, tamanho 12, e os resultados dos cdigos executados sero escritos com a fonte Courier New, Tamanho 12, em Negrito e na cor azul. Como a biblioteca NLTK foi desenvolvida baseada majoritariamente no padro ASCII e em textos da lngua inglesa, para evitar resultados inesperados na execuo dos cdigos sobre textos em portugus baseados em caracteres Unicode, em alguns dos textos as letras acentuadas e caracteres especiais da lngua portuguesa foram substitudos por caracteres no acentuados, ex. por a, por e, por c, e assim por diante.

11

Sumrio
INTRODUO ....................................................................................................................................... 12 1. PLN E PYTHON .................................................................................................................................. 14 1.1. O Processamento de Linguagem Natural .................................................................................. 14 1.2. A linguagem de programao Python ....................................................................................... 15 1.3. O Interpretador interativo ......................................................................................................... 16 1.4. Utilizando simples tcnicas para processamento de textos ...................................................... 17 1.4.1. O uso de funes ................................................................................................................ 20 1.5. A biblioteca NLTK ...................................................................................................................... 22 1.6. Alguns desafios na rea de Processamento de Linguagem Natural .......................................... 24 2. PROCESSAMENTO DE TEXTO BRUTO E O USO DE RECURSOS LXICOS ............................................ 26 2.1. Transformando um texto em tokens ......................................................................................... 26 2.2. Recursos lxicos ........................................................................................................................ 28 2.3. Stopwords ................................................................................................................................. 32 2.4. Expresses regulares e deteco de padres ............................................................................ 33 3. AS CATEGORIAS LXICAS .................................................................................................................. 36 3.1. O processo de etiquetao ........................................................................................................ 38 3.1.1. Etiquetador padro ............................................................................................................ 38 3.1.2. Avaliando a preciso de um etiquetador ............................................................................ 39 3.1.3. Etiquetador Unigram .......................................................................................................... 39 3.1.4. Combinando etiquetadores ................................................................................................ 42 4. ANLISE SINTTICA PARCIAL ............................................................................................................ 44 4.1. Expresses regulares para a identificao de padres .............................................................. 44 4.2. Utilizando gramticas para agrupar e desagrupar palavras....................................................... 46 5. CONSTRUINDO UM SISTEMA PARA CORREO VERBAL .................................................................. 48 5.1. Dicionrios em Python .............................................................................................................. 49 5.2. Definindo os dicionrios ............................................................................................................ 49 5.3. Definindo uma funo auxiliar .................................................................................................. 51 5.4. Definindo uma funo para correo Verbal ............................................................................. 52 6. CONCLUSO ..................................................................................................................................... 57 REFERNCIAS BIBLIOGRFICAS ............................................................................................................ 58

12

INTRODUO

A partir da Revoluo Industrial, a humanidade intensificou a criao de meios e dispositivos para automatizar o trabalho mecnico. Na segunda metade do sculo XX, iniciou-se uma nova revoluo, dessa vez com a ateno dos humanos voltada para a automatizao de atividades intelectuais, desde ento e cada vez mais, restaro aos homens apenas tarefas ligadas s tomadas de decises. No seria bom poder dirigir um carro sem o uso das mos, apenas "conversando" com o automvel? E sobre viajar para a China e poder comunicar-se com os seus habitantes, sem necessariamente saber falar chins? Apesar da primeira situao ainda ser um caso de fico cientfica, a segunda no . Em reportagem do site UOL Tecnologia1 de 23 de maio de 2011, foi listada uma srie de aplicativos para celulares que permitem que uma pessoa viaje para a China e que se comunique de forma satisfatria sem saber o idioma mandarim, a lngua mais falada por l. Entre esses aplicativos esto dicionrios em mandarim, reconhecedores de caracteres, tradutores automticos, pronunciadores de frases e palavras, leitores de texto, entre outros.

Figura 1.1: Aplicativo que reconhece desenhos de caracteres em mandarim feitos na tela de um dispositivo mvel. Aplicativos como esses ainda apresentam falhas e inconsistncias, mas j
1

http://tecnologia.uol.com.br/album/2011_falar_chines_aplicativos_album.jhtm?

13

esto nos auxiliando na resoluo de problemas na rea de PLN (Processamento de Linguagem Natural), que praticamente eram insolveis h 50 anos, quando comearam a surgir os primeiros computadores eletrnicos. No processamento de linguagem natural, um desafio ainda no vencido totalmente saber qual o real sentido de uma sentena, pois a mesma pode assumir vrios significados, mas geralmente apenas um o aceitvel. Para isso utiliza-se um conjunto de regras para tentar compreender, sem ambiguidades, as informaes contidas na linguagem falada ou escrita. Nesse trabalho, concentraremos os nossos esforos no sentido de explicar as principais tcnicas de PLN utilizadas para a manipulao de textos escritos. Para tanto, utilizaremos a linguagem de programao Python para implementar os algoritmos estudados. Por que Python? Porque uma linguagem poderosa, de fcil entendimento, e com uma especial caracterstica, que o fato de possuir sua disposio uma biblioteca de cdigo livre chamada Natural Language Toolkit (NLTK), com vrias funcionalidades especificamente voltadas para o processamento de dados lingusticos. Os livros que nos serviram de base para esse estudo foram Natural Language Processing with Python, Python Text Processing with NLTK 2.0 Cookbook, Mining the Social Web e Python 2.6 Text Processing Beginner's Guide. O interpretador Python para diversas plataformas pode ser obtido gratuitamente em http://www.python.org/, e a biblioteca NLTK tambm pode ser baixada sem custo em http://www.nltk.org/. Nesses dois endereos existe vasta documentao, dados e exemplos que podem ser livremente consultados. Na primeira parte do nosso trabalho comearemos com uma introduo Python e ao PLN, e demonstraremos o que pode ser alcanado com a combinao de simples tcnicas de programao com grandes quantidades de texto, quais so as tcnicas e ferramentas que Python disponibiliza para esse tipo de trabalho e quais so alguns dos desafios do processamento de linguagem natural. Na segunda parte falaremos sobre o uso de recursos lxicos, e como separar palavras, smbolos e pontuaes em um texto para que possam ser usados em diferentes tipos de anlise. Na terceira parte definiremos as categorias lxicas e mostraremos como elas podem ser usadas no processamento de linguagem natural. Na quarta parte veremos como identificar e classificar as caractersticas relevantes de uma linguagem. E finalmente na quinta parte, construiremos um sistema para manipular informaes em dados no estruturados, utilizando algumas das tcnicas vistas ao longo do nosso estudo.

14

1. PLN E PYTHON

1.1. O Processamento de Linguagem Natural

O Processamento de Linguagem Natural um campo de estudo altamente interdisciplinar que engloba conceitos de Lingustica 2, Matemtica e Cincia da Computao. A utilizao da linguagem humana, seja em texto escrito ou falado, est crescendo a taxas exponenciais e as pessoas esto cada vez mais confiando em servios da internet para a busca, filtragem e processamento de contedo. Esses servios que nos permitem fazer tudo isso com a linguagem cotidiana fazem parte dos problemas compreendidos pelo PLN. Para explicar melhor daremos alguns exemplos. Digamos que um blogger esteja tentando obter informaes sobre uma erupo vulcnica no Chile. O seu fluxo de trabalho pode consistir numa sequncia de tarefas baseada na Web. Para cada tarefa que est sendo executada, incluiremos o nome do problema especfico em PLN que est sendo resolvido: -Mostre-me os dez documentos mais relevantes da internet sobre a erupo vulcnica no Chile. (Recuperao de Informao). - Faa um resumo sobre esses duzentos artigos sobre a erupo no Chile. (Resumo Automtico de Documento). - Traduza esse blog do espanhol para o portugus, para que eu possa obter as ltimas informaes sobre a erupo no Chile. (Traduo Automtica). O PLN como rea de estudos acadmicos nunca foi mais relevante do que atualmente. E os sucessos obtidos nessa rea devem-se utilizao de mtodos que so dirigidos por dados de linguagem natural em vez de usar mtodos puramente baseados no conhecimento ou baseados em regras, que alm de no serem to robustas, possuem alto custo computacional. Com o crescimento dessa tendncia, as tcnicas de PLN dirigidas a dados vm se tornando cada vez mais sofisticadas, empregando vrios conhecimentos das
2

Lingustica a cincia que estuda a linguagem verbal humana.

15

reas de Estatstica e de Aprendizado de Mquinas. Tais tcnicas exigem grandes quantidades de dados para poderem construir um modelo razoavelmente semelhante linguagem humana. Em PLN e em Lingustica usa-se com frequncia os termos corpus ou corpora (corpus no plural). Uma coleo com as diversas obras de Machado de Assis pode ser chamada de um corpus, e uma coleo com vrias obras de diversos autores chamamos de corpora. Corpus e corpora em nosso trabalho representaro uma grande coleo finita de textos que sirvam para o propsito de anlise. Podemos usar um corpus para medir a frequncia de uma palavra em um idioma, ou para criar um dicionrio de uma lngua, por exemplo.

1.2. A linguagem de programao Python

Python uma linguagem interpretada, de cdigo aberto, de alto nvel e de uso geral. Foi criada no incio da dcada de 1990, por Guido van Rossum no CWI (Centrum Wiskunde & Informatica) na Holanda. O nome veio de uma homenagem a um programa televisivo humorstico chamado Monty Python, que foi ao ar pelo canal de TV britnico BBC, entre os anos de 1969 e 1974. considerada uma linguagem de programao multiparadigma, ou seja, ao invs de obrigar o programador a adotar um estilo especfico de programao, ela permite que sejam usados estilos diferentes, como programao estruturada ou orientada a objetos, misturando livremente construtores de diferentes paradigmas. Desse modo o programador fica livre para utilizar diferentes ferramentas conforme a sua necessidade. Em Python no existem tipos primitivos, o conceito de varivel sempre representado por um objeto. Python fcil de se aprender, verstil, possue uma sintaxe simples, e alm disso uma linguagem poderosa. Vrias linguagens de programao tem sido utilizadas para PLN, como por exemplo Pearl, Prolog, Java, C ou Ruby. Mas essas linguagens apresentam uma sintaxe mais complexa e portanto, uma curva de aprendizado mais acentuada. Apesar de Python no ser to veloz como linguagens compiladas como C ou C++, a menor velocidade de execuo no percebida na maioria dos programas, desse modo o menor tempo gasto em programao pode compensar o maior tempo com a execuo de cdigo.

16

A combinao entre o poder e a simplicidade, foi o principal critrio que nos guiou no sentido de eleger Python para o nosso estudo sobre Processamento de Linguagem Natural.

1.3. O Interpretador interativo

Uma das facilidades de Python o seu interpretador interativo. Com ele possvel testar e modificar comandos, funes e outros trechos de cdigo antes de inclu-los em um programa. Essa caracterstica nos ajuda a aumentar a velocidade de aprendizado e portanto, esse mais um dos pontos positivos de Python com relao s outras linguagens. O interpretador interativo pode ser acessado usando a interface grfica chamada IDLE (Interactive DeveLopment Environment), que pode ser observada na figura abaixo.

Figura 1.2: Interactive Development Environment IDLE. O smbolo ">>>", chamado de prompt, indica que o interpretador Python est pronto para receber um comando. Para mostrar o funcionamento do interpretador interativo digitaremos um simples comando para imprimir uma string (sentena) na tela:

17

>>> print Cincia da Computao Cincia da Computao >>> Aps digitarmos o comando e pressionarmos a tecla Enter, o interpretador executa a instruo e o resultado aparece na linha seguinte. Logo abaixo do resultado tambm reaparece o prompt, indicando que o interpretador est pronto para receber uma nova instruo. Python consegue manipular strings de vrias maneiras, como concatenar elementos: >>> frase = 'Cincia ' + 'da ' + 'Computao.' >>> print frase Cincia da Computao. >>> O interpretador Python possui uma srie de funes embutidas que esto disponveis a qualquer instante. No decorrer do trabalho utilizaremos vrias dessas funes em nossos exemplos.

1.4. Utilizando simples tcnicas para processamento de textos

J vimos como possvel imprimir uma string na tela utilizando apenas um comando. Veremos agora o que pode ser feito com grandes quantidades de texto, utilizando simples tcnicas de programao. A string do exemplo a seguir foi retirada do site da UNIP, na pgina de Objetivos do Curso de Cincia da Computao: >>> objetivos_curso = "Com o intuito de estimular e contribuir para a preparao de mo-de-obra especializada e indispensvel poltica de desenvolvimento nacional, o bacharel em Cincia da Computao tem sua formao focada, principalmente, para o projeto e desenvolvimento de produtos de software... >>> >>> print objetivos_curso Com o intuito de estimular e contribuir para a preparao de mo-de-obra especializada e indispensvel poltica de desenvolvimento nacional, o bacharel em Cincia da Computao tem sua formao focada, principalmente, para o

18

projeto e desenvolvimento de produtos de software... >>> Nesse exemplo atribumos varivel objetivos_curso, uma string que contm o trecho da descrio dos objetivos do curso de Cincia da Computao. Quando executamos o comando print, o valor da varivel impresso na tela. Vejam o exemplo a seguir: >>> len(objetivos_curso) 279 >>> A funo len() retorna o nmero de caracteres ou o comprimento da string, incluindo espaos em branco, caracteres especiais e pontuao. O nosso exemplo possui 279 caracteres. Veremos agora se a funo len() tambm eficiente para textos maiores, para tanto criamos um arquivo de texto chamado dom_casmurro.txt, que contm todo o contedo da respectiva obra de Machado de Assis, e o salvamos na mesma pasta onde Python foi instalado. >>> dc = open(dom_casmurro.txt) >>> texto = dc.read() >>> len(texto) 373504 >>> Na primeira linha desse exemplo a funo open() recebe o argumento dom_casmurro.txt, que o nome do arquivo. As aspas indicam que queremos abrir o texto no formato string retornado como um objeto arquivo que atribudo varivel dc. Como dc agora um objeto de Python, ele pode acessar o mtodo read() que l o contedo desse objeto na forma de uma longa string. Na linha seguinte usamos a funo len(texto) para medir o comprimento da string lida, e o resultado obtido foi de 373504 caracteres. Uma string pode ser indexada e isso nos permite fatiar um texto. O ndice zero corresponde ao primeiro caractere da string e no nosso exemplo, o ndice 373503 corresponde ao seu ltimo caractere. Verificaremos agora quais so os primeiros duzentos caracteres do nosso texto, os caracteres \n representam uma nova linha, e por conveno m:n significa o intervalo iniciando com o elemento m at n-1, o intervalo abaixo inclui o elemento 0 at o elemento 199 (200 -1): >>> texto[0:200] 'Romance, Dom Casmurro, 1899\n\nDom Casmurro\n\nTexto de refer\xeancia:\n\nObras Completas de Machado de Assis,\nvol. I,\n\nNova Aguilar, Rio de\nJaneiro,

19

1994.\n\n\xa0Publicado Garnier, Rio d'

originalmente\npela

Editora

Percebemos que o texto obtido no est formatado de maneira apropriada para os padres humanos de leitura, e que a palavra referncia no est totalmente legvel (refer\xeancia), isso porque o caractere especial est representado internamente no formato hexadecimal (onde \x indica que o valor a seguir, ea, o caractere no valor hexadecimal). Para contornar essa situao devemos utilizar o comando print para transformar o contedo da varivel texto em um padro de leitura apropriado: >>> print texto[0:200] Romance, Dom Casmurro, 1899 Dom Casmurro Texto de referncia: Obras Completas de Machado de Assis, vol. I, Nova Aguilar, Rio de Janeiro, 1994. Publicado originalmente pela Editora Garnier, Rio d >>> Strings podem ser manipuladas de diversas maneiras, vimos como medir o seu comprimento, atribu-las a nomes de variveis, concaten-las, index-las e fatilas. Podemos tambm substituir os seus caracteres, descobrir a posio de suas palavras, transform-las para letras maisculas ou minsculas, encontrar e isolar caracteres numricos ou especiais contidos nela, entre vrios outros tipos de manipulaes. Essas operaes com strings so importantes para o PLN, pois em muitos casos teremos que fazer uso de expresses regulares nos algoritmos utilizados. Para um aprofundamento no conhecimento das tcnicas utilizadas para a manipulao de strings e outras tcnicas de programao em Python, pode-se consultar a documentao em http://www.python.org.br/wiki/DocumentacaoPython.

20

1.4.1. O uso de funes

O interpretador Python possui uma srie de funes embutidas para ajudar no nosso trabalho. Elas basicamente so blocos de cdigo contendo comandos e declaraes. J vimos algumas delas como a funo len() que retorna o comprimento de uma lista, a funo open() que abre um arquivo e a funo read() que l o contedo de um arquivo. Funes tambm podem ser chamadas de mtodos, quando elas pertencem a alguma classe. A caracterstica mais importante de uma funo a facilidade na reutilizao de cdigo. Alm disso, o uso de funes torna um programa mais legvel, pois abstrai detalhes do cdigo, e tambm mais confivel, pois geralmente so criadas a partir de cdigos exaustivamente testados. No entanto, as funes pr-definidas em Python, s vezes no so suficientes para atingir os nossos propsitos de maneira satisfatria, e por esse motivo, em vrias situaes muito til saber criar nossas prprias funes. Para definir uma funo, ns usamos a palavra reservada def, seguida pelo nome da funo, e seguida por um par de parnteses que podem conter ou no parmetros (dados para serem usados pela funo). Para finalizar a definio da funo usamos o smbolo de dois pontos. Na seo 1.4.1. usamos os seguintes comandos e declaraes: >>> dc = open("dom_casmurro.txt"), para abrir um texto >>> texto = dc.read() para ler o texto aberto , e o comando >>> len(texto) para obter o nmero de caracteres do texto. Poderamos combinar todas essas trs linhas de cdigo em apenas uma funo, desse modo a funo recm criada poderia ser usada para qualquer outro texto. Nomearemos essa funo de open_read_len(), que traduzindo significa abrir, ler, e medir o tamanho do texto que estiver entre os parnteses. Esse texto o parmetro da funo: >>> def open_read_len(texto): texto_aberto = open(texto) texto_lido = texto_aberto.read() return len(texto_lido)

21

Agora que a funo j est definida, podemos us-la simplesmente chamando-a pelo seu nome, seguido por um argumento entre parnteses: >>> open_read_len("dom_casmurro.txt") 373504 Denominamos de argumento o valor passado para o parmetro da funo. Nesse exemplo, o argumento passado foi o arquivo ("dom_casmurro.txt"). Na ltima linha de cdigo da funo usamos a palavra reservada return, que ir devolver um resultado assim que a funo for chamada. Nesse exemplo o valor retornado pela funo foi 373504. Se quisermos reutilizar a mesma funo, mas com outro texto, basta passar um diferente argumento no momento da chamada da funo, como no exemplo abaixo: >>> open_read_len("Memrias Pstumas de Brs Cubas.txt") 355706 Dessa vez passamos como argumento outro arquivo, contendo uma diferente obra de Machado de Assis, o romance Memrias Pstumas de Brs Cubas. E o valor retornado pela funo foi o de 355706 caracteres. Outra facilidade da linguagem de programao Python o uso de funes annimas. Funes annimas utilizam um construtor chamado de lambda. Funes lambda permitem a criao de uma funo em apenas uma linha. O cdigo a seguir exemplifica a diferena entre uma funo normal e uma funo lambda. Textos seguidos por # so comentrios: >>> >>> por >>> >>> # Atribuindo uma sentena varivel texto: texto = "Lambda uma funo annima composta apenas expresses." # Definindo uma funo normal: def retorna_comprimento(x): return len(x) >>> # Chamando a funo e passando a varivel texto como argumento: >>> retorna_comprimento(texto) 59 >>> # Criando uma funo lambda: >>> comprimento = lambda x: len(x) >>> # Chamando uma funo lambda dentro de um comando print: >>> print comprimento(texto) 59

22

Podemos observar que retorna_comprimento() e comprimento() fazem exatamente a mesma coisa, no entanto a funo lambda no possui o comando return, ela sempre retornar o valor da expresso depois do smbolo :. No decorrer deste trabalho, em algumas situaes usaremos funes lambda para simplificar a elaborao dos nossos programas.

1.5. A biblioteca NLTK

Apesar de Python ser considerada uma linguagem fcil para implementar algoritmos na rea de PLN, o estudo de Processamento de Linguagem Natural um tema complexo. Com o intuito de facilitar o entendimento desse assunto, em 2001 um grupo de desenvolvedores liderados por Steven Bird e Edward Loper da Universidade da Pensilvnia iniciou a criao de uma caixa de ferramentas na forma de uma eficiente biblioteca com vrios mtodos, funes e dados especialmente voltados para estudos na rea de lingustica computacional. Essa biblioteca de cdigo aberto chamada NLTK (Natural Language Toolkit), possui dezenas de corpora em diferentes idiomas e vrias ferramentas para processamento de textos, como tokenizadores3, classificadores de palavras, analisadores sintticos, assim como interfaces para bibliotecas de aprendizado de mquina. NLTK um software de cdigo aberto e pode ser baixado gratuitamente em http://www.nltk.org, alm do software, uma vasta documentao est disponvel no site, como artigos, livros, tutoriais, projetos e ideias relacionadas rea de PLN. Para a realizao do nosso trabalho, alm de Python e de NLTK, algumas outras ferramentas tambm foram utilizadas como NumPy que uma biblioteca para manipular vetores e matrizes multidimensionais, e executar tarefas de classificao e lgebra linear para clculos de probabilidade e a biblioteca Matplotlib que foi utilizada para as visualizaes de dados em duas dimenses como grficos de linhas e de barras. Essas duas ferramentas tambm podem ser obtidas gratuitamente no site do NLTK. Para utilizar a biblioteca NLTK em nossos programas, primeiramente devemos import-la utilizando o comando import NLTK. Para importar apenas determinados recursos dessa ferramenta, usamos o comando from ... import ..., dependendo do recurso desejado. Veremos a seguir alguns exemplos de corpus em portugus que esto inclusos no pacote NLTK:

Quebra uma string em tokens, que so os segmentos de texto ou smbolos que sero manipulados pelo Analisador Sinttico.

23

>>> from nltk.examples.pt import * *** Introductory Examples for the NLTK Book *** Loading ptext1, ... and psent1, ... Type the name of the text or sentence to view it. Type: 'texts()' or 'sents()' to list the materials. ptext1: Memrias Pstumas de Brs Cubas (1881) ptext2: Dom Casmurro (1899) ptext3: Gnesis ptext4: Folha de Sau Paulo4 (1994) >>> Nesse comando o smbolo * determina que se importe todos os recursos do mdulo pt, pertencente ao pacote examples da biblioteca NLTK. As primeiras quatro linhas do resultado se referem a uma breve descrio do mdulo, e a algumas instrues para usar certas funes pertencentes a ele e, nas quatro ltimas linhas aparecem os quatro textos importados e que formam a corpora do pacote de exemplos. Esses quatro textos so chamados de textos NLTK, pois j esto formatados, ou seja, j esto tokenizados, suas palavras e pontuaes esto separadas em grupos e, portanto, esto prontos para receber os procedimentos para o estudo lingustico. Em breve veremos como tokenizar os nossos prprios textos. O texto ptext2 se refere ao livro Dom Casmurro. S que nesse caso, como j explicamos todas as suas palavras, smbolos e pontuaes esto isolados na forma de tokens, diferentemente do texto dom_casmurro.txt que foi usado na seo 1.4 e que se refere a uma longa string. Vejamos a diferena entre os arquivos dom_casmurro.txt e ptext2: >>> dom_casmurro = open("dom_casmurro.txt").read() >>> len(dom_casmurro) 373504 >>> len(ptext2) 82088 Como o arquivo ptext2 representa uma lista de tokens, a funo len()ao invs de medir o seu comprimento em caracteres, medir o seu comprimento em tokens. Com o auxlio da funo count() que conta o nmero de vezes que uma especfica string aparece numa lista, verificaremos agora a porcentagem que a palavra Deus ocupa nos livros Gnesis e Dom Casmurro respectivamente:

A palavra So de So Paulo est grafada incorretamente como Sau, provavelmente devido a uma falta de ateno dos desenvolvedores do NLTK.

24

>>> from __future__ import division >>> 100 * ptext3.count('Deus') / len(ptext3) 0.53222158158513333 >>> 100 * ptext2.count('Deus') / len(ptext2) 0.08283793002631322 >>> O comando from __future__ import division usado para garantir que Python use diviso com ponto flutuante. fcil perceber apenas comparando os dois resultados que quando dividimos o nmero de ocorrncias da palavra Deus pelo nmero total de tokens do texto, que o texto 3 tem um carter bem mais religioso do que o texto 2, pois a palavra Deus representa 0,53% dos tokens do livro Gnesis, enquanto que na obra Dom Casmurro, a mesma palavra representa apenas 0,08% dos tokens do livro. Na segunda parte desse trabalho explicaremos melhor a importncia do uso de tokens para o estudo de PLN.

1.6. Alguns desafios na rea de Processamento de Linguagem Natural

Poderemos no futuro criar um sistema computacional que seja capaz de se comunicar conosco de maneira natural, e seremos capazes de no perceber se estamos ou no conversando com uma mquina? Uma mquina poder um dia pensar? Esse uma questo clssica na rea de inteligncia artificial proposta por Alan Turing em 1950. Em filmes de fico cientfica como 2001 - Uma Odisseia no Espao5 e em Blade Runner6 esse problema parece ter sido superado. Mas nos atuais sistemas comerciais de conversao ainda existem muitas limitaes, sendo que alguns j apresentam resultados significativos quando atuando de modo bem especfico.

2001: A Space Odyssey (br: 2001: Uma Odisseia no Espao) um filme americano de 1968 dirigido e produzido por Stanley Kubrick, co-escrito por Kubrick e Arthur C. Clarke. O filme lida com os elementos temticos da evoluo humana, tecnologia, inteligncia artificial e vida extraterrestre. 6 Blade Runner (br: Blade Runner: O Caador de Andrides ) um filme americano de 1982 dirigido por Ridley Scott. No incio do sculo XXI, uma grande corporao desenvolve um rob que mais forte e gil que o ser humano e se equiparando em inteligncia. So conhecidos como replicantes e utilizados como escravos na colonizao e explorao de outros planetas.

25

Sistema: Bom dia, em que posso ajud-lo? Usurio: Qual a previso do tempo para hoje? Sistema: Para o municpio de qual estado? Usurio: Para Porto Alegre no Rio Grande do Sul. Sistema: A temperatura mnima ser de 17C e a mxima de 29C, com sol e aumento de nuvens de manh e com pancadas de chuva tarde e noite. Na situao acima o sistema se comportou de maneira satisfatria, de acordo com a expectativa do usurio. E se o usurio desse uma resposta um pouco diferente para a segunda pergunta do sistema: Sistema: Para o municpio de qual estado? Usurio: Para a capital de So Paulo. Sistema: Por favor, reformule a sua resposta. Aparentemente o sistema no entendeu a resposta do usurio que, para ns humanos, foi perfeitamente inteligvel. Se esse sistema tivesse sido programado para entender que em determinadas situaes o usurio pode simplesmente responder para a capital de tal estado, no haveria um comportamento inesperado da mquina. O que esperar ento de um sistema para uma pergunta mais elaborada como: Qual a melhor poca do ano para tirar frias e viajar para o Nordeste? No preciso ser um agente de viagens para saber que a melhor poca do ano para aproveitar as frias no Nordeste fora do conhecido perodo de chuvas. Em uma conversa entre humanos nem precisaramos citar que estamos nos referindo ao nordeste brasileiro. Mas uma mquina precisaria armazenar e manipular conhecimento para isso, ela teria que saber que durante as frias a maioria dos brasileiros procura sol e calor e que isso corresponde ao adjetivo melhor da pergunta. Tambm teria que saber em quais meses chove menos na regio nordeste do Brasil. Em sistemas de computao preciso habilidade, conhecimento e at alguma sorte para obter respostas sensatas para algumas perguntas. Obter um sistema que responda automaticamente esses tipos de questes envolve uma srie de tarefas de processamento de linguagem como extrao de informaes, inferncia7 e sumarizao8 (Bird et al., 2009).

Inferncia o processo pela qual conclumos algo por meio de um raciocnio. De vrias proposies ns inferimos uma concluso. Inferir , portanto, chegar a uma resposta a partir de juzos anteriores.

26

Apesar de todos os avanos realizados, os atuais sistemas de linguagem natural ainda no conseguem obter um desempenho robusto satisfatrio. Esperamos que um dia esses difceis problemas na rea de inteligncia artificial possam ser superados, mas por enquanto teremos que conviver com essas graves limitaes. No entanto, acreditamos que at o fim desse trabalho, poderemos construir um sistema til para PLN, utilizando tcnicas simples e poderosas, que contribua para a construo de mquinas mais inteligentes.

2. PROCESSAMENTO DE TEXTO BRUTO E O USO DE RECURSOS LXICOS

2.1. Transformando um texto em tokens

J sabemos que a biblioteca NLTK possui vrios textos especialmente tratados para o estudo de PLN. No entanto, s vezes queremos usar os nossos prprios textos, e para que isso seja possvel necessrio prepar-los para as nossas finalidades de anlise lingustica. Como exemplo, extramos do website IDG Now! 9, uma curta reportagem do dia 6 de agosto de 2010, que diz que os sistemas de reconhecimento de voz ficaro mais inteligentes. O contedo da reportagem foi copiado em um arquivo chamado idg_voz.txt e salvo na mesma pasta onde Python est instalado. Vamos abrir esse arquivo e efetuar algumas operaes com as quais j estamos familiarizados:

A sumarizao compreende dois processos: a seleo do contedo relevante de uma mensagem fonte primria e sua organizao coerente. 9 http://idgnow.uol.com.br/mercado/2010/08/06/reconhecimento-de-voz-vai-ficar-mais-esperto-prometepesquisador/#&panel2-1

27

>>> texto_bruto = open("idg_voz.txt").read() >>> len(texto_bruto) 2018 >>> texto_bruto[0:50] 'Reconhecimento de voz vai ficar mais esperto, >>> type(texto_bruto) <type 'str'> >>>

prom'

A funo type() retorna o tipo de objeto. No nosso exemplo o objeto varivel texto_bruto uma string. Com o uso da funo len() podemos ver que essa string possui um total de 2018 caracteres. Para continuar nosso estudo, precisamos transformar esse texto, que uma string (lista de caracteres), em uma lista de tokens. Esse processo chamado de tokenizao e faz uso da funo word_tokenize(). Um token o nome tcnico para uma sequncia de caracteres - como carro, elas ou # que queremos tratar como um grupo (Bird et al., 2009). >>> tokens = nltk.word_tokenize(texto_bruto) >>> type(tokens) <type 'list'> >>> len(tokens) 423 >>> tokens[0:10] ['Reconhecimento', 'de', 'voz', 'vai', 'ficar', 'mais', 'esperto', ',', 'promete', 'pesquisador'] >>> Dessa vez quando usamos a funo type() e passamos tokens como argumento, o objeto retornado do tipo lista com o comprimento de 423 tokens. No comando tokens[0:10], fatiamos essa lista para exibir os seus 10 primeiros itens. E finalmente, para poder utilizar os recursos da biblioteca NLTK, transformaremos essa lista de tokens em um texto NLTK com o uso do mtodo nltk.Text(): >>> texto = nltk.Text(tokens) >>> type(texto) <class 'nltk.text.Text'> >>> Obtemos agora um objeto da classe texto NLTK, pronto para o estudo dos recursos lxicos da biblioteca NLTK.

28

2.2. Recursos lxicos

possvel efetuar em nossos textos diversas manipulaes, que fazem parte de um conjunto de operaes chamado de Recursos Lxicos. Um recurso lxico uma coleo de palavras ou frases que possuem algum tipo de informao associada, ele secundrio ao texto e, portanto, criado com o auxlio de textos (Bird et al., 2009). Um dicionrio um tipo de recurso lxico, pois uma coleo de palavras com suas respectivas definies e sentidos. Nos exemplos anteriores quando usamos o comando: >>> tokens = nltk.word_tokenize(texto_bruto), tambm fizemos uso de um recurso lxico simples, declarado como tokens, que carrega consigo informaes associadas ao seu nome. Podemos criar nossos prprios recursos lxicos dependendo do objetivo a ser alcanado no estudo de um texto. Para o prximo exemplo usaremos um texto que no sabemos sobre qual assunto trata, e com o uso de um recurso lxico simples chamado Distribuio de Frequncia, tentaremos descobrir o assunto do texto. Uma distribuio de frequncia verifica quantas vezes cada token aparece no texto. Ao identificarmos as palavras mais frequentes, poderemos deduzir em boa parte dos casos, sobre qual assunto o texto trata: >>> texto_bruto = open("texto_desconhecido.txt").read() >>> len(texto_bruto) 15914 >>> tokens = nltk.word_tokenize(texto_bruto) >>> texto = nltk.Text(tokens) >>> dist_freq = FreqDist(texto) >>> dist_freq <FreqDist with 2805 outcomes> >>> vocabulario = dist_freq.keys() >>> vocabulario[0:50] ['de', ',', 'e', 'o', 'que', 'a', '"', 'um', 'para', '.', 'com', 'em', 'do', 'os', 'uma', 'reconhecimento', 'como', 'palavras', 'voz', 'ou', 'da', 'sistema', 'mais', 'fala', 'na', 'programa', 'sao', 'O', 'as', 'sistemas', 'computador', 'nao', 'se', 'tambem', 'tem', 'usuarios', 'das', 'no', 'ser', 'som', '(', ')', 'pode', 'por', 'programas', 'E', 'Os', 'cada', 'entre', 'isso'] >>>

29

Analisando o resultado: O primeiro valor retornado, quando utilizamos a funo len(), nos indica que esse texto uma string com 15914 caracteres. Depois tokenizamos texto_bruto, e em seguida o transformamos em um texto NLTK. Na sexta linha, utilizamos a funo FreqDist() para transformar o objeto texto em uma distribuio de frequncia, e atribumos o resultado uma varivel objeto dist_freq. Quando chamamos o objeto dist_freq obtemos como resposta <FreqDist with 2805 outcomes>, ou seja, uma lista de distribuio de frequncia com 2805 resultados ou tokens. Na linha seguinte, quando usamos o comando vocabulario = dist_freq.keys(), a funo keys() organiza a lista de distribuio de modo que os tokens mais frequentes apaream distintamente no incio da lista. O resultado atribudo varivel vocabulario. No ltimo comando solicitamos que sejam exibidos os 50 tokens mais frequentes do texto. Obtemos alguns smbolos de pontuao como a vrgula ',' e o ponto '.'. Esses tokens no nos do o sentido do texto e, portanto so praticamente inteis. Palavras como 'e' e 'o' minsculos, e 'E' e 'O' maisculos so redundncias, pois significam a mesma coisa. Podemos eliminar os smbolos de pontuao e as palavras redundantes convertendo todos os tokens alfabticos do texto para caracteres minsculos: >>> vocab_minusculas = [w.lower() for w in vocabulario if w.isalpha()] >>> vocab_minusculas[0:50] ['de', 'e', 'o', 'que', 'a', 'um', 'para', 'com', 'em', 'do', 'os', 'uma', 'reconhecimento', 'como', 'palavras', 'voz', 'ou', 'da', 'sistema', 'mais', 'fala', 'na', 'programa', 'sao', 'o', 'as', 'sistemas', 'computador', 'nao', 'se', 'tambem', 'tem', 'usuarios', 'das', 'no', 'ser', 'som', 'pode', 'por', 'programas', 'e', 'os', 'cada', 'entre', 'isso', 'modelos', 'podem', 'atuais', 'ja', 'mas'] >>> Nesse comando apenas os tokens constitudos por caracteres alfabticos foram convertidos para tokens formados por caracteres minsculos. A funo lower() responsvel por essa converso e a funo isalpha() verifica se o token formado apenas por letras.

30

Em outras palavras, a varivel 'w' que aqui poderia ser qualquer outro nome, percorre cada item da lista vocabulario por intermdio do comando for, e se o token formado s por letras, ele ento convertido para minsculas e o resultado atribudo varivel vocab_minusculas. Alm dos pontos e palavras redundantes, percebemos a ocorrncia de outros tokens no muito teis para a compreenso do texto como de, que, para e uma. Vamos eliminar tambm as palavras com menos de quatro caracteres: >>> vocab_maior_3 = [w for w in vocab_minusculas if len(w) > 3] >>> vocab_maior_3[0:50] ['para', 'reconhecimento', 'como', 'palavras', 'sistema', 'mais', 'fala', 'programa', 'sistemas', 'computador', 'tambem', 'usuarios', 'pode', 'programas', 'cada', 'entre', 'isso', 'modelos', 'podem', 'atuais', 'muito', 'usuario', 'computadores', 'diferentes', 'estatisticos', 'frases', 'maneira', 'mesmo', 'palavra', 'quando', 'treinamento', 'dados', 'entanto', 'esses', 'falar', 'fonemas', 'grande', 'maior', 'pelo', 'ruido', 'voce', 'garofolo', 'ainda', 'algum', 'anos', 'bastante', 'comandos', 'criar', 'desempenho', 'duas'] >>> Verificamos a ocorrncia frequente de palavras como reconhecimento, palavras, sistemas, fala, programa, computador e frases. Apenas constatando a ocorrncia dessas palavras, podemos concluir que o texto deve falar sobre algum assunto relacionado ao reconhecimento de fala em sistemas computacionais, portanto essa simples tcnica de Distribuio de Frequncia nos auxiliou a dar sentido a um texto desconhecido. O texto original pode ser encontrado em: http://informatica.hsw.uol.com.br/reconhecimento-de-voz.htm Se quisermos saber quantas vezes um determinado token aparece no texto, basta fornecer a palavra procurada como um argumento ao objeto dist_freq: >>> dist_freq['reconhecimento'] 24 >>> dist_freq['palavras'] 20 >>> As palavras reconhecimento e palavras formam 44 dos 2805 tokens do texto, ou seja, elas correspondem juntas a aproximadamente 1,57% do texto.

31

Com o uso da funo plot(), que representa graficamente a participao dos tokens mais frequentes, possvel analisar visualmente a distribuio de frequncia de um texto. A funo plot() a seguir receber dois argumentos, o primeiro indica a quantidade de tokens considerados, e o segundo argumento, cumulative=True, solicita que os resultados sejam acumulados: >>> dist_freq.plot(40, cumulative=True)

Figura 2.1: Grfico com a frequncia acumulada dos 40 tokens mais usados no texto, que juntos correspondem a quase metade dos 2805 tokens identificados.

32

Observamos que apenas 40 dos tokens mais frequentes correspondem a mais de 1200 ocorrncias, quase a metade do texto.

2.3. Stopwords

Mais uma das ferramentas teis do NLTK o corpus chamado Stopwords, que nada mais do que uma coleo de listas de palavras com altas frequncias em vrios idiomas, como alemo, ingls, italiano, francs, portugus, sueco, etc. A lista NLTK de stopwords em portugus contem 203 palavras mais utilizadas em nosso idioma como que, para, uma, se, quando, muito, etc. Stopwords so geralmente palavras com pouca significncia lxica, e a sua presena em um texto dificulta que se percebam as outras palavras com maior importncia, criando o que poderamos chamar de poluio visual. Com o uso dessa ferramenta podemos filtrar um texto e assim obter um conjunto de palavras com maior significncia. >>> from nltk.corpus import stopwords >>> stopwords.words('portuguese')[0:10] ['de', 'a', 'o', 'que', 'e', 'do', 'da', 'para'] >>>

'em',

'um',

No primeiro comando importamos o corpus de stopwords da biblioteca NLTK e no segundo, acessamos os 10 primeiros itens da lista de stopwords em portugus. Agora iremos abrir o arquivo texto_desconhecido.txt, j usado nos exemplos anteriores, e filtr-lo usando stopwords: >>> texto_bruto = open("texto_desconhecido.txt").read() >>> tokens = nltk.word_tokenize(texto_bruto) >>> texto = nltk.Text(tokens) >>> df = nltk.FreqDist(w.lower() for w in texto if w not in stopwords) >>> for word in df.keys()[:20]: print word, df[word]

33

, 123 " 46 . 34 reconhecimento 24 palavras 20 voz 19 sistema 17 fala 15 programa 15 sao 14 nao 13 sistemas 13 tambem 13 computador 11 usuarios 11 ser 10 som 10 ( 9 ) 9 >>> As trs primeiras linhas do cdigo j so familiares. Na primeira abrimos e fizemos a leitura do arquivo texto_desconhecido.txt e atribumos o resultado varivel texto_bruto. Na linha seguinte tokenizamos texto_bruto, na terceira linha transformamos tokens em um texto NLTK e atribumos o resultado varivel texto. Na quarta linha atribumos varivel df o resultado de uma distribuio de frequncia onde percorremos cada token da varivel texto, transformamos cada item em letras minsculas para que no exista redundncia de palavras e verificamos se cada token no est na lista de stopwords. assim que ocorre a filtrao do texto. No ltimo comando solicitamos a impresso dos 20 primeiros tokens mais frequentes da distribuio de frequncia, juntamente com o nmero acumulado de vezes em que o token aparece na lista.

2.4. Expresses regulares e deteco de padres Expresses Regulares so s vezes consideradas o Canivete Suo do processamento de textos (McNeil, 2010, p.137).

34

Uma expresso regular pode ser vista como um conjunto de caracteres que especificam um padro. uma maneira que o programador usa para dizer como o computador deve procurar por certos formatos dentro do texto, e o que fazer aps encontr-los. Em vrias situaes, quando realizamos o estudo lingustico de um texto, procuramos por determinados padres da linguagem. Por exemplo, em alguns casos precisamos saber quais e quantas palavras no texto terminam com as letras ente, como em finalmente, regularmente, geralmente, concorrente, saliente, etc. Com o uso de Expresses Regulares, podemos identificar esses e outros padres. No exemplo a seguir usaremos um dos corpus disponveis pelo NLTK chamado ptext4, que se refere a artigos retirados do jornal folha de So Paulo de 1994. >>> import re >>> final_ido = [w for w in ptext4 if re.search('ido$', w)][:20] >>> type(final_ido) <type 'list'> >>> final_ido [u'reduzido', u'abolido', u'abolido', u'pedido', u'sido', u'marido', u'apreendido', u'r\xe1pido', u'r\xe1pido', u'Devido', u'r\xe1pido', u'sido', u'r\xe1pido', u'Partido', u'Unido', u'Partido', u'Unido', u'prometido', u'sido', u'assumido'] >>> Na primeira linha importamos o mdulo re de Python, que nos permite trabalhar com expresses regulares. O segundo comando pede para percorrer todos os tokens (aqui chamados de w) do arquivo ptext4, e se a busca pela expresso regular ido$ retornar True, o valor dos primeiros 20 itens da lista ser atribudo varivel final_ido. Em re.search a funo search (busca), do mdulo re (regular expressions), utilizada para procurar por padres de expresses regulares, nesse caso a expresso regular procurada definida como 'ido$'. O smbolo $ indica o final da string, isso quer dizer que e a expresso regular pode ser lida como qualquer string que tenha o final ido. No terceiro comando type(final_ido,)verificamos que a varivel final_ido se trata de uma lista de strings. No ltimo comando podemos ver como a varivel representada internamente. A letra u, antes de cada string, indica que ela est representada no

35

formato Unicode10. importante representar textos em portugus no formato Unicode, para evitar problemas com a leitura de caracteres especiais como , , , etc. Para imprimir o contedo na tela podemos usar o cdigo abaixo: >>> for palavra in final_ido: print palavra, reduzido abolido abolido pedido sido marido apreendido rpido rpido Devido rpido sido rpido Partido Unido Partido Unido prometido sido assumido >>> De forma geral, uma expresso regular composta por caracteres e metacaracteres, que nada mais so do que caracteres especiais como ^ $ * +? [ ] . Juntos, os caracteres e metacaracteres formam um padro de texto. Demonstraremos agora como podemos encontrar caracteres especficos em uma frase : >>> frase = 'Expresso Regular: Uma composio de smbolos, caracteres com funes especiais, que, agrupados entre si e com caracteres literais, formam uma seqncia, uma expresso. Essa expresso interpretada como uma regra, que indicar sucesso se uma entrada de dados qualquer casar com essa regra, ou seja, obedecer exatamente a todas as suas condies.'11 >>> re.findall(r'[aeiou]', frase) ['e', '\xe3', 'o', 'e', 'u', 'a', 'a', 'o', 'o', 'i', '\xe3', 'o', 'e', '\xed', 'o', 'o', 'a', 'a', 'e', 'e', 'o', 'u', '\xf5', 'e', 'e', 'e', 'i', 'a', 'i', 'u', 'e', 'a', 'u', 'a', 'o', 'e', 'e', 'i', 'e', 'o', 'a', 'a', 'e', 'e', 'i', 'e', 'a', 'i', 'o', 'a', 'u', 'a', 'e', '\xfc', '\xea', 'i', 'a', 'u', 'a', 'e', 'e', '\xe3', 'o', 'a', 'e', 'e', '\xe3', 'o', '\xe9', 'i', 'e', 'e', 'a', 'a', 'o', 'o', 'u', 'a', 'e', 'a', 'u', 'e', 'i', 'i', 'a', '\xe1', 'u', 'e', 'o', 'e', 'u', 'a', 'e', 'a', 'a', 'e', 'a', 'o', 'u', 'a', 'u', 'e', 'a', 'a', 'o', 'e', 'a', 'e', 'a', 'o', 'u', 'e', 'a', 'o', 'e', 'e', 'e', 'e', 'a', 'a', 'e', 'e', 'a', 'o', 'a', 'a', 'u', 'a', 'o', 'i', '\xf5', 'e'] >>>
10

O Padro Unicode especifica a representao do texto em software e padres modernos. O Unicode fornece um nico nmero para cada caractere, no importa a plataforma, no importa o programa, no importa a lngua. (Em: <http://unicode.org/standard/translations/portuguese.html>. Acesso em: 09 maio 2012.) 11 http://aurelio.net/regex/

36

Na primeira linha do exemplo atribumos uma string varivel frase. No segundo comando utilizamos a funo findall (encontre tudo), seguida por dois parmetros entre parnteses. No primeiro parmetro r'[aeiou]' lido como uma expresso regular r formada pelos caracteres entre os colchetes. E o segundo parmetro a varivel frase. Como resultado, obtemos uma lista com todas as ocorrncias das vogais minsculas definidas entre os colchetes e encontradas na varivel frase, incluindo caracteres acentuados como ou , representados internamente nos formatos hexadecimais e3 e e9, respectivamente. Os caracteres \x representam um escape sequence (sequncia de escape), como j vimos anteriormente na seo 1.4 deste trabalho. No processamento de linguagem natural algumas das utilidades para as expresses regulares so: tokenizar sentenas, isolar e substituir caracteres e palavras, validar campos em formulrios, traduzir palavras, remover caracteres repetidos e verificar ortografia. No entanto devemos ser cautelosos e especficos no seu uso, pois elas podem se tornar complexas rapidamente. Para saber mais sobre o uso de expresses regulares em Python visitem a pgina: http://docs.python.org/library/re.html

3. AS CATEGORIAS LXICAS

Palavras podem ser divididas em grupos chamados de Classes Gramaticais, como verbos, adjetivos, pronomes, advrbios, preposies, substantivos, etc. Em Python esses grupos so conhecidos como Categorias Lexicais Uma das tcnicas utilizadas em Python para classificar as palavras em um texto chamada de tagging ou etiquetao. Na etiquetao atribuda uma etiqueta para cada palavra, como N para substantivo, V para verbo, PREP para preposio, ART para artigo, e assim por diante. No prximo exemplo veremos o trecho de um texto j etiquetado que faz parte do corpus Mac-Morpho12 do NLTK: >>> import nltk >>> nltk.corpus.mac_morpho.tagged_words()[:10]
12

Mac-Morpho se trata de uma coleo de textos em portugus do Brasil, extrados de diferentes sees do jornal Folha de So Paulo de 1994. Esse corpus possui mais de um milho de palavras j etiquetadas.

37

[(u'Jersei', u'N'), (u'atinge', u'V'), (u'm\xe9dia', u'N'), (u'de', u'PREP'), (u'Cr$', u'CUR'), (u'1,4', u'NUM'), (u'milh\xe3o', u'N'), (u'em', u'PREP|+'), (u'a', u'ART'), (u'venda', u'N')] >>> No comando >>> nltk.corpus.mac_morpho.tagged_words()[:10], solicitamos as primeiras dez palavras etiquetadas do corpus mac_morpho, e como resultados obtemos uma lista de dez tuplas, contendo a palavra e sua respectiva etiqueta. Uma tupla uma sequncia, assim como listas e strings. A diferena que ela imutvel, portanto, uma vez criada, no pode ser modificada. Ela tambm pode ser indexada e isso permite que os seus elementos sejam acessados por ndices. As tuplas so criadas usando parnteses e seus elementos so separados por vrgulas. Vamos imprimir o resultado do exemplo anterior em uma forma mais fcil para leitura, usando o comando print: >>> tuplas = nltk.corpus.mac_morpho.tagged_words()[:10] >>> for x, y in tuplas: print x, y Jersei N atinge V mdia N de PREP Cr$ CUR 1,4 NUM milho N em PREP|+ a ART venda N >>> Primeiro atribumos varivel tuplas uma lista com as dez primeiras tuplas do corpus Mac-Morho. Posteriormente utilizamos o comando for para percorrer todos os elementos de tuplas e atribumos o primeiro elemento de cada uma varivel x, e o segundo a varivel y. Na sequncia usamos o comando print para imprimir x (a palavra) e y (a etiqueta). No resultado, Jersei possui a etiqueta N, que significa substantivo, atinge possui a etiqueta V, que significa um verbo, as palavras mdia, milho e venda tambm esto etiquetadas como substantivos.

38

3.1. O processo de etiquetao

Etiquetao o processo de converter uma sentena, que uma lista de palavras, em uma lista de tuplas, onde cada tupla se encontra na formato (palavra, etiqueta). A etiqueta indica se a palavra um substantivo, um adjetivo, um artigo, etc. Aps a tokenizao, o processo de etiquetao a segunda etapa no processamento de linguagem natural. Ao etiquetar as palavras podemos extrair frases com significados de um texto. Para etiquetar palavras usamos etiquetadores. A maioria dos etiquetadores so treinveis. Eles usam uma lista de sentenas j etiquetadas chamadas de sentenas treinadoras. Nos nossos exemplos usaremos as sentenas treinadoras do corpus Mac-Morpho.

3.1.1. Etiquetador padro

O modo mais simples para etiquetar palavras usando o etiquetador padro. O NLTK possui um etiquetador padro chamada DefaultTagger que atribui a mesma etiqueta para todas as palavras encontradas em um texto. Apesar de no fazer muito sentido marcar toda palavra com a mesma etiqueta, o etiquetador padro til para etiquetar palavras desconhecidas. Assim, ao combinarmos o etiquetador padro com etiquetadores mais robustos, poderemos agrupar todas as palavras desconhecidas em uma mesma categoria. >>> from nltk.tag import DefaultTagger >>> etiquetador = DefaultTagger('N') >>> etiquetador.tag(['processamento', 'de', 'linguagem', 'natural', u'', 'uma', u'rea', 'da', u'inteligncia', 'artificial']) [('processamento', 'N'), ('de', 'N'), ('linguagem', 'N'), ('natural', 'N'), (u'\xe9', 'N'), ('uma', 'N'), (u'\xe1rea', 'N'), ('da', 'N'), (u'intelig\xeancia', 'N'), ('artificial', 'N')] >>> No primeiro comando importamos a classe DefaultTagger do pacote tag. Na segunda linha criamos um objeto etiquetador padro, chamado de etiquetador, que recebe a etiqueta N como argumento.

39

No terceiro comando o mtodo tag do objeto etiquetador recebe como argumento uma lista de palavras e a converte em uma lista de tuplas, contendo as palavras e suas respectivas etiquetas. Todas as palavras receberam a etiqueta 'N' que significa substantivo.

3.1.2. Avaliando a preciso de um etiquetador

Para saber o quo preciso um etiquetador, usamos o mtodo evaluate(), que recebe uma lista de sentenas treinadoras como as sentenas do corpus Mac-Morpho, que j se encontram corretamente etiquetadas. Vamos verificar a preciso do nosso etiquetador padro criado no exemplo anterior: >>> from nltk.corpus import mac_morpho >>> sentencas_treinadoras = mac_morpho.tagged_sents()[0:15000] >>> etiquetador.evaluate(sentencas_treinadoras) 0.20727113660113247 >>> No primeiro comando importamos o corpus Mac-Morpho. No segundo, atribumos varivel sentencas_treinadoras as primeiras 15 mil sentenas do corpus mac_morpho. Nesse momento criado um subconjunto do corpus mac_morpho, contendo 15 mil sentenas corretamente etiquetas. No terceiro comando, passamos a varivel sentencas_treinadoras como argumento para o mtodo evaluate() do objeto etiquetador, para verificar a preciso do nosso etiquetador. Como resultado obtemos um valor de 20, 72%. Ou seja, nas 15 mil primeras sentenas do corpus Mac-Morpho, apenas aproximadamente 20% das palavras so realmente substantivos, e portanto receberam a etiqueta 'N'corretamente.

3.1.3. Etiquetador Unigram

Um etiquetador Unigram baseado simplesmente em dados estatsticos. Ele atribui uma etiqueta mais provvel para cada token. Por exemplo, a palavra azul

40

pode ser classificada como um adjetivo, como em O cu azul, ou como substantivo em A cor azul. No etiquetador Unigram a palavra azul ser sempre representada como um adjetivo, pois baseado em dados estatsticos, essa palavra aparece na maioria dos textos como um adjetivo, e por isso receber a etiqueta ADJ. Usaremos a mesma lista de palavras do exemplo anterior para receber etiquetas com o uso do etiquetador Unigram, e depois mediremos a preciso desse etiquetador. >>> from nltk.tag import UnigramTagger >>> sentencas_treinadoras = mac_morpho.tagged_sents()[0:15000] >>> etiquetador = UnigramTagger(sentencas_treinadoras) >>> etiquetador.tag(['processamento', 'de', 'linguagem', 'natural', u'', 'uma', u'rea', 'da', u'inteligncia', 'artificial']) [('processamento',u'N'),('de',u'PREP'), ('linguagem',u'N'), ('natural',u'ADJ'),(u'\xe9',u'V'),('uma',u'ART'),(u'\xe1rea ',u'N'),('da',u'NPROP'),(u'intelig\xeancia','N'),('artifici al',u'ADJ')] >>> No primeiro comando importamos a classe UnigramTagger do pacote tag. No segundo, atribumos varivel sentencas_treinadoras as primeiras 15 mil sentenas etiquetadas do corpus mac_morpho. No terceiro comando, passamos o argumento sentencas_treinadoras para treinar a classe UnigramTagger(), e o resultado desse treinamento atribudo varivel-objeto etiquetador. Nesse momento o objeto etiquetador tem uma referncia baseada em 15 mil frases j corretamente etiquetadas. No ltimo comando o mtodo tag do objeto etiquetador recebe como argumento uma lista de palavras e a converte em uma lista de tuplas, contendo as palavras e suas respectivas etiquetas. Para imprimir o resultado em uma forma mais legvel podemos usar o comando print, como j foi explicado nos captulos anteriores.

>>> tuplas = etiquetador.tag(['processamento', 'de', 'linguagem','natural',u'','uma',u'rea','da',u'intelignci a', 'artificial']) >>> for x, y in tuplas: print x, y

41

processamento N de PREP linguagem N natural ADJ V uma ART rea N da NPROP inteligncia N artificial ADJ >>> No resultado as palavras processamento, linguagem, rea e inteligncia foram corretamente marcadas como substantivos, a maioria das outras tambm foram, como 'de' (preposio), 'natural' (adjetivo), '' (verbo), 'uma' (artigo), e 'artificial' (adjetivo). A palavra 'da' foi etiquetada como nome prprio 'NPROP', o que um erro, pois 'da' uma contrao entre a preposio de e o artigo feminino a. Os pesquisadores que criaram o corpus Mac-Morho substituram todas as contraes da por de_PREP| + a_ART, e por isso que a palavra da do nosso exemplo foi marcada incorretamente. Se quisssemos que ela fosse devidamente etiquetada, deveramos mudar a nossa frase para: processamento de linguagem natural uma rea de a inteligncia artificial. Mesmo assim, conseguimos desta vez um etiquetador bem mais preciso do que o etiquetador padro. Veremos agora como medir a preciso do etiquetador Unigram: >>> etiquetador.evaluate(sentencas_treinadoras) 0.87600245449464142 >>> Analisando o resultado, chegamos marca de 87% de preciso. Nenhum outro etiquetador mais preciso do que esse. No entanto, 13% dos tokens no foram corretamente etiquetados, mesmo usando sentenas treinadoras idnticas s sentenas avaliadoras. Isso ocorreu porque, como j citamos anteriormente, o UnigramTagger se baseia em dados estatsticos e por isso no 100% preciso. Azul por exemplo, nem sempre um adjetivo, a palavra casa pode ser um substantivo, mas s vezes um verbo, e assim ocorre com diversas outras palavras.

42

3.1.4. Combinando etiquetadores

Podemos aumentar a preciso do processo de etiquetao quando combinamos diferentes etiquetadores. Nessa tcnica, dois ou mais etiquetadores so utilizados em conjunto. Se um etiquetador no for capaz de etiquetar uma palavra corretamente, a tarefa passada para o prximo. Nos exemplos a seguir usaremos um diferente trecho do corpus Mac-Morpho para medir a preciso do UnigramTagger, depois o combinaremos com o DefaultTagger para ver se conseguimos um etiquetador com maior preciso: >>> from nltk.corpus import mac_morpho >>> from nltk.tag import UnigramTagger >>>sentencas_treinadoras=mac_morpho.tagged_sents()[0:1000] >>> etiquetador = UnigramTagger(sentencas_treinadoras) >>> sentencas_teste = mac_morpho.tagged_sents()[1000:2000] >>> etiquetador.evaluate(sentencas_teste) 0.72472077122351042 Primeiro importamos o corpus mac_morpho e em seguida importamos a classe UnigramTagger. Na terceira linha atribumos varivel sentenas_treinadoras as primeiras 1000 sentenas etiquetadas (de 0 a 999), do corpus mac_morpho. No quarto comando, passamos o argumento sentencas_treinadoras para treinar a classe UnigramTagger(), e o resultado desse treinamento atribudo varivel-objeto etiquetador. No quinto comando criamos uma varivel chamada sentencas_teste, que tambm recebe 1000 sentenas do corpus mac_morpho, s que de um diferente trecho do corpus, iniciando na sentena de nmero 1000 e indo at a sentena de nmero 1999. No ltimo comando avaliamos a preciso do nosso etiquetador usando como argumento a varivel sentenas_teste, obtendo uma preciso de 72,47%.

Agora iremos combinar o UnigramTagger com o DefaultTagger: >>> from nltk.tag import DefaultTagger >>> etiquetador1 = DefaultTagger('N')

43

>>> etiquetador2 = UnigramTagger(sentencas_treinadoras, backoff=etiquetador1) >>> etiquetador2.evaluate(sentencas_teste) 0.77564020894381447 No primeiro comando importamos a classe DefaultTagger. No segundo comando criamos um objeto etiquetador padro, chamado de etiquetador1, que recebe a etiqueta N (substantivo) como argumento. No terceiro comando criamos um segundo objeto etiquetador chamado etiquetador2, baseado na classe UnigramTagger, que recebe como argumento as variveis sentenas_treinadoras e backoff=etiquetador1. A declarao backoff=etiquetador1 significa que o etiquetador1 marcar com a etiqueta N todas as palavras que o etiquetador2 no conseguir marcar. Seria como dizer: Etiquetador2, marque as palavras que encontrar baseando-se nas sentenas treinadoras, caso no consiga, use o etiquetador1. Aparentemente no h sentido em classificar tudo o que for desconhecido como substantivo, mas baseada em dados estatsticos, a chance de uma palavra desconhecida ser um substantivo de aproximadamente 20%, como j foi visto na seo 3.1.2., quando atribumos a etiqueta N para todas as palavras das primeiras 15 mil sentenas do corpus Mac-Morpho. No ltimo comando avaliamos o etiquetador2, e podemos constatar que o seu ganho de preciso foi de aproximadamente 5% (0.77564 menos 0.72472). Alm dos etiquetadores vistos at agora, existem outros como BigramTagger, TrigramTagger, Brill Taggers e TnT Taggers, que podem auxiliar no aumento de preciso de um etiquetador. Tambm podemos utilizar outras tcnicas como o uso de expresses regulares, que em conjunto com os etiquetadores j mencionados, podem levar a preciso de um etiquetador a mais de 95%.

44

4. ANLISE SINTTICA PARCIAL

A Anlise Sinttica Parcial o processo de extrair pequenas frases de sentenas etiquetadas. diferente da Anlise Sinttica Completa, pois na primeira estamos apenas interessados em frases curtas ao invs de rvores de Anlise Sintticas Completas, que sero estudadas posteriormente. Falaremos nesse captulo sobre algumas tcnicas utilizadas em PLN para extrair pequenas frases de um texto, apenas observando padres particulares em uma sequncia de palavras etiquetadas.

4.1. Expresses regulares para a identificao de padres

Com o uso de expresses regulares modificadas podemos identificar padres em uma linguagem. Esses padres definem quais os tipos de palavras compem um bloco de uma sentena. Expresses regulares tambm podem definir padres para palavras que no desejamos que faam parte de um bloco. Agrupar palavras o processo de isolar padres em uma sentena para manter as palavras em um bloco. O contrrio disso o processo de desagrupar. Uma regra de agrupamento especifica quais grupos devem formar um bloco, e uma regra de desagrupamento especifica quais blocos isolar. Para criar uma regra, a primeira tarefa definir os padres do agrupamento. Esses padres so expresses regulares modificadas equivalentes s sequncias de palavras etiquetadas. Para definir uma etiqueta, colocamo-la entre os sinais de menor que (<) e maior que (>), como em <N>, que especifica uma etiqueta para um substantivo. Vrias etiquetas podem ser combinadas, como em <ART><N><ADJ>, que equivalem a um artigo, seguido por um substantivo, seguido por um adjetivo. Uma frase que respeita esse padro poderia ser: O carro azul, pois O um artigo, seguido por carro que um substantivo, seguido por azul, um adjetivo. A sintaxe das expresses regulares pode ser utilizada tanto dentro como fora dos smbolos < >.

45

Em <N.*> por exemplo, queremos encontrar qualquer etiqueta que inicie com a letra N, seguida por qualquer outro smbolo (representado pelo sinal de pontuao), zero ou mais vezes (representado pelo metacaractere asterisco). Portanto, esse padro reconhecer a etiqueta que representa um substantivo no singular, como em <N>, pois a etiqueta comea com a letra N seguida de nenhuma letra. Esse padro tambm reconhecer a etiqueta para substantivos no plural <NP>, pois o padro <N.*> tambm reconhece a letra N seguida por qualquer outra letra. Os substantivos computador e computadores se encaixam nessa regra, pois possuem as etiquetas <N> e <NP>, respectivamente. Um exemplo do uso da sintaxe de expresses regulares fora dos smbolos < > poderia ser como em <ART>?<N><ADJ>+. O metacaractere ? especifica que a etiqueta anterior a ele (<ART>), opcional, e o metacaractere + especifica que a etiqueta anterior a ele (<ADJ>), deve aparecer uma ou muitas vezes. As blocos de texto a seguir obedecem a esse padro: A cidade grande: um artigo seguido por um substantivo e por um adjetivo. Cincia moderna: um substantivo seguido por um adjetivo, (a presena de um artigo no incio da frase artigo opcional). O edifcio verde claro: um artigo seguido por um substantivo, seguido por dois adjetivos. A criao de padres para agrupar e desagrupar blocos de palavras em um texto depende muito da necessidade e da criatividade do desenvolvedor. Podemos dizer que um processo de tentativa e acerto, e que vai se aperfeioando com prtica.

46

4.2. Utilizando gramticas para agrupar e desagrupar palavras

Um padro para agrupar blocos definido entre chaves normais, como em {<ART><N>}, e um padro para desagrup-los definido entre chaves opostas com em }<V>{. A regra de agrupamento ou desagrupamento que especifica o bloco entre as chaves chamada de gramtica do bloco ou gramtica da frase. Vamos agora criar uma gramtica para extrair frases sem verbos de uma sentena, e para isso usaremos regras de agrupamento e de desagrupamento. Em seguida construiremos uma rvore de anlise para a sentena. >>> from nltk.chunk import RegexpParser >>> analis_gram = RegexpParser(r''' FN: {<ART><N><.*>*<N>} }<V>{ ''') >>> A primeira linha do cdigo importa a classe RegexParser do pacote chunk da biblioteca NLTK. O pacote chunk possui uma srie de classes e interfaces para identificar grupos lingusticos no sobrepostos, como frases verbais e nominais. RegexParser uma classe do pacote chunk, que usa expresses regulares para analisar as etiquetas de um texto e transform-lo em blocos. Na segunda linha instanciamos um objeto da classe RegexpParser e o chamamos de analis_gram (analisador gramatical), que recebe entre os parnteses as regras para agrupamento e desagupamento do texto. O caractere r especifica que devemos interpretar os cdigos nas prximas linhas como expresses regulares, e as trs aspas simples colocadas antes e depois das declaraes significam que podemos escrever o cdigo em mltiplas linhas, isso serve apenas para melhorar a leitura do mesmo. Na terceira linha definimos a nossa gramtica como FN (frase nominal). Uma frase nominal aquela que no possui verbos. Nas linhas 4 e 5 definimos as regras para a gramtica. A primeira regra, entre chaves normais, diz que devemos agrupar o padro formado por um artigo <ART>, seguido por um substantivo <N>, seguido por zero ou mais palavras contendo qualquer tipo de etiqueta <.*>*, at encontrar outro substantivo <N>. A segunda regra, entre chaves opostas, diz que os verbos <V>, devem ser desagrupados.

47

Utilizaremos o nosso analisador gramatical para analisar a sentena O mundo possui diversos idiomas, que j est com as palavras devidamente etiquetadas. >>>analis_gram.parse([('O','ART'),('mundo', N'),('possui', 'V'), ('diversos', 'ADJ'), ('idiomas', 'N')]) Tree('S', [Tree('FN', [('O', 'ART'), ('mundo', 'N')]), ('possui', 'V'), Tree('FN', [('diversos','ADJ'), ('idiomas', 'N')])]) Na primeira linha de cdigo, como o objeto analis_gram foi instanciado a partir da classe RegexpParser, usamos o mtodo parse dessa classe para aplicar as regras da gramtica nas palavras etiquetadas. Como resultado, obtemos a sentena na forma de uma rvore Tree. O primeiro n da rvore S significa sentena. Os ns restantes representam os blocos encontrados e representam subrvores da sentena. Cada subrvore definida dentro de colchetes, e inicia com a palavra Tree, seguida de tuplas entre parnteses que contm a palavra e sua respectiva etiqueta. Por exemplo, no trecho [Tree('FN', [('O', 'ART'), ('mundo', 'N')], temos uma subrvore do tipo FN (frase nominal), formada pela lista de tuplas [('O', 'ART'), ('mundo', 'N')]. Essa subrvore denominada FN pois atende as regras estabelecidas pela nossa gramtica. Notem que a tupla('possui', 'V'), no faz parte de uma subrvore, pois pela gramtica os verbos devem ser desagrupados e por isso ela no precedida por Tree'FN'. Para entendermos melhor o resultado do cdigo, podemos desenhar a rvore utilizando o mtodo draw(): >>> arvore = analis_gram.parse([('O', 'ART'), ('mundo', 'N'),('possui', 'V'), ('diversos', 'ADJ'), ('idiomas', 'N')]) >>> arvore.draw()

48

Obtemos agora uma representao grfica da sentena que uma rvore divida em ns e folhas. O primeiro n S representa toda a sentena, os ns FN representam subrvores de frases nominais. As folhas O ART e mundo N, por exemplo, formam uma frase nominal e por isso pertencem ao n FN. A folha possui V no pertence a nenhuma subrvore, pois foi desagrupada pela regra gramatical. Existem outras regras para manipular blocos, como as regras de fuso, que unem blocos distintos e as regras de diviso que dividem blocos. Juntas, as regras de agrupamento, desagrupamento, fuso e diviso, so suficientes para lidar com a maioria das tarefas envolvidas na anlise gramatical de blocos de sentenas.

5. CONSTRUINDO UM SISTEMA PARA CORREO VERBAL

Agora que j sabemos como extrair blocos de frases em uma sentena etiquetada, veremos o que podemos fazer com esses grupos. Um exemplo poderia ser o de criar um filtro para excluir palavras de pouco significado em um texto, obtendo assim apenas as palavras mais importantes. No texto O parque estava lotado, se filtrarmos o artigo O e o verbo estava, ficaremos apenas com o substantivo parque e o adjetivo lotado. Mesmo assim conseguiremos entender o significado da frase parque lotado. Esse tipo de manipulao de textos bastante usado quando preciso extrair informaes relevantes de grandes quantidades de dados. Em outro exemplo poderamos criar um analisador de textos para obter todas as palavras compostas de um documento, como papel-moeda, arco-ris, meio-dia, obra-prima, etc. Ou talvez para obter os nomes prprios contidos no documento, como Paulo, Maria, Museu do Ipiranga ou Avenida Paulista. Os tipos de aplicaes que podem utilizar essas tcnicas so os mais diversos e dependem muito da necessidade e da criatividade do usurio. Como a quantidade de texto no formato eletrnico vem crescendo a taxas enormes, cada vez mais ser importante conhecer esses princpios de manipulao de textos para que possamos ter acesso s informaes desejadas. Nesse captulo construiremos um pequeno sistema para realizar a correo de verbos em sentenas.

49

A ideia que nos motivou a criar um corretor verbal foi a de demonstrar como as metodologias e tcnicas aplicadas nesse sistema, podem ser utilizadas em sistemas semelhantes, como corretores ortogrficos e outros mais complexos, como os corretores gramaticais que fazem amplo uso dos conceitos do processamento de linguagem natural.

5.1. Dicionrios em Python

Antes de tudo, precisamos introduzir brevemente um conceito pertencente linguagem de programao Python, chamado de dicionrio. Um dicionrio em Python representa uma coleo de elementos formada por pares constitudos por chave e valor respectivamente. Eis um exemplo de dicionrio: nosso_dicionario = 8: 'oito'} {'idade' : 20, 'estado' : SP,

>>> print nosso_dicionario[8] oito # O valor da chave 8 a string oito. E o valor da chave idade o nmero inteiro 20. Dicionrios podem armazenar dados como inteiros, decimais, listas, tuplas, strings, etc., e so declarados dentro dos smbolos de chaves, { }. O smbolo de dois pontos separa a chave do valor, e a vrgula separa os pares.

5.2. Definindo os dicionrios

A primeira tarefa para criar o nosso corretor verbal ser a de definir os dicionrios. Esses dicionrios armazenaro a conjugao do verbo ser nos tempos presente do indicativo e pretrito imperfeito, e nas 3s. pessoas, do singular e do plural. E cada tupla do dicionrio armazenar o verbo e sua respectiva etiqueta. A funo dos dicionrios apontar a conjugao correta de um verbo que se encontra incorretamente conjugado. A tabela abaixo exemplifica as conjugaes:

50

Presente do Indicativo (PI) Pretrito Imperfeito (PIm)

Verbo ser 3. Pessoa do Singular 3. Pessoa do Plural (VS) (ele/ela) (VP) (eles/elas) so era eram

Criaremos agora dois dicionrios, um de singular para plural e outro de plural para singular: >>> singular_plural = { ('', 'VSPI'): ('so', 'VPPI'), ('era', 'VSPIm'): ('eram', 'VPPIm') } >>> plural_singular = { ('so', 'VPPI'): ('', 'VSPI'), ('eram', 'VPPIm'): ('era', 'VSPIm') } >>>

No primeiro bloco de cdigo criamos um dicionrio de Python chamado de singular_plural, que indica qual a correo dos verbos que esto no singular para suas respectivas conjugaes no plural. Entre as chaves inserimos quatro tuplas. A primeira tupla ('', 'VSPI') a chave do valor ('so', 'VPPI'). Isso quer dizer que quando o corretor verbal solicitar a correo da palavra , a chave-tupla ('', 'VSPI') apontar para o valor ('so', 'VPPI'). A tupla ('era', 'VSPIm') apontar para ('eram', 'VPPIm'). Esse princpio tambm se aplica para as tuplas restantes. No segundo bloco de cdigo criamos outro dicionrio de Python chamado de plural_singular, que indica qual correo dever ser feita para os verbos que se encontram incorretamente conjugados no plural. As etiquetas utilizadas representam uma juno das etiquetas do verbo e suas respectivas flexes gramaticais (singular e plural), com as etiquetas dos tempos verbais. A etiqueta VPPIm por exemplo, significa Verbo Plural Pretrito Imperfeito. Para deduzir o significado das outras etiquetas, basta consultar a tabela.

51

5.3. Definindo uma funo auxiliar

Agora que j construmos os dicionrios, o prximo passo a ser tomado o de definir uma funo auxiliar que percorrer as tuplas de um bloco para verificar se elas possuem um determinado atributo. Caso esse atributo seja encontrado, a funo retornar o ndice da primeira tupla onde o atributo foi encontrado, caso contrrio ela retornar nada. O atributo pode ser uma etiqueta de verbo ou de substantivo. >>> def indice_atributo(frase, atributo, inicio=0, incremento=1): comprimento = len(frase) final = comprimento if incremento > 0 else -1 for indice in range(inicio, final, incremento): if atributo(frase[indice]): return indice return None >>> Para o texto a seguir, adotaremos como referncia uma frase de comprimento n igual a 5 tuplas. Na primeira linha do cdigo usamos a palavra chave def para definir uma funo que nomearemos de indice_atributo. A funo possui quatro parmetros, o primeiro (frase) uma lista de tuplas a ser analisada, o segundo (atributo) o resultado de uma funo lambda que retorna a etiqueta identificadora de um verbo ou de um substantivo. Os outros dois parmetros (inicio e incremento) j iniciam com valores padres 0 e 1 respectivamente. O parmetro inicio se refere ao primeiro ndice do bloco a ser analisado (ndice 0), e incrementado pela varivel incremento a cada looping. Na linha comprimento = len(frase), atribumos varivel comprimento o tamanho da varivel frase, com o auxilio da funo len() de Python. Portanto, o valor de comprimento ser 5. Na declarao final = comprimento if incremento > 0 else -1, a varivel final receber o valor 5 se a varivel incremento for positiva, caso contrrio final receber o valor -1. Esse valor -1 determina que a lista seja percorrida de frente para trs, pois em alguns momentos o corretor verbal precisar conferir se a tupla que antecede um verbo constituda por um substantivo. Poderemos compreender melhor essa situao quando executarmos o corretor verbal. No comando seguinte, for, nomeamos uma varivel de indice que percorrer a lista de tuplas. Para isso utilizamos a funo embutida de Python

52

range(). A finalidade dessa funo a de interar sobre uma sequncia numrica que so os parmetros entre parnteses. O parmetro, inicio, determina que o looping inicie no ndice 0 da tupla, e que seja incrementado por 1 (incremento=1), at alcanar o ndice final 5. Em if atributo(frase[indice]):, determinado que se a varivel atributo (uma etiqueta verbal ou nominal), for encontrada na tupla, o ndice dessa tupla ser retornado pela funo. Caso o atributo procurado no seja encontrado na frase, a funo retornar None, uma palavra reservada de Python que em portugus significa Nada ou Nenhum.

5.4. Definindo uma funo para correo Verbal

Aps definirmos os dicionrios e a funo auxiliar, s nos resta agora definir a funo responsvel pela correo verbal, e isso o que faremos a seguir. Com a inteno de facilitar a leitura do cdigo, copiamos a tela do editor interativo Python que contm a definio da funo corretor_verbal e a anexamos na prxima pgina deste trabalho. Na sequncia explicaremos o funcionamento da funo.

53

54

Na primeira linha do cdigo definimos a funo corretor_verbal, que recebe frase como parmetro. Esse parmetro uma lista de tuplas da frase a ser analisada. Cada tupla conter a palavra e sua respectiva etiqueta. Na linha seguinte temos: indice_verbo = indice_atributo(frase, lambda (palavra, etiqueta): etiqueta.startswith('V')), onde criada uma varivel chamada indice_verbo que receber o ndice da tupla onde o primeiro verbo encontrado na frase. Para que isso ocorra, a funo indice_atributo percorrer sequencialmente as tuplas da frase at encontrar o primeiro verbo. Caso nenhum verbo seja encontrado o valor retornado ser nenhum e a frase ser impressa na tela sem modificaes. Se um verbo for encontrado, a varivel indice_verbo receber a posio da tupla na qual o verbo se encontra. A seguir, em verbo, etiqueta_verbo = frase[indice_verbo] criada uma varivel do tipo tupla chamada verbo, etiqueta_verbo que recebe o contedo da varivel indice_verbo. Nesse momento a tupla (verbo, etiqueta_verbo) e indice_verbo se encontram na memria. Agora verificaremos se encontramos um substantivo do lado direito do verbo, caso no encontremos, verificaremos do lado esquerdo. Em atributo_substantivo = lambda (palavra, etiqueta): etiqueta.startswith('N'), a varivel atributo_substantivo receber o valor N, caso uma tupla contendo um substantivo seja encontrada. Em indice_substantivo = indice_atributo(frase, atributo_substantivo, inicio=indice_verbo+1), a varivel indice_substantivo receber o ndice da tupla onde o substantivo encontrado na frase. Caso nenhum substantivo seja encontrado ao lado direito do verbo ento ele ser procurado do lado esquerdo, conforme definido a seguir: if indice_substantivo is None: indice_substantivo = indice_atributo(frase, atributo_substantivo, inicio=indice_verbo-1, incremento=-1)

55

Caso ele tambm no seja encontrado do lado esquerdo, a frase ser impressa na tela sem modificaes. if indice_substantivo is None: return frase Se um substantivo for encontrado, ento o contedo referente ao seu ndice ser atribudo varivel substantivo, etiqueta_substantivo, conforme demonstrado a seguir: substantivo, etiqueta_substantivo = frase[indice_substantivo] Em sua ltima etapa, a funo verificar se o substantivo encontrado est no plural. Em caso positivo, ele far a correo do verbo, se o mesmo se encontrar no singular, e ento a frase correta ser impressa na tela. Se o substantivo encontrado estiver no singular, ento ele verificar se o verbo da frase tambm se encontra no singular, caso no se encontre, o verbo ser corrigido e a frase correta ser impressa na tela. if etiqueta_substantivo.endswith('S'): frase[indice_verbo] = singular_plural.get((verbo, etiqueta_verbo), (verbo, etiqueta_verbo)) else: frase[indice_verbo] = plural_singular.get((verbo, etiqueta_verbo), (verbo, etiqueta_verbo)) return frase Para testar o nosso corretor verbal, criamos algumas frases com verbos e substantivos no incio e meio da frase: Exemplo 1, verbo incorreto (presente/singular), no inicio da frase: >>> frase = [('', 'VSPI'), ('caras', ('as','ART'), ('passagens', 'NS')] >>> corretor_verbal(frase) [('s\xe3o', 'VPPI'), ('caras', 'ADV'), ('as', ('passagens', 'NS')] Para tornar o resultado mais legvel usamos o comando print: >>> for x, y in frase: print x, y, so VPPI caras ADV as ART passagens NS 'ADV'),

'ART'),

56

Exemplo 2, verbo incorreto (presente/plural), no meio da frase: >>> frase = [('a', 'ART'), ('so','VPPI'), ('distante', 'ADJ')] >>> corretor_verbal(frase) [('a', 'ART'), ('cidade', 'N'), ('distante', 'ADJ')] >>> for x, y in frase: print x, y, a ART cidade N VSPI distante ADJ ('cidade', 'N'),

('\xe9',

'VSPI'),

Exemplo 3, verbo incorreto (pretrito/singular), no meio da frase: >>> frase = [('as', 'ART'), ('solues', 'NS'), ('era','VSPIm'), ('muitas', 'PRONADJ')] >>> corretor_verbal(frase) [('as', 'ART'), ('solu\xe7\xf5es', 'NS'), ('eram', 'VPPIm'), ('muitas', 'PRONADJ')] >>> for x, y in frase: print x, y, as ART solues NS eram VPPIm muitas PRONADJ

Exemplo 4, verbo incorreto (pretrito/plural), no meio da frase: >>> frase = [('Quando', 'ADV'), ('eram','VPPIm'), ('pequena', 'N')] >>> corretor_verbal(frase) [('Quando', 'ADV'), ('ela', 'PRON'), ('pequena', 'N')] >>> ('ela', 'PRON'),

('era',

'VSPIm'),

Percebemos que, a partir dos exemplos, o nosso corretor verbal se comportou bem em situaes controladas. Apesar de ele estar longe se der um corretor verbal real, conseguimos verificar na prtica a aplicao de alguns dos princpios do processamento de linguagem natural na prtica..

57

6. CONCLUSO

Nesse trabalho conseguimos entender o funcionamento do Processamento de Linguagem Natural e aprender algumas das principais tcnicas que podem auxiliar nessa rea. Encontramos algumas dificuldades como, por exemplo, a de lidar com os caracteres da lngua portuguesa, j que a grande maioria das publicaes sobre esse assunto se encontram na lngua inglesa e, portanto voltadas para o processamento de textos em ingls. Tambm encontramos certa dificuldade para encontrar corpora preparada em portugus. No nosso trabalho utilizamos o corpus Mac-Morpho em boa parte dos exemplos, mas infelizmente esse corpus apesar de conter mais de 1 milho de palavras etiquetadas, no possui as sentenas no formato de rvores, o que fundamental para uma anlise sinttica completa. No entanto, acreditamos que atingimos o nosso objetivo principal, que era o de explicar como feito o Processamento de Linguagem Natural e o que preciso para que ele seja realizado

58

REFERNCIAS BIBLIOGRFICAS

BIRD, Steven; KLEIN, Ewan; LOPER, Edward. Natural Language Processing with Python. First Edition. Sebastopol, CA OReilly Media, Inc., 2009

PERKINS, Jacob. Python Text Processing with NLTK 2.0 Cookbook. First Edition. Birmingham, UK. Packt Publishing Ltd.,2010

MCNEIL, Jeff. Python 2.6 Text Processing Beginner's Guide. First Edition. Birmingham, UK. Packt Publishing Ltd.,2010

Sites na Internet: http://www.python.org/ http://code.google.com/p/nltk/ http://nltk.org/

Você também pode gostar