segunda-feira, 7 de outubro de 2013

Unigramas, bigramas e trigramas.

O post de hoje é bem curto mas muito funcional.

No post anterior aprendemos a fazer o pré-processamento do texto, chegando no afim a um array de palavras com seu radical extraído, sem stopwords e com padronização (sem acentos e caracteres especiais). Este array, por si só, já pode ser considerado como um conjunto de unigramas, ou seja, palavras únicas que podem ser utilizadas em uma afinidade de aplicações.

Uma das aplicações é, por exemplo, a contagem das palavras no conjunto de dados (coisa que já realizamos no post passado também). As unigramas podem dar noção do tema do texto, por exemplo, se você considerar um conjunto de 10 ou 15 palavras mais frequentes. Entretanto, as vezes a simples análise da frequência de unigramas não traz conhecimento preciso.

Alguns pesquisadores que estudaram a probabilidade de uma palavra aparecer após outra propuseram o uso dos bigramas e trigramas para caracterizar textos. Os bigramas são sequências de duas palavras e os trigramas são sequências de três palavras. Após a criação dos bigramas e trigramas, podemos contar as suas frequências e ver se trazem algum significado relevante para o texto.

Em Python, construir os bigramas e trigramas a partir das unigramas é relativamente simples, veja a função que criaremos a seguir:


def bigramas(words):
 
    bigrams = []
 
    for i in range(0, len(words)):
        if (i == len(words)-1):
            break
        else:
            bigrama_obs = words[i] + '_' + words[i+1]
            bigrams.append(bigrama_obs)
 
    return bigrams

A único input desta função é o próprio array de unigramas que vimos no post anterior. A função de trigramas é muito semelhante e segue a mesma lógica da função de bigramas:


def trigramas(words):
 
    trigrams = []
 
    for i in range(0, len(words)):
        if (i == len(words)-2):
            break
        else:
            trigrama_obs = words[i] + '_' + words[i+1] + '_' + words[i+2]
            trigrams.append(trigrama_obs)
 
    return trigrams

Os bigramas e trigramas funcionam melhor com textos mais longos, de alguns parágrafos. Neste caso, recomendo o uso de um texto de notícia, por exemplo, como deste link do UOL. Aplicando os procedimentos vistos no post anterior na seguinte ordem:
  1. Eliminação de pontuações e caracteres especiais
  2. Eliminação dos acentos
  3. Tokenização
  4. Eliminação das stopwords
podemos aplicar as funções bigramas() e trigramas() para criar arrays destes tipos e utilizar a função FreqDist() da biblioteca NLTK para calcular as frequências.

Para este exemplo, as 3 palavras (unigramas) mais frequentes foram black, blocs e rio, com cinco ocorrências cada. Já para a análise de bigramas foram: black_blocs, capital_paulista e policiais_militares, com cinco, duas e duas ocorrências cada, respectivamente. Neste caso, a análise de bigramas trouxe uma compreensão muito mais precisa do tema do texto.

Até a próxima!

sábado, 21 de setembro de 2013

Análise de Textos Facilitada

Agora que já estamos mais familiarizados com a manipulação básica de textos no Python, vamos nos aprofundar um pouco mais no pré-processamento. Entretanto, sem aumentar o grau de dificuldade, pois temos um aliado que vou apresentar para vocês: a biblioteca NLTK.

Segundo o próprio site oficial do NLTK (www.nltk.org), em livre tradução:
NLTK é uma plataforma líder para construir programas em Python para trabalhar com dados de linguagem humana. Esta plataforma oferece recursos fáceis de usar para processamento de textos em tarefas de classificação, "tokenização", "stemming", "tagging", "parsing" e compreensão semântica.
Instalando o Pacote

A ferramenta NLTK está disponível gratuitamente para download no site www.nltk.org/install.html. Após instalado o pacote básico (seguindo as instruções apresentadas no site), é necessário instalar o conjunto de dados que dá suporte a esta ferramenta, disponível no link www.nltk.org/data.html. Após instalados esses dois módulos, a ferramenta poderá ser utilizada.

Tokenização

Paralelamente às técnicas de pré-processamento que vimos nos posts anteriores, vamos aprender aqui o conceito de "tokenização". Na prática, significa a divisão do texto em partes menores segundo algum critério objetivo. Já fizemos isso anteriormente quando dividimos o texto em diversas palavras. Mas vamos voltar um pouco no tempo neste caso. Antes de dividir o texto em palavras, podemos olhar de forma um pouco mais abrangente quais são as partes de um texto.

