Letícia Tavares
Menu

Letícia Tavares

Analista de Dados Cientista de Dados

Descrição

Análise de Preconceito com Python

App_web_musica

Construção de um método de classificação de preconceito em textos aplicado em frases retiradas da internet em português brasileiro, onde todas possuiam discurso de ódio.

O discurso de ódio, usualmente estabelecido como qualquer discurso que apresente desprezo por uma ou mais pessoas com base em alguma carecterísica como cor, gênero, orientação sexual, aparência, religião, identidade de gênero ou outra, afeta milhões de pessoas em todo mundo tendo um maior impacto atualmente graças aos sites e redes sociais. Esse trabalho tem como propósito dar início a uma possível solução para identificação de indícios de preconceito em textos para que futuramente possa ser utilizado como ferramenta na luta para mudar essa situação, levando informações para as pessoas que praticam esse ato que talvez as faça mudar de atitude, diminuindo assim o bullying cibernético e possivelmente o pessoal.

O dataset utilizado é constituído por uma coluna denominada "frase" que contém 452 documentos, onde cada documento é uma frase com teor preconceituoso retirada da internet, e outra coluna que apresenta a classificação do preconceito contido em cada frase. Esse trabalho apresenta apenas quatro tipos de preconceito, sendo eles Sexismo, LGBTFobia, Racismo e Gordofobia. Para este método, a coluna tipo, ou seja, as categorias reais servirão apenas para ajudar a avaliar se os tópicos encontrados fazem sentido.

Após a fase de pré-processamento do texto, uma matriz será montada com cada documento como uma linha e cada palavra como uma coluna. Os valores serão preenchidos pelo cálculo de frequência de cada palavra calculada pelo método "Frequência do Documento Inverso".

Reconstruir a matriz usando um produto externo de dois vetores seria bastante complicado. Na maioria dos casos, não conseguimos reconstruir exatamente a matriz. Porém, se tivermos um vetor com a frequência relativa de cada palavra do vocabulário fora da contagem total de palavras, e um com o número médio de palavras por documento, então esse produto externo seria o mais próximo possível.

2.1 Tópicos

Consideremos essas matrizes para duas colunas e duas linhas. A decomposição ideal seria agora agrupar os documentos em dois grupos, cada um dos quais tem uma distribuição de palavras tão diferente quanto possível, mas o mais semelhante possível entre os documentos no mesmo grupo. Vamos chamar esses dois grupos de "tópicos". E agruparíamos as palavras em dois grupos, com base naqueles que aparecem com mais frequência em cada um dos tópicos. O desafio nesse método é determinar o número de tópicos ideal.

3. Importação de Bibliotecas

Primeiro, é necessário importar as bibliotecas e funções que serão utilizadas, junto com a abreviação de funções no pacote numpy. Onde a classe CountVectorizer será usada para criar uma matriz de termo de documento.

In [ ]:
from time import time
import numpy as np
import os

from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn.decomposition import NMF, LatentDirichletAllocation
from sklearn.datasets import fetch_20newsgroups
from sklearn.decomposition import NMF
import pandas as pd

4. O Dataset

Como citado anteriormente, este dataset é composto por duas colunas, frases e tipo, respectivamente. A categoria frase contém 452 frases retiradas da internet com teor preconceituoso, enquanto a categoria tipo contém o tipo de preconceito contido em cada frase.

In [ ]:
def print_top_words(model, feature_names, n_top_words):
    for topic_idx, topic in enumerate(model.components_):
        message = "Topic #%d: " % topic_idx
        message += " ".join([feature_names[i]
                             for i in topic.argsort()[:-n_top_words - 1:-1]])
        print(message)
    print()
In [ ]:
print("Loading dataset...")
hate = pd.read_csv("https://raw.githubusercontent.com/leticiatavaresds/Projeto-ALA/master/dados_odio.csv")
t0 = time()
dataset = hate
data_samples = dataset.frase[:452]
print("done in %0.3fs." % (time() - t0))
Loading dataset...
done in 0.001s.

Abaixo é possível observar uma amostra com as primeiras 15 linhas do dataset para se ter uma ideia do que está sendo trabalhado.

In [ ]:
hate.head(15)
Out[ ]:
frase tipo
0 Mulher tem de se dar ao respeito Sexismo
1 não sou preconceituoso tenho até um amigo negro Racismo
2 pode ser gay mas não precisa beijar em público LGBTfobia
3 mulher ao volante perigo constante Sexismo
4 ela tem cabelo ruim Racismo
5 isso é coisa de mulherzinha Sexismo
6 ela é bonita mas é gordinha Gordofobia
7 um bando de vagabundinha de vestido curto Sexismo
8 gorda suja Gordofobia
9 gritei vai macaca pela janela e a vizinha negr... Racismo
10 o brasil seria mais lindo se não houvesse fres... Racismo
11 to começando a virar racista por causa dessas ... Racismo
12 Bom dia negros fedidos Racismo
13 mulher que anda toda decotada mostrando tudo p... Sexismo
14 Tem que bater na mulher isso sim Sexismo

Para facilitar o entendimento sobre a base de dados, abaixo é possível visualizá-la em Dataframe, vendo as informações gerais dos dados.

In [ ]:
print('Tamanho da base de treinamento {}\n'.format(hate.shape[0]))
hate.tipo.value_counts()
Tamanho da base de treinamento 452

Out[ ]:
LGBTfobia     191
Sexismo       174
Racismo        60
Gordofobia     27
Name: tipo, dtype: int64
In [ ]:
import seaborn as sns
import matplotlib.pyplot as plt

sns.factorplot(x="tipo", data=hate, kind="count", size=6, aspect=1.5, palette="PuBuGn_d")
plt.show();
/usr/local/lib/python3.6/dist-packages/seaborn/categorical.py:3666: UserWarning: The `factorplot` function has been renamed to `catplot`. The original name will be removed in a future release. Please update your code. Note that the default `kind` in `factorplot` (`'point'`) has changed `'strip'` in `catplot`.
  warnings.warn(msg)
/usr/local/lib/python3.6/dist-packages/seaborn/categorical.py:3672: UserWarning: The `size` paramter has been renamed to `height`; please update your code.
  warnings.warn(msg, UserWarning)
In [ ]:
print(hate.tipo.value_counts()/(hate.shape[0])*100)
LGBTfobia     42.256637
Sexismo       38.495575
Racismo       13.274336
Gordofobia     5.973451
Name: tipo, dtype: float64

5. Balanceamento das Classes

É possível notar que o conjunto não está balanceado, com referência ao tipo. Se contarmos o número de documentos de cada etiqueta, podemos ver que há um número significativamente maior de frases rotuladas como Sexismo e LGBTfobia. De fato, apenas 5,9% são classificados como gordofobia e 13,2% como Racismo, quando o ideal seria proporções iguais, ou seja, cada um das quatro categorias com 25% . Isso é problemático, pois com esses dados, há uma grande chance de que ele seja padronizado para prever todos os rótulos como LGBTfobia ou Sexismo, o que afetará na eficiência do código.

Uma forma de tentar contornar a situação é usar a função upsampling. Em que são recebidos e substituídos documentos da classe minoritária até que a classe esteja do mesmo tamanho que a maioritária. Com substituição significa que o mesmo documento pode ser usado várias vezes, ou seja, repetido. Como tem duas classes com muitas frases e duas com poucas, serão balanceado dois pares, sendo o primeira LGBTfobia e Gordofobia, e logo após, Sexismo e Racismo.

In [ ]:
from sklearn.utils import resample
train_majority = hate[hate.tipo=='LGBTfobia']
train_minority = hate[hate.tipo=='Gordofobia']
train_minority_upsampled = resample(train_minority, 
                                 replace=True,    
                                 n_samples=len(train_majority),   
                                 random_state=123)
balance1 = pd.concat([train_minority_upsampled, train_majority])
balance1['tipo'].value_counts()
Out[ ]:
Gordofobia    191
LGBTfobia     191
Name: tipo, dtype: int64
In [ ]:
from sklearn.utils import resample
train_majority = hate[hate.tipo=='Sexismo']
train_minority = hate[hate.tipo=='Racismo']
train_minority_upsampled = resample(train_minority, 
                                 replace=True,    
                                 n_samples=len(train_majority),   
                                 random_state=123)
balance2 = pd.concat([train_minority_upsampled, train_majority])
balance2['tipo'].value_counts()
Out[ ]:
Sexismo    174
Racismo    174
Name: tipo, dtype: int64
In [ ]:
hate = pd.concat([balance1, balance2])
In [ ]:
print('Tamanho da base de treinamento {}\n'.format(hate.shape[0]))
hate.tipo.value_counts()
Tamanho da base de treinamento 730

Out[ ]:
Gordofobia    191
LGBTfobia     191
Sexismo       174
Racismo       174
Name: tipo, dtype: int64

