import pandas as pd
import re
from datetime import datetime
import string
from nltk.tokenize import word_tokenize
import nltk
import matplotlib.pyplot as plt
nltk.download('punkt')
nltk.download('stopwords')
stopwords = nltk.corpus.stopwords.words('portuguese')
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.preprocessing import FunctionTransformer
from sklearn.model_selection import GridSearchCV, StratifiedKFold
from sklearn.metrics import f1_score, matthews_corrcoef, accuracy_score
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.multiclass import OneVsRestClassifier
[nltk_data] Downloading package punkt to /root/nltk_data... [nltk_data] Package punkt is already up-to-date! [nltk_data] Downloading package stopwords to /root/nltk_data... [nltk_data] Package stopwords is already up-to-date!
dados = pd.read_csv('/content/drive/MyDrive/DATA/pedidos-recursos-features-process.csv')
def clear_values_regex(df):
df = df.replace(r'\r\n\r\n',' ', regex=True)
df = df.replace(r'\r\n',' ', regex=True)
df = df.replace(r'\r \r',' ', regex=True)
return df
dados = clear_values_regex(dados)
dados = dados[dados['atendimento_resposta'] != 'Não Classificado']
dados = dados.reset_index(drop=True)
colunas = ['conteudo_resposta','conteudo_recurso1','conteudo_recurso2','conteudo_recurso3','conteudo_resposta_recurso1','conteudo_resposta_recurso2','conteudo_resposta_recurso3']
for colu in colunas:
dados[colu] = dados[colu].fillna('')
Os pedidos podem ser considerando um conjunto de interações entre o solicitante e órgão em que deseja uma informação, anteriormente nossa modelagem considerava apenas o pedido e a primeira resposta do órgão, portanto, para esse estudo iremos considerar alguns cenários de modelagem que nos consiga mostra a importância desses recursos para a modelagem.
def limpando_texto(mensagem):
# Diminuindo os caracteres
mensagem = mensagem.lower()
# url
regex_url = r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))"
mensagem = re.sub(regex_url,'site',mensagem)
# data replace
mensagem = re.sub(r'\d{2}.\d{2}.\d{4}','data',mensagem)
# remove pontuação
table = str.maketrans('', '', string.punctuation)
stripped = [palavra.translate(table) for palavra in mensagem.split()]
mensagem = ' '.join(stripped).strip()
# remove stopword
mensagem_tokens = word_tokenize(mensagem)
mensagem = [word for word in mensagem_tokens if not word in stopwords]
mensagem = " ".join(mensagem)
return mensagem
dados['conteudo_pedido'] = dados['conteudo_pedido'].apply(limpando_texto)
dados['conteudo_resposta'] = dados['conteudo_resposta'].apply(limpando_texto)
Para essa modelagem iremos considerar três possiveis casos:
dados['conteudo_resposta_ultima'] = ''
for i in range(len(dados)):
if dados['conteudo_recurso3'][i] != '':
dados['conteudo_resposta_ultima'][i] = dados['conteudo_recurso3'][i]
else:
if dados['conteudo_recurso2'][i] != '':
dados['conteudo_resposta_ultima'][i] = dados['conteudo_recurso2'][i]
else:
if dados['conteudo_recurso1'][i] != '':
dados['conteudo_resposta_ultima'][i] = dados['conteudo_recurso1'][i]
else:
dados['conteudo_resposta_ultima'][i] = dados['conteudo_resposta'][i]
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:12: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy if sys.path[0] == '': /usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:10: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy # Remove the CWD from sys.path while we load stuff. /usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:7: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy import sys /usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:4: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy after removing the cwd from sys.path.
dados['join_pedido'] = dados['conteudo_pedido'] + ' '+ dados['conteudo_recurso1']+ ' '+ dados['conteudo_recurso2']+ ' '+ dados['conteudo_recurso3']
dados['join_resposta'] = dados['conteudo_resposta'] + ' '+ dados['conteudo_resposta_recurso1']+ ' '+ dados['conteudo_resposta_recurso2']+ ' '+ dados['conteudo_resposta_recurso3']
Para essa etapa matemos o processo de treinamento do modelo considerando as abordagens:
Considerando os cenários diferentes a modelagem varia por conta dos paramentos de treinamento que será recebido.
def get_text_data(x):
return [record[0] for record in x]
def get_text_data_2(x):
return [record[1] for record in x]
transformer_text = FunctionTransformer(get_text_data)
transformer_text_2 = FunctionTransformer(get_text_data_2)
def train_models(X_train,y_train):
pipeline = Pipeline([
('features', FeatureUnion([
('text_features', Pipeline([
('selector', transformer_text),
('vec', TfidfVectorizer(analyzer='word'))
])),
('text_features2', Pipeline([
('selector', transformer_text_2),
('vec', TfidfVectorizer(analyzer='word'))
]))
])),
('svc', SVC(C = 100 , gamma=0.001 , kernel='rbf'))
])
pipeline.fit(X_train,y_train)
return pipeline
def train_model_unique(X_train,y_train):
pipeline = Pipeline([
('features', FeatureUnion([
('text_features', Pipeline([
('selector', transformer_text),
('vec', TfidfVectorizer(analyzer='word'))
]))
])),
('svc', SVC(C = 100 , gamma=0.001 , kernel='rbf'))
])
pipeline.fit(X_train,y_train)
return pipeline
def label_encode(x):
if x == 'Atendido':
return 1
else:
return 0
def split_data(df):
labels = df['atendimento_resposta'].apply(label_encode)
df = df.drop(columns=['atendimento_resposta'])
X_train, X_test, y_train , y_test = train_test_split(df, labels, test_size=0.2, random_state=5)
X_train = X_train.to_numpy()
X_test = X_test.to_numpy()
return X_train, X_test, y_train , y_test
def test(df,cenario):
X_train, X_test, y_train , y_test = split_data(df)
if cenario == 1 :
model = train_model_unique(X_train,y_train)
else:
model = train_models(X_train,y_train)
predicted_text = model.predict(X_test)
accuracy = accuracy_score(y_test, predicted_text)
f1 = f1_score(y_test, predicted_text)
mcc = matthews_corrcoef(y_test, predicted_text)
result = pd.DataFrame(zip([float('{:04.2f}'.format(accuracy*100))],[float('{:04.2f}'.format(f1*100))],[mcc]),columns=['Acurácia','F1','MCC'])
return result
def cenarios_teste(data,cenario):
key = ['Atendido vs Não Atendido','Atendido vs (Não e Parcialmente Atendido)']
cenarios = {
'Atendido vs Não Atendido' : ['Atendido','Não Atendido'],
'Atendido vs (Não e Parcialmente Atendido)' : ['Atendido','Não Atendido','Parcialmente Atendido']
}
result_final = pd.DataFrame(columns=['cenario','Acurácia','F1','MCC'])
for k in key:
local = data[data['atendimento_resposta'].isin(cenarios[k])]
result_local = test(local,cenario)
result_local['cenario'] = k
result_final = pd.concat([result_final,result_local])
return result_final
def selecionado_data(data):
key = ['Apenas a resposta do órgão','Pedido e última resposta','Junção de todo os rescursos']
cenarios = {
'Apenas a resposta do órgão' : ['conteudo_resposta','atendimento_resposta'],
'Pedido e última resposta' : ['conteudo_pedido','conteudo_resposta_ultima','atendimento_resposta'],
'Junção de todo os rescursos': ['join_pedido','join_resposta','atendimento_resposta']
}
result_final = pd.DataFrame(columns=['dados','cenario','Acurácia','F1','MCC'])
for k in key:
cenario = 0
local = data[cenarios[k]]
if k == 'Apenas a resposta do órgão': cenario = 1
result_local = cenarios_teste(local,cenario)
result_local['dados'] = k
result_final = pd.concat([result_final,result_local])
return result_final
resultado = selecionado_data(dados)
resultado
dados | cenario | Acurácia | F1 | MCC | |
---|---|---|---|---|---|
0 | Apenas a resposta do órgão | Atendido vs Não Atendido | 79.77 | 85.98 | 0.542140 |
0 | Apenas a resposta do órgão | Atendido vs (Não e Parcialmente Atendido) | 71.79 | 77.55 | 0.436693 |
0 | Pedido e última resposta | Atendido vs Não Atendido | 81.20 | 86.64 | 0.573614 |
0 | Pedido e última resposta | Atendido vs (Não e Parcialmente Atendido) | 73.68 | 78.28 | 0.469640 |
0 | Junção de todo os rescursos | Atendido vs Não Atendido | 81.61 | 86.91 | 0.583408 |
0 | Junção de todo os rescursos | Atendido vs (Não e Parcialmente Atendido) | 73.74 | 78.38 | 0.471310 |
Observamos um comportamento favorável tanto para resposta de órgão quando considerando todos os recursos juntos.