Um texto simples pode ser estruturado em parágrafos e frases. Parágrafos e frases podem apresentar ideias distintas e são utilizados para estruturar os assuntos que são abordados no texto. Desta forma, fazer análises de texto considerando esta separação parece ser coerente.

No exemplo a seguir, utilizamos o pacote NLTK para separar o conteúdo de um texto bem simples em frases. O resultado é uma lista (array) de frases:

# coding=utf-8

# Importação das Bibliotecas
from nltk.tokenize import sent_tokenize

texto = 'Este é um texto simples. Este é o pacote NLTK.'
print sent_tokenize(texto)

Veremos que este processo é importante quando escolhermos as métricas de relevância para os termos. Antecipando um pouco, um termo que aparece com muita frequência em muitos documentos (neste caso, frases), pode não ser tão relevante assim. Desta forma, separar em frases pode nos ajudar a identificar quais palavras realmente importam nos conjuntos de textos.

Uma vez separadas as frases, podemos novamente separar as palavras, mas desta vez utilizando a biblioteca NLTK. Após isso, podemos fazer o filtro das stopwords que prometi nos posts anteriores com um comando bem simples e utilizando uma biblioteca de stopwords em português existente na própria biblioteca NLTK:

from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
print word_tokenize(texto)

filtrado = [w for w in word_tokenize(texto) if not w in stopwords.words('portuguese')]
print filtrado

Aliado às técnicas de remoção de acentos, caracteres especiais, tabulações e quebras de linhas vistas nos posts anteriores, estamos quase finalizando o pré-processamento básico de textos. Mas ainda temos uma etapa importante: stemming.

Stemming

Não consegui encontrar uma palavra boa para traduzir este termo, mas o processo de stemming consiste em se remover os plurais, gêneros e flexões verbiais das palavras, sobrando apenas o radical, que contém o sentido em si da palavra. Continuando nosso programa:

import nltk
stemmer = nltk.stem.RSLPStemmer()
filt_stem = []

for i in filtrado:
 filt_stem.append(stemmer.stem(i))

print filt_stem

Por fim, podemos aplicar ao nosso texto exemplo dos posts anteriores (texto_longo) e observar a frequência dos termos, agora utilizando o NLTK:

fdist = nltk.FreqDist(filt_stem)

for i in fdist:
 print i + ': ' + str(fdist[i])

No próximo post veremos um pouco de teoria sobre as diferentes medidas de relevância de textos e uma parte prática sobre como calculá-las utilizando a biblioteca NLTK.

Obrigado!

domingo, 15 de setembro de 2013

Pré-processamento de Textos

Vimos no post anterior que quando analisamos textos precisamos fazer alguns ajustes nele antes. Estes ajustem servem para melhorar os resultados e corrigir algumas imperfeições da análise que passam desapercebidas por nós quando estamos simplesmente lendo um texto.

São elas:
  1. Pontuações - as pontuações no texto acabam transformando as palavras. Como o Python não sabe identificar as palavras automaticamente, uma palavra 'concluído' acaba sendo diferente de uma palavra 'concluído!'.
  2. Acentuações - o mesmo problema que temos nas pontuações também se aplica nas acentuações, ou seja, a palavra 'conversão' é diferente a palavra 'conversao'. Desta forma, erros ortográficos no texto são facilmente confundidos com palavras diferentes.
  3. Case Sensitive - este termo define quando a palavra está sendo escrita em maiúscula ou minúscula. O Python (e a maioria das linguagens de programação) identifica como palavras diferentes, por exemplo: 'Conversão' e 'conversão'.
Existem outras tarefas mais complexas que fazem parte do pré-processamento de textos mas deixaremos isso para um próximo post. Hoje vamos focar nos três itens apresentados acima.

Case Sensitive

Antes de qualquer processamento, vamos converter todo o nosso texto para letras minúsculas. Aproveitando o código do texto anterior que gera uma variável chamada texto_longo: 

# -*- coding: utf-8 -*-
texto_longo = '''
 Esta é uma demonstracao de como podemos escrever textos
 longos. Estes textos longos podem ser parágrafos inteiros
 de livros, reportagens, notícias e ate mesmo posts de blogs.
 Seja qual for a sua fonte, ela poderá ter textos longos como
 este, tenha certeza disto!
 '''

texto_longo = texto_longo.lower()
print texto_longo

Pontuações e Acentuações