No gráfico abaixo é possível notar como as classes ficaram mais balanceadas, apesar de melhorar a situação para o código, não é ideal já que frases repetidas não acrescentam informações novas.

In [ ]:
import seaborn as sns
import matplotlib.pyplot as plt

sns.factorplot(x="tipo", data=hate, kind="count", size=6, aspect=1.5, palette="PuBuGn_d")
plt.show();
/usr/local/lib/python3.6/dist-packages/seaborn/categorical.py:3666: UserWarning: The `factorplot` function has been renamed to `catplot`. The original name will be removed in a future release. Please update your code. Note that the default `kind` in `factorplot` (`'point'`) has changed `'strip'` in `catplot`.
  warnings.warn(msg)
/usr/local/lib/python3.6/dist-packages/seaborn/categorical.py:3672: UserWarning: The `size` paramter has been renamed to `height`; please update your code.
  warnings.warn(msg, UserWarning)

6. Tokenização

Cada palavra em uma frase tem um peso, ou seja, não se deve olhar uma frase como um todo, mas cada palavra que compõem esta frase. Logo, o Python precisa pegar cada frase e a separar. Representando assim cada documento de texto como o conjunto de suas palavras. Essa representação é conhecida como Bag-of-Words, em que geramos os atributos do texto como atributos categóricos. E esse processo é conhecido como tokenização lexical que marca cada palavra como um token no texto, identificando-a mesmo se tiver encostada em alguma pontuação. Dessa forma, a função quebra cada texto em palavras, criando desse modo um array com todas as palavras contidas dentro do texto. Por exemplo, como é possível observar a baixo, a frase "nos só realizamos exames até tal peso" foi transformada no array ['nos', 'so', 'realizamos', 'exames', 'ate', 'tal', 'peso'].

In [ ]:
import gensim

data = hate.frase.values.tolist()

def sent_to_words(sentences):
    for sentence in sentences:
        yield(gensim.utils.simple_preprocess(str(sentence), deacc=True))  

data_words = list(sent_to_words(data))

print(data_words[:3])
[['nos', 'so', 'realizamos', 'exames', 'ate', 'tal', 'peso'], ['ta', 'gorda', 'demais'], ['ta', 'gorda', 'demais']]

7. Stop-Words

Ainda trabalhando no texto, é necessário remover as "stopwords" que são palavras muito frequentes, tais como “a”, “de”, “o”, “da”, “que”, “e”, “do” entre outras. São palavras que podem ser consideradas irrelevantes para o entedimento do sentido de um texto, ou seja, palavras semanticamente irrelavantes normalmente advérbios, artigos, pronomes e preposições. No array abaixo é possível ver as palavras removidas.

In [ ]:
import nltk
import numpy as np

nltk.download('stopwords')
nltk.download('rslp')
lista_Stop = nltk.corpus.stopwords.words('portuguese')
np.transpose(lista_Stop)
[nltk_data] Downloading package stopwords to /root/nltk_data...
[nltk_data]   Package stopwords is already up-to-date!
[nltk_data] Downloading package rslp to /root/nltk_data...
[nltk_data]   Package rslp is already up-to-date!
Out[ ]:
array(['de', 'a', 'o', 'que', 'e', 'do', 'da', 'em', 'um', 'para', 'com',
       'não', 'uma', 'os', 'no', 'se', 'na', 'por', 'mais', 'as', 'dos',
       'como', 'mas', 'ao', 'ele', 'das', 'à', 'seu', 'sua', 'ou',
       'quando', 'muito', 'nos', 'já', 'eu', 'também', 'só', 'pelo',
       'pela', 'até', 'isso', 'ela', 'entre', 'depois', 'sem', 'mesmo',
       'aos', 'seus', 'quem', 'nas', 'me', 'esse', 'eles', 'você', 'essa',
       'num', 'nem', 'suas', 'meu', 'às', 'minha', 'numa', 'pelos',
       'elas', 'qual', 'nós', 'lhe', 'deles', 'essas', 'esses', 'pelas',
       'este', 'dele', 'tu', 'te', 'vocês', 'vos', 'lhes', 'meus',
       'minhas', 'teu', 'tua', 'teus', 'tuas', 'nosso', 'nossa', 'nossos',
       'nossas', 'dela', 'delas', 'esta', 'estes', 'estas', 'aquele',
       'aquela', 'aqueles', 'aquelas', 'isto', 'aquilo', 'estou', 'está',
       'estamos', 'estão', 'estive', 'esteve', 'estivemos', 'estiveram',
       'estava', 'estávamos', 'estavam', 'estivera', 'estivéramos',
       'esteja', 'estejamos', 'estejam', 'estivesse', 'estivéssemos',
       'estivessem', 'estiver', 'estivermos', 'estiverem', 'hei', 'há',
       'havemos', 'hão', 'houve', 'houvemos', 'houveram', 'houvera',
       'houvéramos', 'haja', 'hajamos', 'hajam', 'houvesse',
       'houvéssemos', 'houvessem', 'houver', 'houvermos', 'houverem',
       'houverei', 'houverá', 'houveremos', 'houverão', 'houveria',
       'houveríamos', 'houveriam', 'sou', 'somos', 'são', 'era', 'éramos',
       'eram', 'fui', 'foi', 'fomos', 'foram', 'fora', 'fôramos', 'seja',
       'sejamos', 'sejam', 'fosse', 'fôssemos', 'fossem', 'for', 'formos',
       'forem', 'serei', 'será', 'seremos', 'serão', 'seria', 'seríamos',
       'seriam', 'tenho', 'tem', 'temos', 'tém', 'tinha', 'tínhamos',
       'tinham', 'tive', 'teve', 'tivemos', 'tiveram', 'tivera',
       'tivéramos', 'tenha', 'tenhamos', 'tenham', 'tivesse',
       'tivéssemos', 'tivessem', 'tiver', 'tivermos', 'tiverem', 'terei',
       'terá', 'teremos', 'terão', 'teria', 'teríamos', 'teriam'],
      dtype='<U12')

8. Stemming

É uma técnica que permite diminuirmos a palavra até a sua raiz/radical. Assim são eliminados prefixos, sufixos, características de número, gênero e grau. Desta forma, diversas palavras são reduzidas para um mesmo termo e tratadas como uma só. Para exemplificar, as palavras mulher e mulheres quando submetidas à função de Stemming, ambas as palavras serão diminuídas até a base "mulh".

In [ ]:
import spacy
def aplica_Stemmer(texto):
    stemmer = nltk.stem.RSLPStemmer()
    frases_sem_Stemming = []
    for(palavras) in texto:
        com_Stemming = [str(stemmer.stem(p)) for p in palavras if p not in lista_Stop]
        frases_sem_Stemming.append(" ".join(com_Stemming))

    return frases_sem_Stemming
In [ ]:
data_words = aplica_Stemmer(data_words)

Gráfico de Frequências das Palavras

O gráfico abaixo apresenta a frequência das vinte palavras que mais aparecem em analisando todas os documentos. Pode-se se observar que as mais aparecem são as raízes nao,você, gord, mulh e ser. Talvez para outros propósitos as palavras "nao" e "ser" fossem desnecessárias, porém para esse trabalho, elas possuem pesos importantes, a palavra "não" por exemplo é bastante frequente em frases sexistas.

In [ ]:
import collections
cv = CountVectorizer()
bow = cv.fit_transform(data_words)
word_freq = dict(zip(cv.get_feature_names(), np.asarray(bow.sum(axis=0)).ravel()))
word_counter = collections.Counter(word_freq)
word_counter_df = pd.DataFrame(word_counter.most_common(20), columns = ['word', 'freq'])
fig, ax = plt.subplots(figsize=(12, 10))
sns.barplot(x="word", y="freq", data=word_counter_df, palette="PuBuGn_d", ax=ax)
plt.show();

O algoritmo do modelo NMF requer uma matriz de documento por palavra como a entrada principal. Então, vou vetorizar meus dados usando transformação TfidfVectorizer, que irá contar as ocorrências de cada palavra, em cada documento, resultando em uma matriz de termos-freqüências de Dimensões: quantidade de documentos por quantidade de palavras, onde a ordem das palavras não importa.

Nem todas as palavras presentes em um docmento possuem a mesma importância. Em qualquer documento de texto, haverá várias palavras que aparecem com muita frequência e que nem sempre são significantes para a classificação. Se fôssemos construir um modelo sem pesar essas palavras, elas ofuscariam palavras menos frequentes durante o treinamento. Ao ponderarmos estas palavras de alta frequência, podemos atribuir, por exemplo, mais importância a palavras menos frequentes, mas talvez mais úteis.

Há várias fórmulas para calcular a importância ou peso da palavra no documento, porém aqui será utilizado o método TFIDF.

