Aprimorando a análise de dados textuais através de comparações de strings.

Matheus Henrique
Bemol
Published in
5 min readMar 10, 2021
Photo by Florencia Viadana on Unsplash

Imagine, por um instante, que você precisa fazer uma análise de dados para saber quais bairros de Manaus mais reclamam do saneamento básico. Para isso, você quer começar com uma contagem de reclamações por bairro.

O problema é que na sua fonte de dados, digamos, o Twitter, os usuários escrevem os nomes dos seus bairros sem nenhuma padronização. Ex.: “Santo Antônio”, “St. Antônio”, “S Antonio”. Observar nuances de milhares de registros — como o uso de ponto para abreviações — facilmente se torna um trabalho árduo para o olho humano. Quem garante que você não pulará a linha 3692?

Um pouco de nerdice

Além do óbvio transtorno da falta de padronização, essas variações mexem em um conceito matemático importante para a área de ciência de dados: a cardinalidade.

Cardinalidade, na teoria de conjuntos, pode ser entendida como uma medida para o número de elementos pertencentes a um conjunto.

Por exemplo, o conjunto A = {1,2,3} tem cardinalidade 3, ou na notação matemática, |A| = 3 (não confundir com a mesma notação de valor absoluto da função modular ou ainda da operação de norma na álgebra vetorial). Além disso, lembre-se que um conjunto não possui elementos repetidos.

No contexto da Ciência de Dados, especialmente em Machine Learning, quando se aumenta a cardinalidade, aumenta a dificuldade dos modelos para fazer generalizações. Um projeto de Processamento de Linguagem Natural (do inglês, NLP) que lidasse com nossa base exigiria mais recursos necessários para ser treinado, além de provavelmente acabar inferindo incorretamente que “Santo Antônio” é algo diferente de “S. Antônio”. Sua performance final decrementaria por causa da alta cardinalidade.

Solução

Para contornar nosso problema inicial, uma solução simples é usar algoritmos que medem a similaridade de strings, em especial os algoritmos de distância de edição. Existem diversos deles, e para não fugir do nosso escopo, eu recomendo que você leia esse artigo (em inglês) caso você queira conhecê-los melhor.

Para o nosso exemplo, vamos utilizar a biblioteca Python textdistance e o algoritmo de distância Jaro–Winkler:

O que retornará 0.8110256410256411 .

O método normalized_similarity() retorna um score para a similaridade entre as duas palavras. É como se "S. Antonio" e "Santo Antônio" fossem aproximadamente 81% semelhantes. Simples, não?

Assim, para a solução do nosso problema, uma função rudimentar poderia ser feita dessa maneira:

A saída da função ficaria da seguinte maneira:

corrige_bairro('St Antonio')
<<< 'Santo Antônio'

Comparando strings maiores

Uma limitação dos algoritmos de distância de edição é que eles desempenham mal em strings maiores. Entretanto, caso você precise de algum tipo de validação de frases ou parágrafos, podemos usar outras abordagens.

Vamos voltar ao nosso exemplo fictício. Imagine agora que para selecionar os tweets válidos você filtrou todos aqueles em que a localização do usuário estivesse em Manaus e no corpo do texto houvesse menção aos bairros da cidade. Ainda assim, muita coisa pode vir além dos comentários sobre o esgoto dos bairros. Como selecionar apenas os tweets sobre saneamento básico?

Uma estratégia simples é usar o TF-IDF. Ele é uma medida que busca mensurar a importância de uma palavra para um texto. Ela leva em consideração a frequência da palavra no texto (term frequency — TF) e contrabalanceia com o inverso da frequência do termo em todo o conjunto de documentos (inverse document frequency — IDF). Isso evita que palavras muito comuns mas sem importância (o termo “uma”, por exemplo) tenham um grande peso. Para mais detalhes, eu recomendo esse artigo (em inglês).

A ideia aqui é descobrir o assunto do tweet analisando a nota dele ao ser comparado com as palavras-chave de nosso interesse.

A conhecida biblioteca para Machine Learning, Scikit-Learn, possui uma classe para implementação do TF-IDF. O código abaixo mostra um exemplo didático do uso dessa métrica.

Agora cada tweet de exemplo foi transformado em um vetor (eu sei que você trabalhou com grandezas vetoriais em física do ensino médio). E uma maneira de se comparar vetores é através da cosine similarity.

A saída será:

<<< array([[0.52603395, 0.43140316, 0.24102946, 0.0854548 ]])

Pode-se dizer que o primeiro tweet é mais de 52% semelhante a nossa frase alvo, isso é um bom indicativo de que ele fala sobre saneamento básico. O mesmo não é verdade para o último tweet, que possui apenas 8,5% de similaridade. Assim, podemos estabelecer um limite de corte de 0.5, por exemplo, para afirmar que o tweet fala sobre saneamento.

Classificando textos

Além disso, com o TF-IDF você pode até extrair o assunto principal do texto e classificá-lo conforme necessário. Inclusive, o motor de busca do Google usa uma tática semelhante.

Para exemplificar, vamos supor que precisamos rastrear as notícias a respeito de saneamento básico. Podemos usar o TF-IDF para ranquear as palavras mais importantes. No exemplo abaixo, utilizamos o texto dessa notícia e a armazenamos na variável noticia.

Para ordenar as cinco palavras com notas mais altas, criamos um DataFrame com a biblioteca Pandas. Perceba que o método get_feature_names() retorna uma lista das palavras na mesma ordem que as notas armazenadas em rank.

Palavras com maior peso

Assim, conseguimos perceber que as palavras mais importantes são “marco”, “saneamento” e “presidente”. De fato, o texto fala sobre o marco legislativo a respeito de saneamento básico que aguarda ações do presidente. Poderíamos então, classificar essa notícia com o tema do saneamento básico.

Comentários adicionais

  • Não viva com a cabeça nas nuvens: no mundo real haverão mais palavras, erros ortográficos e pré-processamentos a serem feitos. Os scores poderão ser mais baixos. Esteja sensível ao estabelecer um bom limite de corte;
  • Palavras ao pé da letra: os métodos abordados focam na palavra exata. Dessa maneira, “empresa” e “empresas” são considerados coisas diferentes. Para contornar isso, deve-se utilizar técnicas de stemming e lemmanization. Para saber mais a respeito, indicamos esse post (em inglês);
  • Deep Learnings são reacionários: os pós-modernos dizem que tudo é um jogo de linguagem sem significado prévio, mas as redes neurais teimam. Os algoritmos do estado da arte são capazes de comparar a semântica, isto é, o sentido de palavras semelhantes, como em “alagamento” e “inundação”. Para saber mais, leia sobre os algoritmos word2vec, GloVe e fasttext nesse artigo (em inglês);
  • Olha o que ele fez: os trechos de código foram elaborados para serem didáticos e não para serem os mais pythonics;

--

--