<jupyter_start><jupyter_text>Analise de Sentimentos Fazendo Join de duas bases pré-classificadas em português(1) Resenhas: https://www.linguateca.pt/Repositorio/ReLi/(2) Tweets: https://www.kaggle.com/leandrodoze/sentiment-analysis-in-portuguese Inspirador Por: (2)<jupyter_code>#Importando as bibliotecas necessárias a essa atividade
import os
import re
import pandas as pd
import numpy as np
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
#Leitura dos arquivos da coleção ReLi
base_path_reli = 'ReLi-Lex'
train = []
files = [os.path.join(base_path_reli, f) for f in os.listdir(base_path_reli)]

for file in files:
    t = 'pos' if '_Positivos' in file else 'neg'
    with open(file, 'r') as content_file:
        content = content_file.read()
        all = re.findall('\[.*?\]',content)
        for w in all:
            train.append((w[1:-1], t))
#Transformação da coleção ReLi em dicionário, substituindo o rótulo neg para Negativo e pos para Positivo
#Dessa forma, os rótulos serão igualados a outra coleção
train_dict = {}
for x, y in train:
    if y == "neg":
        train_dict[x] = "Negativo"
    elif y == "pos":
        train_dict[x] = "Positivo"
#Para efeitos de estudo, é sempre bom saber com o que estamos lidando
print(type(train_dict), len(train_dict))
#Transformando a coleção do ReLi em dataFrame
df_resenhas = pd.DataFrame(data=[[item[0], item[1]] for item in train_dict.items()], columns=['Text', 'Classificacao'])
df_resenhas.head()
#Leitura dos Tweets rotulados para análise de sentimentos
df_tweets = pd.read_csv('Tweets_Mg.csv',encoding='utf-8', usecols=["Text", "Classificacao"])
df_tweets.count()
#Verificando como estão os nossos dados
df_tweets.head()
#Realizando a contagem de cada classe, em outros trabalhos talvez seja interessante ter classes balanceadas.
qtd_neutros   = df_tweets[df_tweets.Classificacao == "Neutro"]
qtd_positivos = df_tweets[df_tweets.Classificacao == 'Positivo']
qtd_negativos = df_tweets[df_tweets.Classificacao == 'Negativo']
print(10*"=","Tweets Neutros",10*"=")
print(qtd_neutros.count())
print()

print(10*"=","Tweets Positivos",10*"=")
print(qtd_positivos.count())
print()

print(10*"=","Tweets Negativos",10*"=")
print(qtd_negativos.count())
#Concatenando os dois DataSets
frames = [df_resenhas, df_tweets]
train_set = pd.concat(frames)
#Descrever a coleção ajuda a compreender possíveis melhorias
train_set.describe()
#Como observado a duplicade de de registros, foi necessário a remoção de registros duplicados.
train_set.drop_duplicates(subset='Text', inplace=True)
train_set.describe()
#Por desencargo de conciência, realizei a remoção de registros nulos, mas não resultou em nada
train_set.dropna(inplace=True)
train_set.describe()
#Recontando os registros por classe, agora com a coleção concatenada e higienizada
qtd_neutros   = train_set[train_set.Classificacao == "Neutro"]
qtd_positivos = train_set[train_set.Classificacao == 'Positivo']
qtd_negativos = train_set[train_set.Classificacao == 'Negativo']
print(10*"=","Tweets Neutros",10*"=")
print(qtd_neutros.count())
print()

print(10*"=","Tweets Positivos",10*"=")
print(qtd_positivos.count())
print()

print(10*"=","Tweets Negativos",10*"=")
print(qtd_negativos.count())
# Remoção de Acentos e Caracteres Especiais - Padronização de Texto\n
dicionario_traducao = {'#': '', '{': '', '}': '', '>': '', '<': '', ',': '', ';': '',
                       '\"': '','@': '','&': '','®': '','¿': '','!': '','/': '','-':''}
train_set.replace(dicionario_traducao, regex=True, inplace=True)
train_set.describe()<jupyter_output><empty_output><jupyter_text>Naive Bayes<jupyter_code>from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV

#Criação do modelo
from sklearn.pipeline import make_pipeline
modelo = make_pipeline(TfidfVectorizer(analyzer = "word"),
                       MultinomialNB())

classifier = GridSearchCV(estimator=modelo, 
                          param_grid={
                              'multinomialnb__alpha':[0.1, 0.5, 1.0], 
                              'multinomialnb__fit_prior':[True,False], 
                              'tfidfvectorizer__ngram_range':[(1,1), (1,2), (2,2)]
                          },                           
                          n_jobs=4,
                          cv=10)

X = train_set['Text']
y = train_set['Classificacao']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)