Para remoção de pontuações e acentuações podemos utilizar o comando replace() que aprendemos no post anterior para remoção das quebras de linha. A diferença aqui é que, no caso acentuações, precisamos substituir a letra acentuada pela sua correspondente não acentuada, enquanto que para pontuações basta a remoção como fizemos para as quebras de linha.


As pontuações principais são:
  • Ponto final (.)
  • Vírgula (,)
  • Ponto de exclamação (!)
  • Ponto de interrogação (?)
  • Ponto-e-vírgula (;)
Vamos nos limitar a estes que aparecem no texto sugerido (nem todas), mas esta metodologia pode ser extendida a todos os caracteres especiais. Desta forma, aplicamos o comando replace() recorrentemente para remover as pontuações.

pontos = ['.',',','!','?',';']

for p in pontos:
 texto_longo = texto_longo.replace(p, '')

print texto_longo

Para remoção das acentuações temos que substituir cada letra acentuada pela sua correspondente não acentuada utilizando também o comando replace(). Veja abaixo:

acentos = ['á','é','í','ó','ú','à','è','ì','ò','ù',
     'ã','ẽ','ĩ','õ','ũ','â','ê','î','ô','û']
s_acentos = ['a','e','i','o','u','a','e','i','o','u',
    'a','e','i','o','u','a','e','i','o','u']

for i in range(0, len(acentos)):
 texto_longo = texto_longo.replace(acentos[i], s_acentos[i])

print texto_longo

Agora que nosso texto está preparado, vamos contar as palavras como fizemos no post anterior:

from collections import Counter

palavras = texto_longo.replace('\n',' ').replace('\t','').split(' ')
contador = Counter(palavras)

for i in contador.items():
 print i

Diferente do resultado anterior, sem pré-processamento, temos agora as palavras mais frequentes:
  • 'textos': 3
  • 'longos': 3
  • 'de': 3
No post anterior vimos que 'longos' tinha apenas 2 citações, entretanto, uma citação estava escondida junto ao ponto final da primeira frase. Agora temos uma análise mais correta.

No próximo post veremos como remover palavras de alta frequência e pouca relevância, chamadas de stop words, e veremos um pouco sobre extração de radicais, para eliminar o efeito da conjugação de verbos e flexão. Até a próxima!


Python e Frequência de Palavras

Iniciando nossos posts práticos, vamos conhecer uma técnica simples de processamento de textos que gera as famosas nuvens de palavras que vemos tanto por aí nas redes sociais.

As nuvens de palavras, ou tag clouds, nada mais são do que uma representação gráfica (colorida ou não) das palavras mais frequentes contidas em algum corpo de texto. O tamanho das palavras possui uma relação direta com a frequência a qual aparecem no texto.

Portanto, neste post, apresentaremos como calcular a frequência de palavras contidas em um texto. Para isso, utilizaremos a linguagem Python.

Por que a linguagem Python?

Python é uma linguagem de programação de alto nível, orientada a objetos, gratuita, multiplataforma e de fácil aprendizado. Dadas estas características, é muito comum encontrar pela internet uma infinidade de pacotes desenvolvidos para facilitar as análises que desejamos obter.

Caso você não conheça nada sobre Python ainda, recomendamos uma visita ao site http://www.learnpython.org. Este site apresenta um console interativo onde você pode testar os comandos do tutorial sem ter o Python instalado em seu computador.

Após se familiar com a ferramenta, você pode obter o instalador pelo site http://www.python.org e usar a linguagem em sua própria máquina (recomendamos a versão 2.7, pois nem todos os pacotes estão disponíveis ainda para a versão 3.x).

Após a instalação, basta você abrir o console no Linux ou prompt de comando no Windows, digitar ‘python’ e começar a programar. Uma alternativa é utilizar as IDEs que auxiliam no desenvolvimento ao colorir tags e indicar erros no código como o IDLE (que vem com o próprio python na versão para Windows), Geany, Eclipse, gedit com plugin, vi, emacs, etc.

Manipulando strings no Python

Na linha de comando do Python no modo interativo, podemos começar criando uma variável (texto) que recebe um valor do string e fazemos algumas manipulações com ela.

    texto = 'Ola mundo'
    len(texto) # Retorna a quantidade de caracteres = 9
    
    # Concatenando strings

    excl = '!'
    texto2 = texto + excl
    print texto2 # = Ola mundo!

    len(texto2) # = 10