Frequência Absoluta (TF)

$TF(w) = \frac{F(w) }{F(Todas as palavras)}$

onde $F(w)$ é a frequência de um termo $w$ em um documento.

A matriz de termos-freqüências (TF) atribui uma pontuação a uma palavra com base em sua ocorrência em um documento específico . Isso é ruim pois palavras mais comuns (artigos, preposições, etc) deveriam ter peso menor, já que são menos discriminantes, para isso foram ignoradas palavras comuns como artigos e preposições usando (stopwords). Porém, pode haver palavras comum para a situação, mas que não está dentro da lista de palavras do stopwords. O TFIDF resolve esse problema.

Frequência Inversa de Documentos (IDF)

$IDF(w) = log\frac{N}{dF_t}$,

onde $N$ é a quantidade de documentos e $dF_t$ é a quantidade de documentos em que o termo $w$ aparece.

A fórmla do IDF é capaz de aumentar a importância de palavras que aparecem um poucos documentos e diminuir a importância de palavras que aparecem em muitos, já que termos de baixa frequencia são normalmente mais discriminantes.

Assim o peso de cada termo (t):

  • aumenta quando t aparece muitas vezes em poucos documentos
  • diminui quando t aparece em muitos documentos
  • diminui quando t aparece poucas vezes no documento

10. Construtor de Classe

Existem alguns parâmetros importantes que devem ser passados para o construtor da classe. O primeiro parâmetro é o max_features. Isso ocorre porque, quando convertemos palavras em números usando a abordagem do pacote de palavras, todas as palavras únicas em todos os documentos são convertidas em recursos. Todos os documentos podem conter dezenas de milhares de palavras únicas. Mas as palavras que têm uma freqüência muito baixa de ocorrência são raramente um bom parâmetro para classificar documentos. Assim, ao atribuir um número inteiro $n$ ao max_features, apenas as $n$ palavras que mais ocorrem como recursos serão consideradas.Como o dataset aqui utilizado é pequeno e restaram poucos recursos após o processameto do texto, o max_features não é necessário e não entrará no construtor.

O próximo parâmetro é min_df que foi definido como 5. Isso corresponde ao número mínimo de documentos que devem conter esse recurso. Desta forma, apenas as palavras que ocorrem em pelo menos 5 documentos serão inclusas. Da mesma forma, para o max_df, o valor é definido como 0,85, em que a fração corresponde a uma porcentagem. Aqui 0.85 significa que será incluiso apenas as palavras que ocorrem em no máximo 85% de todos os documentos. Palavras que ocorrem em quase todos os documentos geralmente não são adequadas para classificação porque não fornecem informações exclusivas sobre cada um.

Finalmente, as palavras de parada (stop words) serão removidas do texto, pois, no caso da análise de sentimento, as palavras de parada não podem conter nenhuma informação útil.

$d_{\mathrm{Fro}}(X, Y) = \frac{1}{2} ||X - Y||_{\mathrm{Fro}}^2 = \frac{1}{2} \sum_{i,j} (X_{ij} - {Y}_{ij})^2$

In [ ]:
print("Extracting tf-idf features for NMF...")
tfidf_vectorizer = TfidfVectorizer(max_df=0.85, min_df=5,
                                   stop_words= lista_Stop)
t0 = time()
tfidf = tfidf_vectorizer.fit_transform(data_words)
print("done in %0.3fs." % (time() - t0))
Extracting tf-idf features for NMF...
done in 0.015s.

11. NMF - Fatoração de Matriz Não-Negativa

A NMF (fatoração de matriz não-negativa) é um método de fatoração de matriz em que as matrizes são restringidas a serem não-negativas. Nessa redução dimensional a matriz inicial $V$ é decomposta em duas matrizes $W$ e $H$, sendo que as três matrizes são não-negativas, ou seja, possuem todos os seus valores nulos ou positivos.

No NMF a matriz original $V (m$ x $n)$ onde $m$ é o número de documentos e $n$ o número de palavras, é aproximadamente fatorizado em uma matriz $D = WH$, onde $W (m$ x $k)$ é a matriz de pesos , $H (k$ x $n)$ é a matriz de características e $k$ é um parâmetro definido. Nessa aplicação, $k$ será o número de agrupamentos e está associado ao número de tópicos a serem encontrados nas frases. Geralmente k é escolhido para ser menor que $n$ ou $m$, de modo que $W$ e $H$ sejam menores que a matriz original D. Isso resulta em uma versão compactada da matriz de dados original.

NMF - Modelagem de tópicos

alt text

Uma matriz documento-termo, como a que foi montada anteriormente, pode ser decomposta em componentes que podem ser considerados “tópicos” e cada documento pode ser decomposto em uma média ponderada de tópicos. Devido a isso, essa decomposição é a que melhor se aplica a esse trabalho já que a não-negatividade torna a interpretacão destas matrizes mais simples. Não seria possível ter uma interpretação lógica do que significa um tópico ter peso “negativo”. Apenas zero que implica o tópico não está relacionado ao documento, ou um valor positivo que indica seu peso no mesmo.

Embora existam algumas variantes, uma medida existente que será usada é a norma Frobenius (a soma dos erros quadrados por elementos).

$||a||_F = tr(a^T,a)^(\frac{1}{2})$

Onde $tr(x,y)$ representa o produto interno entre $x$ e $y$.

NMF - Aplicando o Algoritmo

No Python , o NMF é implementado a classe decomposition.NMF da biblioteca de aprendizagem de máquina chamada “Scikit-Learn”. Essa classe utiliza como método de otimização o método MU (Multiplicative Update).

Neste método, o $W$ e o $H$, cada um deles é atualizado iterativamente de acordo com a seguinte regra que garante que uma vez tendo-se matrizes não-negativas, a atualização garante a preservação da não-negatividade:

O processo iterativo consiste em alternadamente realizar o método de gradiente descendente para a matriz $W$ e $H$:

$W ← W − ηW∇wf$

$H ← H − ηH∇Hf$

sendo $ηχ$ uma matriz contendo os passos a serem escolhidos e $∇χf$ o gradiente.

e assim, calcular seu gradiente em relação a $W$ torna-se mais fácil:

$∇Wf = WHH^T − VH^T$

Analogamente, em relação a $H$:

$∇Hf = W^TWH − W^TV$

Substituindo as Equaçõe, as respectivas regras de atualização são dadas por

$W ← W − ηW(WHH^T − VH^T)$

