Classificando textos com Machine Learning

Suzana Mota
9 min readAug 9, 2019

--

J.K Rowling, Beatles x Rolling Stones: Entenda como classificar autorias de músicas/textos utilizando Machine Learning

Há algum tempo atrás, a aclamada escritora J.K Rowling, famosa pela série Harry Potter foi desmascarada por um algoritmo de Machine Learning. Ela decidiu publicar um novo livro, escondendo sua autoria, utilizando o pseudônimo de Robert Galbraith.

O livro chamado The Cuckoo’s Calling, agradou a crítica especializada, mas não chegou a vender muitos exemplares. Um repórter do London’s Sunday Times ficou intrigado e resolveu convidar dois especialistas em Machine Learning para analisarem o estilo da escrita.

Qual não foi a surpresa, quando os especialistas encontraram resultados que apontavam com uma alta probabilidade que J.K Rowling seria SIM, a autora do livro desconhecido.

O repórter enviou para um dos editores de Rowling: “Acredito que Robert Galbraith é na verdade J.K. Rowling, vocês podem me responder de forma direta?’”. No dia seguinte, o editor afirmou que a autora havia decidido “confessar”…

E assim, mais um dia foi salvo pelas técnicas de Machine Learning!

Você pode ver o link da notícia real aqui.

J.K Rowling era realmente a autora de The Cuckoo’s Calling e o livro foi um sucesso de vendas após a descoberta.

Quer aprender como fazer isso e identificar o estilo de escrita de um autor? Então mãos a obra!

Mas como isso funciona?

Claro, que não é uma tarefa tão trivial, realizar a classificação de textos utilizando Machine Learning, para tanto, algumas simplificações costumam ser feitas, para reduzir a dimensão do problema.

  1. Geralmente não são consideradas a ordem das palavras em um texto: Sabemos que em várias situações a ordem das palavras podem ser importantes e alterar o sentido e interpretação do texto. Mas para este caso específico de classificação que queremos observar o estilo do autor, este dado não é relevante.
  2. Considerar apenas as palavras “fortes”: Isso quer dizer que ignoramos artigos (o, a, um, uns), conectivos (de, para, por) e pontuações, pois eles carregam pouca informação a respeito do estilo do autor.

Vamos utilizar a técnica de Machine Learning de aprendizado supervisionado, o que significa, que vamos fazer com que a máquina aprenda a realizar a classificação, observando um conjunto de textos já classificados e entenda qual o padrão aplicado ali.

Para isso, pegamos todos os textos de todos os autores e colocamos em um vetor, neste vetor separamos todas as palavras fortes em um bag of words (um saco de palavras) e ali observamos a presença ou a ausência de cada palavra. Assim, conseguimos transformar o nosso texto puro em valores numéricos e o nosso algoritmo será capaz de identificar os padrões e perfis de cada autor.

Beatles x Rolling Stones

No nosso modelo, vamos comparar o estilo de escrita das duas principais bandas da história. Temos um arquivo chamado conteudo.csv ( você pode baixar ele aqui), na coluna texto, temos frases que pertencem as músicas das duas bandas e na coluna classificação indicamos a qual banda a frase pertence com:

1 = Beatles

2 = Rolling Stones

Agora Let it be because I can’t get no satisfaction…

Vamos ver como isso funciona!

PS: Esse artigo fica mais agradável com a trilha sonora apropriada.

Definindo o dataset:

A primeira coisa que precisamos fazer é transferir este texto para algo que seja facilmente lido e entendido pelo computador.

Vamos portanto levar cada uma destas frases para um arquivo CSV ou Comma Separated Values que são simplesmente arquivos, onde cada informação é separada por vírgula.

A cada vez que uma vírgula aparece no texto, a máquina considera como um novo valor.

Neste exemplo vamos ter apenas dois tipos de valores: texto e classificação.

texto, classificacao
Speaking words of wisdom, 1
Let it be, 1
Cause I try, and I try, and I try, and I try, 2
I can’t get no, 2

No nosso dataset portanto temos várias frases que pertencem a cada banda, as frases com o valor 1 pertencem aos Beatles e com valor 2 pertencem aos Rolling Stones.

Lendo o dataset:

Vamos agora ler todo o arquivo do dataset e extrair os textos dele. Para isso, você vai precisar instalar as bibliotecas abaixo, abra o terminal ou o prompt de comando e digite:

pip install pandas
pip install numpy

Agora precisamos ler o nosso arquivo CSV e mostrar os resultados na tela, apenas para verificar se esta tudo ok.