Textos longos podem ser inseridos no código da seguinte forma:

    texto_longo = '''Esta e uma demonstracao de como podemos escrever textos
        longos. Estes textos longos podem ser paragrafos inteiros
     de livros, reportagens, noticias e ate mesmo posts de blogs.
     Seja qual for a sua fonte, ela podera ter textos longos como
     este, tenha certeza disto!
    '''

    print texto_longo            

O comando split() apresentado a seguir quebra a string em múltiplas partes. O parâmetro que esta função pede é o caractere que fará a quebra. Como queremos separar as palavras pelo espaço em branco, podemos utilizar ’ ’ como parâmetro, veja:

    print texto_longo.split(' ')

Como você pode ver, a saída de uma função split() é um array de strings. Mas vemos também alguns caracteres especiais que não estavam visíveis no texto anteriormente. Cada caractere tem uma função específica:
  • \n - indica uma quebra de linha
  • \t  - indica uma tabulação (tecla tab)
É interessante que estes caracteres sejam removidos antes do comando split(). Para isso, podemos utilizar o comando replace() e substituir estes caracteres especiais por espaço vazio, ou seja, ”. E, por fim, executar o comando split()

    print texto_longo.replace('\n',' ').replace('\t','').split(' ')

Agora que já temos um array de palavras, podemos calcular a frequência delas para ver quais aparecem mais neste texto. Para facilitar este processo utilizaremos uma biblioteca nativa do Python chamada collections e a classe Counter fará todo o trabalho “sujo” por nós.

    from collections import Counter
    palavras = texto_longo.replace('\n',' ').replace('\t','').split(' ')

    contador = Counter(palavras)
    
    for i in contador.items():

        print i

Eis o resultado, com a quantidade de ocorrências das mais citadas:
  • 'textos': 3
  • 'de': 3
  • 'e': 2
  • 'longos': 2

As demais palavras possuíram apenas uma única ocorrência cada. Agora vejamos que interessante: se removemos as palavras ‘de’ e ‘e’ que não representam muita coisa sozinhas, temos apenas ‘textos’ e ‘longos’ que constituem, justamente, o tema do texto.

No próximo texto veremos como fazer pré-processamento de textos no Python para evitar que palavras muito frequentes sem significado entrem em nossa análise e alguns tópicos importantes adicionais. Até lá!

O que é Text Analytics?

Text Analytics, também chamado a grosso modo de Text Mining se refere ao processo de extrair informações de grande qualidade de textos puros [1].

Pense em um artigo comum de revista, por exemplo, e responda algumas perguntas como:
  1. Quem são os autores deste artigo?
  2. Quais são as entidades, locais, pessoas ou instituições envolvidas neste texto?
  3. Qual o assunto do texto?
  4. O texto disserta sobre aspectos positivos ou negativos acerca do assunto?
Estas informações são apenas para esquentar.

TextAnalytics acaba sendo, então, um conjunto de técnicas e metodologias para se responder, de forma automatizada, a todas estas perguntas citadas acima e muitas outras.

A análise de textos envolve várias áreas de conhecimento como extração de informação, análise léxica, estudo das distribuições de frequência de palavras, reconhecimento de padrões, tagging, mineração de dados, redes complexas, regreas de associação, visualização de dados e análise preditiva. Em resumo, estamos falando essencialmente de transformar textos em dados para análise, por meio da aplicação de técnicas de processamento de linguagem natural e métodos analíticos.

Esta tagcloud, também conhecida como nuvem de palavras, foi criada a partir de um texto puro utilizando técnicas de análise de textos.

A aplicação destas técnicas é bem ampla, abrangendo as seguintes áreas:
  • Business Intelligence
  • Análise de Sentimento
  • Aplicações de Segurança
  • Biblioteconomia
  • Marketing
  • Aplicações Acadêmicas

Agora que já introduzimos o tema, apresentaremos no próximo post como manipular pequenos textos na linguagem Python e calcular as frequências de termos distintos conhecidos como unigramas. Até lá!

Fonte:

[1] Text mining - Wikipedia [http://en.wikipedia.org/wiki/Text_mining]

Iniciando...

Olá pessoal, tudo bem com vocês?

Estive pesquisando pela web e encontrei poucas referencias atuais sobre mineração de textos, então devido criar um blog para postar informações atuais sobre o assunto.

A ideia inicial é postar textos com tutoriais, passo a passos e até alguns fundamentos teóricos sobre essa categoria de mineração de dados.

Sintam-se a vontade para colaborar enviando suas perguntas ou mesmo sugestões de posts.

Um abraço e até o próximo post!