classifier.fit(X_train, y_train)

predicoes = classifier.predict(X_test)

np.mean(predicoes == y_test)
from sklearn import metrics
print(metrics.classification_report(y_test, predicoes))
print()
print("Melhores Parâmetros:", classifier.best_params_)
#Persistindo o modelo para publicação futura em uma API
from joblib import dump, load
dump(classifier, 'SentimentAnalysisNB.pkl')
#Reabrindo o modelo e validando em algumas frases
modelo = load('SentimentAnalysisNB.pkl')

validacao = ["Existem muitas formas de se aprender, basta querer.",
          "Há dias que o trabalho é muito cansativo.", 
          "Hoje não estou muito bem",
          "Depois do culto você vai ver",
          "Vestidos de heróis dos pés a cabeça para levar um pouco de conhecimento para a humanidade",
          "A Net é muito boa, tem um excelente serviço de telefonia, sucesso de vendas"
         ]
resultado = modelo.predict(validacao)
predicted_proba = modelo.predict_proba(validacao)
for i in range(len(validacao)):
    print(str(i),"\t",resultado[i],"\t",predicted_proba[i])<jupyter_output>0 	 Negativo 	 [0.46097559 0.42890592 0.11011849]
1 	 Neutro 	 [0.19683529 0.6857719  0.1173928 ]
2 	 Neutro 	 [0.11851488 0.61981471 0.26167041]
3 	 Neutro 	 [0.23275545 0.74383508 0.02340947]
4 	 Negativo 	 [0.63853877 0.06794565 0.29351558]
5 	 Positivo 	 [0.22854476 0.35588412 0.41557112]<jupyter_text>Random Forest<jupyter_code>from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV

#Criação do modelo
from sklearn.pipeline import make_pipeline
modelo = make_pipeline(TfidfVectorizer(analyzer = "word"),
                       RandomForestClassifier(n_jobs=4, random_state=12))

classifier = GridSearchCV(estimator=modelo, 
                          param_grid={
                              'randomforestclassifier__criterion':['gini', 'entropy'], 
                              'randomforestclassifier__bootstrap':[True,False], 
                              'randomforestclassifier__n_estimators':range(1,11), 
                              'randomforestclassifier__max_depth':range(8,11),
                              'randomforestclassifier__class_weight':['balanced','balanced_subsample'],
                              'tfidfvectorizer__ngram_range':[(1,1), (1,2), (2,2)]
                          },
                          n_jobs=4,
                          cv=10)

X = train_set['Text']
y = train_set['Classificacao']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)

classifier.fit(X_train, y_train)

predicoes = classifier.predict(X_test)

np.mean(predicoes == y_test)
from sklearn import metrics
print(metrics.classification_report(y_test, predicoes))
print()
print("Melhores Parâmetros:", classifier.best_params_)
#Persistindo o modelo para publicação futura em uma API
from joblib import dump, load
dump(classifier, 'SentimentAnalysisRF.pkl')
#Reabrindo o modelo e validando em algumas frases
modelo = load('SentimentAnalysisRF.pkl')

validacao = ["Existem muitas formas de se aprender, basta querer.",
          "Há dias que o trabalho é muito cansativo.", 
          "Hoje não estou muito bem",
          "Depois do culto você vai ver",
          "Vestidos de heróis dos pés a cabeça para levar um pouco de conhecimento para a humanidade",
          "A Net é muito boa, tem um excelente serviço de telefonia, sucesso de vendas"
         ]
resultado = modelo.predict(validacao)
predicted_proba = modelo.predict_proba(validacao)
for i in range(len(validacao)):
    print(str(i),"\t",resultado[i],"\t",predicted_proba[i])<jupyter_output>0 	 Neutro 	 [0.32328157 0.3687935  0.30792493]
1 	 Neutro 	 [0.32328157 0.3687935  0.30792493]
2 	 Negativo 	 [0.37914925 0.33605563 0.28479512]
3 	 Neutro 	 [0.30666577 0.41290992 0.2804243 ]
4 	 Positivo 	 [0.27513599 0.33948954 0.38537447]
5 	 Neutro 	 [0.32328157 0.3687935  0.30792493]
{'fraction_non_alphanumeric': 0.11785503830288745, 'fraction_numerical': 0.047731290512669416, 'mean_word_length': 3.8188529244747302, 'pattern_counts': {'":': 2, '<': 12, '<?xml version=': 0, '>': 12, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '663213', 'license': 'MIT', 'n_tokens_mistral': 3321, 'n_tokens_neox': 3010, 'n_words': 685, 'path': 'Sentiment_Analysis.ipynb', 'repo_name': 'hroatti/Python', 'size': '8485'}