#Lendo o CSV e imprimindo na tela
import pandas as pd
from collections import Counter
import numpy as np
from sklearn.model_selection import cross_val_score
classificacoes = pd.read_csv('conteudo.csv')
#print(classificacoes)

Agora vamos pegar a texto e armazenar na variável textos.

#Colocando os textos em uma variavel
textos = classificacoes[‘texto’]
print(textos)

E vamos deixar todas as palavras em minúsculo, apenas para que a máquina não faça distinção de uma palavra escrita Assim ou assim.

Afinal de contas para o computador, uma palavra com letra minúscula é completamente diferente de uma com letra maiúscula, mas para os seres humanos é tudo a mesma coisa.

E também vamos separar cada palavras isoladamente, transformando as frases em um bag of words (saco de palavras)

#Transformando palavras em strings
#cada linha se refere a um array com cada uma das palavras #minusculas separadas
palavrasIsoladas = textos.str.lower().str.split()
print(palavrasIsoladas)

Temos então cada frase, com suas palavras separadas por vírgula, esse passo vai ser importante para que consigamos criar um dicionário com todas as nossas palavras distintas.

Criando um dicionário:

Quando aprendemos a falar, vamos criando aos poucos o nosso vocabulário e acrescentando palavras a ele, ao longo da vida.

Com o computador é exatamente igual, ela só entende números e não conhece nenhuma palavra ainda. A proposta aqui é ensinar um padrão de texto para que possamos entender o padrão de escrita das nossas queridas bandas.

Mas o computador não sabe sequer, o que é uma palavra e não tem repertório nenhum. Para isso, vamos criar um mini-dicionário com todas as palavras usadas no nosso dataset.

A máquina vai ler o nosso dataset e armazenar no seu mini-dicionário todas as palavras distintas, simples assim.

#Criando um unico array com todas as palavras unicas (dicionario)
dicionario = set()
for lista in palavrasIsoladas:
dicionario.update(lista)
print(dicionario)#imprime o total de palavras diferentes
totalDePalavras = len(dicionario)
print(totalDePalavras)

O resultado é uma listinha separada por vírgula, de todas as nossas palavras distintas e o valor de quantas palavras distintas temos no nosso dataset:

Vinculando palavras a posições em um vetor:

De novo, essas máquinas amam números! Então, para ela aprender melhor vamos deixá-la vincular uma posição numérica a cada palavra do nosso mini-dicionário.

Para isso vamos criar um mapeamento, que associa cada uma das palavras que temos no nosso dicionário a uma posição de 0 até o valor máximo de palavras que temos.

#Associa cada palavra a uma posicao e armazena em um dicionario mapeado
palavraEposicao= dict(zip(dicionario, range(totalDePalavras)))
print(palavraEposicao)

Contando a presença de cada palavra:

Lembra que o nosso dicionário mapeado, possui as palavras únicas, ou seja, sem repetição? Agora vamos pegar todo o texto com palavras repetidas e tudo mais e vamos observar quantas vezes cada palavra única do nosso dicionário mapeado, estão sendo repetidas ali no texto inteiro. Para isso, vamos fazer o código:

#Funcao que conta a presenca de cada palavra única presente no dicionario mapeado, no texto inteirodef vetorizarPresencaPalavras(texto, palavraEposicao):
vetor = [0] * len(palavraEposicao)
for palavra in texto:
if palavra in palavraEposicao:
posicao = palavraEposicao[palavra]
vetor[posicao] += 1
return vetor
texto = palavrasIsoladas[0]
print(vetorizarPresencaPalavras(texto, palavraEposicao))

Neste exemplo estamos passando palavrasIsoladas[0], o que quer dizer que estamos passando apenas a primeira frase do texto. Para considerar o texto todo, vamos alterar este trecho de código.

#Funcao que conta a presenca de cada palavra única presente no dicionario mapeado, no texto inteirodef vetorizarPresencaPalavras(texto, palavraEposicao):
vetor = [0] * len(palavraEposicao)
for palavra in texto:
if palavra in palavraEposicao:
posicao = palavraEposicao[palavra]
vetor[posicao] += 1
return vetor
vetoresDeTexto = [vetorizarPresencaPalavras(texto, palavraEposicao) for texto in palavrasIsoladas]
print(vetoresDeTexto)

Agora concluímos a preparação do nosso texto. Vamos para a etapa de associar cada grupo de palavras a seus autores ou classificações.

O que ele traz é um vetor de valores, considerando que o dicionário de palavras mapeadas fosse apenas:

{‘help’: 0, ‘I’: 1, ‘need’: 2, ‘someone’: 3}

Se passarmos a frase: “I need you”, a função vetorizarPresencaPalavras irá retornar o vetor:

{1, 1 , 0} indicando que encontrou a palavra “I” uma vez, a palavra “need” uma vez e a palavra “you” 0 vezes.

Associando o texto ao seu autor:

Vamos nos lembrar que o arquivo CSV possuía duas colunas, uma com texto e outra com a classificação, que nada mais é que um rótulo numérico para a banda autora do texto.

Como este código já é numérico não vamos precisar fazer alterações, apenas armazenamos o valor em uma variável:

#Associa o texto ao autorautor = classificacoes['classificacao']

Treinando os classificadores utilizando Machine Learning:

Vamos utilizar a abordagem de classificação supervisionada, ou seja, nós ja temos os dados rotulados indicando qual texto pertence a qual banda.

Agora precisamos treinar o nosso classificador, mostrando estes dados rotulados para ele. Também vamos definir a porcentagem dos dados que será utilizado para treino, nesse caso definimos como 80%, mas você pode alterar este valor, para fazer isto vamos fazer o código:

#Armazena o texto e os autoresx = np.array(vetoresDeTexto)
y = np.array(autor)
#Define porcentagem de Treino
porcentagem_de_treino = 0.8

E agora vamos definir e pegar os dados propriamente ditos, tanto os dados do texto, como o rótulo da banda autora daquele texto/música:

#Define o Tamanho dos dados de treino, a partir da porcentagem de #treinotamanho_de_treino = int(porcentagem_de_treino * len(y))
tamanho_de_validacao = len(y) — tamanho_de_treino
#Pega os dados de treino
treino_dados = x[0:tamanho_de_treino]
treino_marcacoes = y[0:tamanho_de_treino]
#Pega os dados de validacao
validacao_dados = x[tamanho_de_treino:]
validacao_marcacoes = y[tamanho_de_treino:]

A função que vai efetivamente treinar o nosso conjunto de dados e associar a seus classificadores é esta abaixo:

#Funcao que Treina os dadosdef predict(nome, modelo, treino_dados, treino_marcacoes):
k = 10
scores = cross_val_score(modelo, treino_dados, treino_marcacoes, cv = k)
taxa_de_acerto = np.mean(scores)
msg = "Taxa de acerto do {0}: {1}".format(nome, taxa_de_acerto)
print(msg)
return taxa_de_acerto

Utilizando diferentes classificadores:

Agora podemos realizar a classificação, utilizando diferentes técnicas, neste exmplo, utilizamos os classificadores OneVsRest, OneVsOne, MultinomialNb e Adaboost.

Em outro artigo, vamos detalhar o funcionamento de cada técnica de classificação.

#Utilizando o classificador OneVsRest
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import LinearSVC
resultados = {}
modeloOneVsRest = OneVsRestClassifier(LinearSVC(random_state = 0))
resultadoOneVsRest = predict("OneVsRest", modeloOneVsRest, treino_dados, treino_marcacoes)
resultados[resultadoOneVsRest] = modeloOneVsRest
#Utiliznado o classificador OneVsOne
from sklearn.multiclass import OneVsOneClassifier
modeloOneVsOne = OneVsOneClassifier(LinearSVC(random_state = 0))
resultadoOneVsOne = predict("OneVsOne", modeloOneVsOne, treino_dados, treino_marcacoes)
resultados[resultadoOneVsOne] = modeloOneVsOne
#Utilizando o classificador MultinomialNb
from sklearn.naive_bayes import MultinomialNB
modeloMultinomial = MultinomialNB()
resultadoMultinomial = predict("MultinomialNB", modeloMultinomial, treino_dados, treino_marcacoes)
resultados[resultadoMultinomial] = modeloMultinomial
#Utilizando o classificador Adaboost
from sklearn.ensemble import AdaBoostClassifier
modeloAdaBoost = AdaBoostClassifier()
resultadoAdaBoost = predict("AdaBoostClassifier", modeloAdaBoost, treino_dados, treino_marcacoes)
resultados[resultadoAdaBoost] = modeloAdaBoost

Podemos ver aqui, o resultado de cada um deles, nesse caso, o vencedor foi a classificação do AdaBoost. Mas dependendo da necessidade, do dataset e do tipo de classificação, diferentes técnicas podem ser mais apropriadas.

Obrigada por chegar até aqui, se você tem dúvidas, sugestões, ou algo que você julgue interessante de compartilhar, escreva aqui nos comentários!

E se você achou esse artigo útil de alguma forma, deixa a sua palminha e compartilha com os amigos.

Por fim, temos o código inteiro disponível no Github, faça o download e crie suas próprias classificações.

--

--