$H ← H − ηH(W^TWH − W^TV$

Adotando:

$ηW = \frac{W}{WHH ^ T}$

e

$ηW = \frac{H}{W^ TWH}$

A descida de gradiente escalada pode ser escrita da seguinte forma:

$W ← [W]_{i,j} [\frac{VH^ T}{WHH ^ T}]_{i,j} $

$H ← [H]_{i,j} [\frac{W^ TV}{W^ TWH}]_{i,j} $

Essa é a regra de atualização multiplicativa utilizada para obter as matrizes $W$ e $H$.

In [ ]:
vectors_tfidf = tfidf_vectorizer.fit_transform(data_words)
V = tfidf_vectorizer.fit_transform(data_words).toarray()
vocab = np.array(tfidf_vectorizer.get_feature_names())

Tamanho do Vocabulário

Apos o processo de Stemming e retirada das Stop Words sobraram apenas 203 palavras no vocabulário, o que é um número bem pequeno para um bom resultado.

In [ ]:
len(vocab)
Out[ ]:
203

Tamanho da Matriz

A matriz que foi montada com o dataset após todos o processamento de texto, possui 730 linhas, ou seja, 730 documentos e 203 colunas em que cada uma representa uma palavra do vocabulário presente no dataset.

In [ ]:
V.shape
Out[ ]:
(730, 203)
In [ ]:
from sklearn import decomposition

num_topics = 6
num_top_words = 10

clf = decomposition.NMF(n_components=num_topics, random_state=1)

Decomposição da Matriz

Implementado a classe decomposition.NMF da biblioteca “Scikit-Learn”.O método de otmização MU (Multiplicative Update) anteriormente será aplicado, e assim serão obtidas as duas matrizes $W$, de tamanho $(730, 6)$ e $H$, de tamnho $(6, 203)$.

In [ ]:
W = clf.fit_transform(vectors_tfidf)
H = clf.components_
In [ ]:
W.shape
Out[ ]:
(730, 6)
In [ ]:
H.shape
Out[ ]:
(6, 203)

Matriz W

Cada elemento $a_{ij}$ da matriz $W$ representa a importância de cada tópico $j$ sobre o o documento $i$.

Matriz H

Cada elemento $a_{ij}$ da matriz $H$ representa o peso da palavra $j$ sobre o tópico $i$. Abaixo, é possivel observar pelo primeiro array da matriz $H$, o peso de cada uma das $203$ Palavras sobre o Tópico $0$.

In [ ]:
H[0:1]
Out[ ]:
array([[9.54957250e-03, 1.67417086e-01, 0.00000000e+00, 2.41559344e-02,
        0.00000000e+00, 9.92716728e-03, 0.00000000e+00, 4.29351233e-02,
        1.20963035e-02, 0.00000000e+00, 0.00000000e+00, 2.51667159e-02,
        1.49903627e-01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
        3.91017207e-02, 0.00000000e+00, 1.36000450e-04, 6.47090070e-02,
        7.99964455e-04, 4.55128738e-02, 3.21448561e-02, 0.00000000e+00,
        4.44963501e-03, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
        5.12387357e-02, 6.53094919e-02, 5.05289779e-02, 4.55128738e-02,
        0.00000000e+00, 3.61160742e-02, 9.15190395e-03, 9.38395248e-03,
        2.21265885e-02, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
        0.00000000e+00, 1.30151319e-02, 0.00000000e+00, 0.00000000e+00,
        3.59232258e-03, 0.00000000e+00, 0.00000000e+00, 1.78320255e-02,
        5.23836869e-02, 4.02936022e-02, 1.73071497e-02, 0.00000000e+00,
        0.00000000e+00, 4.76311178e-02, 1.32648750e-02, 5.66996363e-02,
        1.90673714e-03, 4.17889623e-02, 1.43878664e-01, 3.32929630e-02,
        0.00000000e+00, 1.65487607e-01, 0.00000000e+00, 1.58316720e-01,
        3.44092785e-02, 5.10838378e-03, 1.10887296e-01, 0.00000000e+00,
        3.63367679e-02, 0.00000000e+00, 1.16932148e-02, 6.58857495e-02,
        3.44092785e-02, 0.00000000e+00, 2.87198311e-01, 3.18436939e-03,
        1.67747257e-01, 2.43612308e-02, 2.08623194e-02, 2.11256618e-01,
        3.59495875e-02, 4.01013218e-03, 0.00000000e+00, 5.58731830e-03,
        7.02500113e-02, 2.96655827e-02, 5.17922288e-02, 0.00000000e+00,
        1.05640101e-02, 0.00000000e+00, 1.01942496e-01, 0.00000000e+00,
        0.00000000e+00, 3.32223474e-02, 3.32929630e-02, 7.53400428e-02,
        6.84251329e-05, 4.58827243e-03, 2.20321937e-02, 4.55128738e-02,
        0.00000000e+00, 1.25598380e-02, 0.00000000e+00, 3.67775700e-02,
        0.00000000e+00, 1.55928237e-01, 0.00000000e+00, 0.00000000e+00,
        0.00000000e+00, 0.00000000e+00, 1.11804883e-01, 1.91849092e-02,
        2.53479464e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
        0.00000000e+00, 2.65040860e-02, 3.32929630e-02, 0.00000000e+00,
        1.20065887e-01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
        0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
        2.41462922e-03, 6.58415330e-03, 0.00000000e+00, 0.00000000e+00,
        0.00000000e+00, 0.00000000e+00, 3.44092785e-02, 0.00000000e+00,
        1.69021372e-01, 4.55128738e-02, 1.38049508e-01, 5.84090975e-02,
        0.00000000e+00, 1.79781100e-02, 0.00000000e+00, 1.40005395e-01,
        3.44092785e-02, 2.37292472e-02, 0.00000000e+00, 0.00000000e+00,
        5.95103634e-02, 0.00000000e+00, 0.00000000e+00, 8.43588145e-02,
        0.00000000e+00, 3.87087069e-02, 2.10486599e-02, 2.50727833e-01,
        0.00000000e+00, 0.00000000e+00, 5.13269237e-02, 0.00000000e+00,
        0.00000000e+00, 0.00000000e+00, 2.06322878e-02, 0.00000000e+00,
        0.00000000e+00, 1.24570527e-02, 0.00000000e+00, 5.11171827e-02,
        3.64590403e-02, 3.44092785e-02, 0.00000000e+00, 0.00000000e+00,
        0.00000000e+00, 0.00000000e+00, 4.64047866e-01, 0.00000000e+00,
        0.00000000e+00, 0.00000000e+00, 5.49988346e-02, 0.00000000e+00,
        0.00000000e+00, 2.35075875e-01, 0.00000000e+00, 3.22629458e-02,
        0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 2.77207211e-02,
        0.00000000e+00, 8.84228818e-02, 1.53786137e-02, 1.05282137e-01,
        4.25781247e-03, 2.39936938e-02, 4.10928645e-03, 0.00000000e+00,
        0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
        0.00000000e+00, 0.00000000e+00, 9.08463191e-03]])
In [ ]:
doctopic = clf.fit_transform(V)
In [ ]:
topic_words = []

for topic in clf.components_:
    word_idx = np.argsort(topic)[::-1][0:num_top_words]
    topic_words.append([vocab[i] for i in word_idx])
In [ ]:
doctopic = doctopic / np.sum(doctopic, axis=1, keepdims=True)
/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in true_divide
  """Entry point for launching an IPython kernel.
In [ ]:
frases = []

for fn in hate.frase:
    basename = os.path.basename(fn)
    name, ext = os.path.splitext(basename)
    name = name.rstrip('0123456789')
    frases.append(name)
       
frases = np.asarray(frases)
doctopic_orig = doctopic.copy()

num_groups = len(set(frases))

doctopic_grouped = np.zeros((num_groups, num_topics))

for i, name in enumerate(sorted(set(frases))):
    doctopic_grouped[i, :] = np.mean(doctopic[frases == name, :], axis=0)
    

doctopic = doctopic_grouped

Pelo array abaixo pode ser visto o peso de cada tópico sobre o primeiro documento, se ele fosse classificado apenas em um tópico, seria no tópico 4 que possui maior peso.

In [ ]:
doctopic[0]
Out[ ]:
array([0.        , 0.04014027, 0.11876195, 0.03487505, 0.60965322,
       0.19656952])

No código abaixo, pode-se observar os três tópicos com mais peso em cada frase, nota-se que as frases não estão mais na ordem que se encontravam no dataset, mas sim em ordem alfabética.

In [ ]:
frase = sorted(set(frases))

print("Top NMF topics in...")
  
for i in range(len(doctopic)):
    top_topics = np.argsort(doctopic[i,:])[::-1][0:3]
    top_topics_str = ' '.join(str(t) for t in top_topics)
    print("{}: {}".format(frase[i], top_topics_str))
Top NMF topics in...
 A única coisa que você pilota bem é fogão: 4 5 2
 Mulher age com emoção e não com a razão: 1 0 5
 Mulher não sabe jogar futebol: 1 0 5
90% dos adotados vão ser homossexuais e vão ser garotos de programa deste casal: 5 3 4
A coisa tá preta: 2 5 1
A mas também ela pediu né andando com um cara desses!: 5 2 1
A mulher nasceu para ser mãe: 5 1 4
A mulher que usa roupas provocativas não pode reclamar se for estuprada: 1 0 3
A mulher é mais sensível por isso é suscetível ao pecado  eles custam a acreditar mas quem manda mesmo é o homem: 1 0 5
A noite aquela avenida fica cheia de travecos se oferecendo para programa: 4 5 1
A única coisa que mulher sabe pilotar bem é o fogão: 1 5 2
ABSURDO!!!!! Deus fez o homem para a mulher e a mulher para o homem! Fim de papo: 1 0 5
Abusar de mulher feia é fazer um favor: 1 5 4
Achei foi pouco. Tinha que dar uns tapas no resto das aberrações que estão nessa modinha ai: 4 0 1
Adoro gay mas não gosto que fiquem se beijando na minha frente: 0 5 1
Agora eu não quero que o público LGBT crie currículo para as escolas públicas de primeiro grau: 0 4 5
Aparato excretor não reproduz: 0 5 4
Apesar de ser travesti eu como aquele cuzinho fácil: 5 4 3
Aquelas meninas da computação são tudo esquisita sem peito sem bunda pow dá nem pro cara pegar é melhor as da saúde: 5 4 1
Aquele cara tinha o comportamento de mulher ele era bem afrescalhado! : 1 5 4
Aquele traveco é horroroso mesmo eu não sei quem tem coragem de fazer programa com ele: 0 4 2
Aquilo é um traveco: 0 3 5
As coisas não são assim se o homem quiser ter filho a mulher tem parar a vida dela e ter: 1 0 2
As lésbicas são todas feias por isso que são lésbicas: 4 3 1
As mulheres têm que fingir que os homens é que mandam": 1 0 5
As negras têm mais necessidade de sexo: 3 1 5
Beijo gay: 5 0 4
Bicha safada: 5 4 3
Bissexualidade não existe: 0 4 5
Bolsomito 17. Morte aos negros gays e lésbicas: 3 5 0
Bolsonaro vai limpar essa faculdade de preto e viado: 5 0 3
Bom dia negros fedidos: 3 0 1
Cabelo ruim: 1 5 0
Cadê as mulheres do grelo duro do nosso partido?: 1 5 4
Casa só com 'mãe e avó' é 'fábrica de desajustados: 4 1 5
Claro que existe violência doméstica mas também tem mulher que gosta né?: 1 0 2
Como a mulher dar de mamar alimentar alguém é coisa de mulher por isso ela tem que estar na cozinha: 1 2 3
Como vai achar um marido se não faz nada dentro de casa: 0 4 5
Cor de pele: 5 3 4
Cor do pecado: 5 3 4
De tanto ser enrabado  ficou arrombado: 5 4 1
Deixa esse cabelo crescer desse jeito vai virar homem igual a filha da Gretchen: 1 5 0
Denegrir: 5 4 3
Depois tem gente que não sabe pq é estuprada. Por isso que não tenho dó não cada um faz por merecer suas atitudes: 0 1 4
Depressão é falta de Deus na vida da pessoa: 1 5 4
Deus fez o homem para a mulher: 1 0 5
Deve ser gorda e mal comida: 5 2 4
Digamos que viadinho é a lésbica que nasceu com piru: 5 4 0
Dá nojo: 0 5 4
E eu que fui "tentar" me maquiar e minha mãe disse que eu tava parecendo um traveco : 5 1 0
E os namoradinhos?: 5 4 3
E quando foi que você virou lésbica?: 4 5 0
Ela não namorava com um cara: 0 4 2
Ela não quis ficar comigo então provavelmente é lésbica: 0 4 5
Ela é brava assim porque é mal-amada: 5 4 0
Ela é lesbica porque ainda não conheceu um homem que a pegue de jeito: 0 1 4
Ele era da capoeira lia tudo sobre cultura preta e que dizia para mim que tinha medo de eu traí-lo e que por ser preta eu era viciada em sexo. E que negras são geneticamente mais propensas a serem infiéis porque precisam de mais sexo do que mulheres brancas. Que ele estava sendo corajoso em assumir uma mulher preta sabendo do risco que corria..: 5 1 3
Ele era boiola: 4 5 1
Ele é boiola porque gosta de homens e anda rebolando: 1 4 0
Elegeram um comedor de traveco: 0 3 5
Eles pegam mais no teu pé porque tu é menina: 4 0 2
Ensinar para a criança que ser gay é normal? Não!: 5 0 4
Então quem é o homem que é a mulher: 1 0 5
Essa blusinhha ta mostrando muito o peito vai acabar sendo estuprada: 2 0 5
Esse cara é muito estranho parece meio afrescalhado: 3 1 4
Esse cara é boiola viu como ele anda: 4 5 1
Esse catimbozeiro já era pra ter saído: 4 5 1
Esse negócio de experimentar não existe. Pronto: 0 5 4
Esse short ta muito curto pra tu: 2 5 4
Esse vestido tá muito curto!: 2 1 5
Esses jogadores estão jogando como mocinhas: 1 0 5
Este é meu melhor amigo gay: 5 3 0
Eu achei que ele fosse homem igual a mim: 1 4 0
Eu até entendo ser gay mas precisa ser afeminado desse jeito: 5 3 0
Eu mando nela: 5 4 3
Eu não estou sendo homofóbico você é que está sendo muito sensível: 4 0 5
Eu não tenho nenhum problema com lésbicas inclusive eu adoro vê-las se pegando: 0 4 5
Eu não tive filho homem pra ser viado: 5 0 1
Eu sou homem de verdade. Uma noite comigo e você vai mudar de ideia: 4 0 1
Eu só não entendo por que você iria querer mutilar seu corpo: 4 0 5
Eu só quero pedir para que as vagabundas não se ofendam: 0 3 4
Existem até mulheres competentes: 1 3 0
FELIZ NATAL lésbica amada q só come peru na noite de natal!! Cuidado pra nao engasgar: 0 4 5
Família gay não existe: 0 5 4
Fecha as pernas: 4 5 3
Feminista até se casar: 3 4 1
Feminista é tudo gorda e puta: 2 5 4
Ficou perfeito até parece homem de verdade!: 1 4 3
GAY = LIXO: 5 0 4
Gay não é gente fora do Mackenzie: 0 5 4
Gorda com piercing no umbigo e barriga de fora é demais ne?: 2 5 4
Gosto de ter onde pegar: 1 4 0
Handebol é jogo pra homem: 1 5 4
Homem não chora: 0 1 4
Homem não cuida de criança quem cuida é a mãe e irmã não o pai: 0 1 5
Homem pode ter cabelo branco mulher não. Fica feio: 1 0 4
Homem que é homem não anda arrumado desse jeito esse aí só pode ser viado: 5 1 0
Homem trai mesmo: 1 4 0
Homossexualidade é uma doença: 5 4 3
Isso aí é coisa de marica: 2 1 3
Isso não deixa seu parceiro inseguro?: 0 5 4
Isso não existe você só se decepcionou com algum homem: 4 0 1
Isso é coisa de gorda marxista: 2 1 5
Isso é coisa de mulher promíscua: 1 2 3
Isso é moda logo vai passar!: 5 0 4
Já sabe cozinhar já pode casar!: 4 1 5
Já é preto e ainda por cima gay?: 5 0 4
Larga de ser viadinho: 5 4 3
Legging é roupa de academia não pra usar no dia a dia: 0 5 4
Lugar de mulher é na cozinha: 1 3 5
Lugar de traveco é no cemitério: 3 0 1
Lá vem o baitola!: 4 5 0
Lésbicas ridículas e nojentas: 5 0 4
Macho véi o Zequinha é baitola ele foi pego comendo um viado atrás de uma moita na rua da feira: 5 4 1
Mas como você vai fazer quando quiser ter filhos?: 4 1 5
Mas como vocês transam?: 4 5 3
Mas engenharia mecânica muito masculino por que você não faz contabilidade?: 4 0 5
Mas eu não vou ser paquerado em um bar gay?: 5 0 4
Mas eu tenho amigos negros: 3 0 5
Mas o que vocês fazem não é bem sexo né?: 4 0 5
Mas ser gay vai contra a natureza: 5 0 4
Mas suas amigas trocam de roupa na sua frente: 3 0 2
Mas tem umas meninas que pedem": 0 5 4
Mas você já tentou com um homem: 4 1 0
Mas você já transou com um homem pra saber se gosta: 4 1 5
Mas você já transou com uma mulher pra saber se gosta: 4 1 5
Mas você não acha que falta alguma coisa?: 4 0 2
Mas você não sabe cozinhar? Menina você tem que aprender a fazer as coisas na cozinha: 4 0 1
Mas você prefere mais homens ou mulheres?: 1 4 5
Mas você vai me entenderquando você tiver com duas crianças ocupando praticamente todo o seu tempoe o seu marido reclamando pq vc não faz as coisas dentro de casa: 4 0 1
Mas você é mulher tem que ser fofa e delicada não ficar mostrando o dedo do meio assim: 5 4 1
Me trocou por aquela gorda?: 2 5 4
Menina informática? Você não prefere dançar?: 4 0 5
Menina não grita: 0 3 5
Menina não pode empinar pipa: 0 1 5
Menina tem que brincar com coisa de menina: 2 0 1
Menina tem que vestir rosa: 0 4 1
Mercado negro: 3 5 4
Meu professor é boiola: 4 5 1
Meus amigos gays têm postura nunca gostei de viadinho: 5 3 0
Mulata: 4 5 3
Mulher bissexual é disseminadora de DSTs: 1 4 5
Mulher com mulher não faz filho: 1 0 5
Mulher com pelo parece um homem: 1 0 4
Mulher de boca suja é horrível: 1 2 3
Mulher deve ganhar salário menor porque engravida: 1 4 5
Mulher e carro quanto menos rodados melhor: 1 5 4
Mulher falando palavrão é feio: 1 5 4
Mulher na política não dá certo: 1 0 5
Mulher no volante perigo constante: 1 5 4
Mulher no volante..: 1 5 4
Mulher não gosta de homem; gosta de dinheiro: 1 0 5
Mulher não pode beber e passar do limite é feio demais: 1 0 2
Mulher não pode dar no primeiro encontro: 1 0 5
Mulher não sabe dirigir: 1 0 5
Mulher que diz ‘não’ para mim está só se fazendo de difícil: 1 0 4
Mulher que usa cabelo curto é sapatão: 1 5 4
Mulher que vai para cama no primeiro encontro não serve para casar: 1 0 4
Mulher tem de se dar ao respeito: 1 3 5
Mulher tem que se cuidar: 1 5 4
Mulher é muito problemática: 1 5 4
Mulheres que se dão ao respeito não são estupradas: 1 0 3
Mãe solteira? Vai ser difícil achar um homem que te aceite assim: 5 1 0
Na cama deve ser um pouco entediante né sem pênis e penetração..: 5 2 4
Na hora de pagar a conta nenhuma mulher é feminista: 1 3 5
Na verdade toda mulher gosta de um cafajeste: 1 3 4
Nada contra até tenho amigos que são mas…: 3 4 1
Nada de agir como mulherzinha: 1 0 5
Nenhum cara queria dormir com você e por isso hoje você prefere meninas certo?: 4 0 5
Ninguém precisa saber que você é gay: 4 5 0
Nossa mas você tem certeza que é lésbica? É tão feminina: 4 5 3
Nossa mas você é tão bonita pra ser lésbica: 5 4 3
Nossa mas é muita DR e TPM junta né: 2 5 1
Nossa parece até mulher de verdade: 1 3 4
Nossa seu namorado é branco? Tá de parabéns: 2 3 4
Nossa você é uma negra linda: 3 4 5
Nunca deixo mulher pagar conta pra mim é constrangedor": 1 4 5
Nunca vi mulher fazer nada que preste para a humanidade: 1 4 5
Não corta o cabelo!: 0 1 5
Não custa nada ser recatada: 5 0 4
Não existe essa coisa de feminicídio: 0 2 1
Não existem bissexuais existem sem-vergonhas: 0 4 1
Não precisa ficar contando para todo mundo que você é gay: 4 5 0
Não sei porque tanta discriminação. Minhas melhores professoras foram as prostitutas: 5 0 4
Não seja uma vadia: 0 5 4
Não sou tuas negas: 0 5 4
Não te estupro porque você não merece: 0 4 5
Não tem problema a mulher trabalhar fora desde que não atrapalhe nas tarefas domésticas: 0 1 5
Não tem problema ser gay desde que se comporte como homem: 5 0 1
Não temos o seu tamanho: 0 5 4
Não tenho TV colorida para ficar olhando essa preta não: 0 5 4
Não tenho nada contra as lésbicas mas eu não suportaria se minha filha fosse: 0 5 1
Não trabalhamos com roupas do se tamanho: 0 5 4
Não use isso na escola: 0 4 5
Não vou combater nem discriminar mas se eu vir dois homens se beijando na rua vou bater: 0 1 4
O Leozinho é muito baitola! Calça enfiada no rabo e gosta de dar o rabo!!: 1 0 4
O cabeleireiro é baitola: 4 1 5
O cabelereiro baitola ficou dando em cima do rapaz que foi cortar o cabelo: 4 5 1
O cara beija outro cara é boiola!: 4 5 0
O filho começa a ficar assim meio gayzinho leva um couro e muda o comportamento dele: 5 1 0
O homem deve ser submisso a Deus e trabalhar pra sustentar sua família: 5 1 4
O que acontece está menstruada?: 5 4 3
O que ela queria com um vestido daquele?: 4 0 1
O sangue de um homossexual pode contaminar o sangue de um heterossexual: 0 5 1
O seu macaco preto imundo vai aprender a jogar bola: 5 0 3
Ok você defender a igualdade mas não seja essas feministas não: 0 4 5
Olha o baitola como anda todo rebolando: 4 0 3
Olha só aquele travecão lá!: 4 0 1
Olha prali que desgraça esse macho e fêmea em cima do trio: 4 1 0
Onde está seu namorado?: 4 1 2
Pablo vitar é o único traveco feio: 1 3 0
Para uma negra até que você é bonita: 3 4 5
Pare de fazer gordice: 2 4 5
Pare de ser tão dramática: 5 3 2
Pediu pra ser estuprada: 5 4 0
Pena que não é homem: 0 1 4
Pode ser lésbica mas não precisa se vestir como homem: 5 0 1
Por isso que tá gordo: 2 5 4
Por mim está tudo bem desde que eu possa assistir!: 5 2 1
Por que você ainda não está casada?: 4 0 5
Por que você nunca usa vestidos?: 4 1 5
Por que você tá brava? É TPM?: 4 2 5
Porque mulher tem que ser mulher fingir tudo bonitinho: 1 5 4
Poxa fica difícil apoiar a causa gay assim. Vcs exigem respeito mas não respeitam: 0 5 1
Pra ficar bonita mulher tem que sofrer: 1 4 5
Pra ter virado lésbica ela só pode ter desistido de homem: 1 4 5
Preferia ter um filho drogado a ter um filho gay: 5 1 0
Prefiro ficar com a gorda que com você: 4 2 5
Preto emagrece lista engorda short não te cai bem tira o biquíni põe o maiô: 0 5 3
Qual a cor da sua vagina?..: 5 3 1
Quando ver duas barangas pretas na rua diga a do meio é uma gracinha: 5 4 0
Que coisa estranha é vc. Alma negra suja: 3 2 1
Que desperdício tão bonita: 4 3 5
Que desperdício tão lindo e gay: 5 4 3
Que respeitar homossexual: 5 0 4
Quem vai ficar com seus filhos?: 5 4 1
Quem é a ativa e quem é a passiva?: 5 4 3
Quem é a mulher da relação?: 1 5 4
Quem é o macho da relação?: 5 1 4
Roberta é uma arrombada todo mundo já comeu: 4 3 5
Sabe que o Brasil tá violento e ainda usa roupa curta. Tá pedindo pra ser estuprada: 5 2 0
Sai fora Maria-João: 5 4 3
Sapatas vão morrer: 5 3 4
Se acabou depois dos filhos: 5 1 0
Se continuar desse jeito não vai arrumar um marido: 0 5 1
Se ela foi estuprada a culpa é dela que estava dando mole: 0 3 1
Se eu tiver um filho gay algum dia eu estupro ele: 5 0 1
Se forem estupradas vão dar graças a Deus: 1 0 3
Se iludiu tanto que virou lesbica: 4 5 0
Se um casal homossexual vier morar do meu lado isso vai desvalorizar a minha casa ! Se eles andarem de mão dada e derem beijinho desvaloriza: 5 0 1
Se virem você brincar com os meninos vão chamar você de maria-sapatão: 4 0 5
Se você fica mais com homem você não é 100% bissexual: 4 0 1
Se você é sapatão é porque os caras com quem você transou deveriam ser muito ruins na cama: 4 5 3
Sempre quando vejo um preto vindo em minha direçaoja escondo meu relogiominha pulseira: 5 2 1
Ser gay tudo bem mas me xavecar já é demais: 5 2 0
Ser gorda tudo bem mas gorda chata não: 5 2 0
Seria incapaz de amar um filho homossexual: 0 1 5
Serviço de preto: 5 0 3
Será que você não é uma heterossexual recalcada?: 5 4 0
Seu currículo é ótimo você é super qualificada mas só tenho uniformes P: 4 5 3
Seu tio precisa arrumar logo uma mulher para cozinhar e lavar para ele: 1 5 4
Sou preconceituoso com muito orgulho: 5 4 3
Sua pele é bem escura parece gringa: 5 1 2
Só conseguiu emprego no Jornal Nacional por causa das cotas preta imunda: 5 4 0
Te pago com banana: 1 5 4
Tem que bater na mulher isso sim: 1 3 5
Tem que saber fazer comida sim como vai arranjar um namorado desse jeito?: 5 1 4
Tem viado que precisa levar um murro na boca para aprender a falar como homem: 1 5 4
Temos que destruir isso na raíz e matar Jean Wyllys: 5 4 3
Tenho curiosidade de ficar com uma mulher trans: 1 4 5
Tenho fetiche em mulher gorda: 1 2 5
Ter ciúme de mulher feia é como colocar alarme em um Fiat 147 : 1 5 4
Ter filho faz parte da vida vc tem que agradar seu marido: 1 4 5
Tinha que ser preto pra fazer cagada: 5 4 0
Tinha que ser uma mulher pra dirigir tão ruim assim: 5 1 4
Tinha que ser viado: 5 3 4
Tira esse short e coloca uma calça porque não quero que pensem que minha namorada é uma vagabunda: 0 4 3
Todas as mulheres do Brasil deveriam ganhar um tapa na cara: 1 5 3
Transexuais são homens vestidos de mulher: 1 3 4
Tudo bem se a minha mina for bi principalmente se ela me convidar pra um ménage: 5 4 2
Tudo bem ser gay mas não precisa ficar desmunhecando: 5 0 4
Tudo bem ser gay não precisa ficar dando pinta: 5 0 4
Tá com a cara fechada por que? Brigou com o namorado?: 2 4 0
Tá gorda demais: 2 5 4
Um homem tão bonito e gay… que desperdício!: 5 1 4
Uma mulher só é completa quando tem filhos: 1 4 5
Ué mas você é mulher! Como não sabe cozinhar?: 1 4 0
Vai chorar mocinha?: 5 0 4
Vai sair com essa roupa? Depois não reclama se for estuprada: 0 3 5
Vamo quebrar lampada na cabeça dessas bicha: 5 1 3
Veado bom é veado morto: 3 1 5
Vestido curto demais. Tá pedindo..: 2 5 1
Viado sujo você merece morrer: 4 2 3
Viado tem que morrer: 5 3 1
Vira homem arrombado: 1 4 0
Vira homem!: 1 4 0
Viu o Balta passando o piru na bunda do boiola ele quis sentir entrar no seu cu mas ficou só no sarro: 4 5 1
Você até que é bonita para trabalhar com computação: 4 3 0
Você deve pegar todas porque tem o pau grande né?: 4 5 2
Você deveria se sentir agradecida por aquela cantada: 4 5 3
Você está certa se os caras continuarem idiotas como são hoje eu também vou começar a sair com mulheres: 4 1 3
Você está saindo com um cara mais novo? Que loba!: 4 5 3
Você gosta de mulheres porque tem nojo de homens. Você deve ter namorado só idiotas: 4 1 5
Você ia ficar linda se emagrecesse algns quilinhos: 4 5 1
Você já transou com alguma mulher ou só tá querendo ser moderna?: 5 4 1
Você nem dá pinta de gay eu não tinha ideia que você fosse: 4 0 5
Você nem parece trans: 4 1 5
Você não acha que está muito gorda pra usar isso?: 4 2 0
Você não acha que já comeu demais?: 4 0 2
Você não acha que vai sentir falta de sexo com homens um dia: 4 0 1
Você não acha que é lésbica só por que nunca encontrou o homem certo?: 4 0 1
Você não acha que é lésbica só por que nunca encontrou o homem certo : 4 0 1
Você não engravida porque é gorda: 4 2 0
Você não tem do que reclamar do seu marido. Você tem sorte. Ele poderia estar lhe batendo e ter outras mulheres: 4 1 0
Você não é bissexual? Deixa eu fazer parte da brincadeira: 4 0 5
Você não é gay: 4 0 5
Você não é gay tá confuso: 4 0 5
Você não é gorda você é gordinha: 4 2 0
Você pode ser gay mas não viado: 5 4 0
Você precisa de um namorado pra viver bem: 4 5 3
Você ser afeminado machuca meu coração: 5 4 3
Você ser sapatão é muita falta de rola: 5 4 3
Você só quer uma desculpa pra sair pegando todo mundo: 4 5 1
Você só é lésbica porque nenhum homem te comeu direito: 4 1 0
Você é assim lésbica desde sempre ou não: 4 0 1
Você é bissexual?: 4 5 3
Você é bonita nunca pensou em emagrecer?: 4 3 5
Você é homem tem que curti a vida mesmo: 4 1 0
Você é menina não pode jogar futebol: 4 0 1
Você é muito bonita pra ser lésbica: 5 4 3
Você é muito feminina para ser gay não é possível: 5 4 0
Você é mulher está na hora de casar e ter filhos: 1 4 5
Você é mulher óbvio que não entende nada da marvel: 1 4 0
Você é tão bonzinho um negro de alma branca e pura: 3 4 5
Você é um homem ou uma mulher?: 1 4 5
Você é uma mocinha. Aprende a sentar: 4 5 3
Você é uma mulata tipo exportação: 4 5 3
Você é uma princesa: 4 5 3
Você é um baitola!: 4 5 3
Vocês nunca vão ter respeito enquanto se vestirem de mulher: 4 1 5
Vocês podem não se tocar ou beijar? Meus filhos não vão entender: 0 4 5
Vocês são lésbicas? Então beija aí pra eu ver!: 4 5 3
Vocês usam vibrador: 4 1 0
Volta pra casa viadinho: 5 4 1
Vá mas se comporte como mulher direita: 1 5 4
a sociedade brasileira não gosta de homossexuais: 0 1 3
aquela putinha da Rússia não foi nada de besta se ela não quisesse que aquela 'brincadeira' acontecesse não tava no meio de um monte de homem: 0 1 5
arranjem maridos ricos para vocês se darem bem na vida: 4 5 1
as feministas querem ficar com os peitos de fora na rua: 4 5 0
bate no viadinho: 5 1 3
bicha: 5 4 3
boiola nojento e espalhafatoso argh: 4 5 1
convivo com negros: 3 5 4
depois que acabou a entrevista de emprego perguntou “mas vem cá vc vai vir todo dia com esse cabelo aí?”: 3 4 5
e uma mulher ainda acha que pode se igualar a um homem: 1 4 0
ei não sou racista mas 95% dos pretos tem cara de bandido marginal: 0 3 5
ela deu pro chefe só pode: 1 0 4
ela gosta de apanhar: 1 0 5
ela me largou para virar sapatão? Onde foi que eu errei?: 4 1 5
ela só é lésbica pq não conheceu um homem que faz gostoso: 0 1 4
ela tem cabelo ruim: 1 5 0
ela é bonita mas é gordinha: 2 4 3
emagrece que homem nao gosta de mulher assim nao: 1 0 4
essa roupa não tá muito gay?: 0 5 2
essas meninas ficam andando na rua a noite e depois reclama quando é estuprada!: 4 0 5
eu não estou sendo machista os homens dirigirem melhor que as mulheres eh um fato eh assim que funciona: 1 0 5
eu não tenho preconceito até tenho um amigo gay: 0 5 3
eu pensei que era uma mulher que tava dirigindo mas como é um homem deve ser algum problema no carro: 5 1 4
gorda suja: 2 3 5
gritei vai macaca pela janela e a vizinha negra bateu no portão  de casa pra me dar bronca: 3 5 1
homem não gosta de mulher alta se continuar crescendo desse jeito vai ficar solteira: 1 0 5
homossexual tem que morrer: 5 0 3
homossexualismo: 5 4 3
isso tudo é mimimi mulher tem que ficar em casa mesmo: 1 5 4
isso é coisa de mulherzinha: 1 2 3
jogo não é coisa de mulher vai lavar uma louça: 1 0 2
lista negra: 3 0 5
lugar de macaco é no zoológico: 3 0 1
ma vez você fez sexo de verdade?: 4 3 1
magia negra: 3 5 4
mas você tem que ficar com ele mesmo se ele te tratar mal pelo menos até o bebê nascer: 4 5 3
me empresta seu cabelo ai pra eu lavar louça: 5 4 1
meuracistasecreto-usuarios-do-twitter-expoem-frases-racistas-do-dia-a-dia: 0 3 5
mulher: 1 4 0
mulher ao volante perigo constante: 1 5 4
mulher que anda toda decotada mostrando tudo pra todo mundo não merece respeito minha opinião: 1 5 0
mulher que se valoriza demais perde a oportunidade de ter um homem bom: 1 2 3
mulher tem que ser mãe SIM ela nasceu pra isso: 5 1 4
nada contra as feministasmas que necessidade de tirar a roupa pra protestar e deixar o sovaco peludo?: 5 0 4
neguinha como você a gente estupra e depois queima para não poluir o solo: 3 4 0
nem pensa em cortar o cabelo de novo mulher tem que ter cabelo comprido: 1 4 5
nenhum homem gosta de mulher como você tem que mudar: 1 4 0
nossa você é linda se fosse na época da escravidão eu te comprava: 4 3 5
não basta ser sapatona tem que ser macho ainda por cima: 5 0 4
não helena vc n vai usar essa bermuda só homem pode!: 0 1 4
não há lugar para negros sujos: 3 0 2
não quer engravidar fecha as pernas: 0 4 5
não sou preconceituoso tenho até um amigo negro: 3 0 4
nós só realizamos exames até tal peso: 3 4 1
o afro-descendente mais leve lá pesava 7 arrobas eu acho que nem pra procriador eles servem mais: 4 5 0
o brasil seria mais lindo se não houvesse frescura com piadas racistas mas já que é proibido a única solução é extarminar os negros: 3 0 4
olha a roupa que ela tava usando: 0 4 2
olha como o viadinho rebola: 5 0 4
onde você comprou essa camisa tinha pra homem?: 4 1 5
ovelha negra: 3 5 4
para de agir como uma mulherzinha: 1 5 4
parece um mulequinho com esse bonéquem disse que vc pode usar assimé coisa de garoto: 1 2 0
perai que voz de traveco é essa?: 0 3 5
pergunta como você é na cama porque sempre ouviu que pretas são mais quentes: 4 5 0
piaçava: 5 4 3
pode ser gay mas não precisa beijar em público: 5 0 4
preto vai morrer: 5 0 3
quando conhecer uma piroca de verdade você casa: 4 3 1
quer morre viado: 5 4 3
roupas grandes nesta loja: 4 0 5
sai pra la boiola: 5 4 1
se aborto é uma questão que as mulheres decidem estupro é uma questão dos homens: 1 0 3
se fosse pra pegar uma mulher macho era melhor ficar com homem logo: 1 5 4
se mexem com você na rua é sinal que você é bonita você tem que agradecer: 4 3 5
se vc arrumasse uma mulher não ia precisar fica lavando louça e limpando casa: 1 0 4
só o começo. Vamos limpar Altamira desta peste negra: 3 5 1
só pode fazer sexo depois do casamento pq se não fica rodada: 1 0 4
tem quilombola pesando 7 arrobas: 4 3 5
tenho colegas negros: 3 5 4
teu namorado deixa?: 0 4 2
to começando a virar racista por causa dessas cotas que beneficiam os pretos: 5 3 0
todo jovem negro é vagabundo e bandido: 3 0 1
um bando de vagabundinha de vestido curto: 3 1 4
vai cortar mais seu cabelo? assim não vai arrumar homem nenhum: 0 1 5
veste uma roupa descente: 0 1 4
viado: 5 3 1
você está engordando demais nessa gravidez depois que ganhar o nenê seu marido vai te trocar por outra hein: 4 2 5
você reclama dos homens mexerem com você na rua? vai ver quando chegar na minha idade e ninguém se quer olhar pra você vai se sentir feia: 4 1 5
você tem que aprender a cozinhar pra quando você se casar saber fazer as coisas: 4 5 1
vão se foder seus negros e feministas de merda gays do demo queime judeus: 3 5 0
 Então você faria um ménage?: 4 5 3
 Menina não brinca de luta: 0 4 5
 Nenhum cara quer transar com uma virgem: 4 1 3
 O que vocês fazem na cama: 4 5 0
É A VIDA SE tivesse nascido branca talvez peguasse algueen: 5 3 4
É falta de rola: 4 5 0
É lésbica pq nunca te peguei de jeito: 4 5 0
É melhor você chamar um homem para te ajudar com isso: 4 1 0
É muito bonita pra ser inteligente: 5 4 3
É ridículo você acreditar que ainda existe racismo no Brasil. Estão é se fazendo de vítimas: 4 0 5
É tudo moda é porque você é jovem e ainda está procurando: 4 5 3
É verdade que as negras são as rainhas do sexo anal?: 3 1 4
é diferente ele é homem: 1 0 4
é esse cabelo curto aí?! Tá parecendo homem: 1 2 0
“Inveja branca: 3 4 5

12. Resultado

Finalmente, é possivel visualizar as palavras de maior peso que caracterizam cada tópico. Como a matriz possui 203 colunas, o seja, cada tópico tem o peso de todas as palavras, o número de palavras que serão usadas para caracterizar é escolhido manualmente, aqui foi estipulado como 10, assim aparecem apenas a 10 top words de cada tópico. Este é o resultado final do projeto, com base na análise das palavras mais importantes de cada tópico é que se deve classificá-lo, mas como o dataset utilizado é pequeno e vocabulário ficou com poucas palavras, o resultado obtido não ficou satisfatório, sendo complicado a classificar cada tópico. Um dos que daria pra classificar seria o tópico 1. Como as palavras de mais importância dele são "mulher", "homem", "gosta/gostosa", "fetiche", "feia", "sabe/saber", pode ser classificado como Sexismo.

Se o resultado obtido fosse satisfatório, assim seria feita a análise. Cada tópido receberia uma das quatro classificações de acordo com suas 10 palavras mais importantes.

In [ ]:
for t in range (len(topic_words)):
    print("Tópico {}: {}".format(t, ' '.join(topic_words[t][:15])))
Tópico 0: nao tamanh gay roup trabalh hom pod gost ach estupr
Tópico 1: mulh hom gost fetich ter cois fei assim sab filh
Tópico 2: gord suj ta demal cois marx bonit fetich barrig umbig
Tópico 3: negr amig ate sex lug suj alm list bonit verdad
Tópico 4: voc bonit fic porqu nunc emagrec pra ach pens lind
Tópico 5: ser gay tud bem pra cheir chat legal dev precis

Nesta projeto foi apresentado a construção de um método de classificação de preconceito em textos aplicado em frases retiradas da internet em português brasileiro, onde todas possuiam discurso de ódio.

Na proposta foi utilizada uma metodologia para a análise do preconceito com base no aprendizado de máquina que envolvia o método de Fatorização de Matriz Não-Negativa. Para isso, foram realizadas as etapas de coleta de frase com teor preconceituoso, rotulação manual de cada frase, pré-processamento dos dados, construção de uma matriz com os dados, fatorização da matriz e análise do resultado.

O resultado obtido não foi satisfatório devido a baixa qualidade do dataset que além de possuir poucos documentos, não está balanceado e possue muitas frases parecidas, contendo assim um vocablário pequeno. Além disso, o tema escolhido possuem mensagens difíceis de serem rotuladas até mesmo pelos humanos, com isso as incertezas nas classificações também podem ser justificadas por essa qestão. Dessa forma, fica visível a dificuldade deste tipo de classificação já que envolve conceitos de opinião e pontos de vista.

14. Trabalhos Futuros

A partir dos resultados obtidos, nota-se que alguns pontos merecem atenção especial, como construir um dataset melhor e testar outros métodos para verificar se é possível obter um resultado com uma qualidade melhor.

Podem ser feitas também análises específicas sobre os termos mais comumente utilizados por usuários do Twitter para abordar um tipo de preconceito poderiam ser realizadas. Além disso, utilizar a geolocalização para identificar regiões que mais comentam sobre tais assuntos identificando a polaridade das mensagens.

Com isso, pretende-se dar continuidade a este projeto nas seguintes direções:

  • Obter um dataset maior e mais balanceado a partir de uma API fornecida pla rede social "twitter".
  • Procurar bibliotecas mais eficientes para o pré-processamento de textos em português brasileiro, se necessário, tentar construir uma ou trabalhar com documentos em inglês, já que para esse idioma é possível encontrar bibliotecas com boa qualidade.
  • Calcular a acurácia do resultado
  • Aplicar outros métodos como o LDA, para comparar os resultados obtidos e assim definir o melhor.
  • Incluir informacões geográficas – como latitude e longitude dos emissores dos tweets, permitindo a geracão de grafos associados e o estudo da difusão dos tipos de preconceito;
  • Criar uma função para analisar novos documentos de textos e classificá-los.

15. Licença

The MIT License (MIT) 2022 - Letícia Tavares. Leia o arquivo LICENSE.md para mais detalhes.

16. Referências

Topic modeling in Python - https://liferay.de.dariah.eu/tatom/topic_model_python.html Mineiração de Dados - http://thiagomarzagao.com/assets/teaching/mineracao/slides10.pdf

A Practical Introduction to NMF (nonnegative matrix factorization) - http://mlexplained.com/2017/12/28/a-practical-introduction-to-nmf-nonnegative-matrix-factorization/

Uma Abordagem Computacionnal para Identificação de Indício de Preconceito em Textos baseado em Análise de Sentimentos. - http://www.repositorio.ufal.br/bitstream/riufal/2465/1/Uma%20abordagem%20computacional%20para%20identifica%C3%A7%C3%A3o%20de%20ind%C3%ADcio%20de%20preconceito%20em%20textos%20baseada%20em%20an%C3%A1lise%20de%20sentimentos.pdf

NMF with the Frobenius norm - https://scikit-learn.org/stable/modules/decomposition.html#nmf-with-the-frobenius-norm

Sklearn.decomposition.NMF - https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.NMF.html

Identificação de Temas em Redes Sociais por meio de técnicas de agrupamento - https://siaiap32.univali.br/seer/index.php/acotb/article/view/10562/5917

Análise de Sentimento de Mensagens do Twitter em Português Brasileiro Relacionadas a Temas de Saúde - http://repositorio.unifesp.br/bitstream/handle/11600/41280/Disserta%E7%E3o%20-%20Gabriela%20Denise%20de%20Araujo.pdf;jsessionid=7CCB48A2713A5EDC4A5CAD91FA308B09?sequence=1

Análise dos sentimentos expressos na rede social Twitter em relação aos filmes indicados ao Oscar 2017 - https://repositorio.ufu.br/bitstream/123456789/20133/1/AnaliseSentimentosExpressos.pdf

Topic Modeling with NMF and SVD - https://github.com/fastai/numerical-linear-algebra/blob/master/nbs/2.%20Topic%20Modeling%20with%20NMF%20and%20SVD.ipynb

Non-Negative Matrix Factorization - https://github.com/lvazic/StockTradingInsights

Outros Projetos

Confira alguns dos meus outros projetos

Contato

FALE COMIGO!