<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 <h1 align="center"> Introdução ao Processamento de Linguagem Natural (PLN) Usando Python </h1>
<h3 align="center"> Professor Fernando Vieira da Silva MSc.</h3>
<h2>Problema de Classificação</h2>
<p>Neste tutorial vamos trabalhar com um exemplo prático de problema de classificação de texto. O objetivo é identificar uma sentença como escrita "formal" ou "informal".</p>
<b>1. Obtendo o corpus</b>
<p>Para simplificar o problema, vamos continuar utilizando o corpus Gutenberg como textos formais e vamos usar mensagens de chat do corpus <b>nps_chat</b> como textos informais.</p>
<p>Antes de tudo, vamos baixar o corpus nps_chat
Step1:  <p>Agora vamos ler os dois corpus e armazenar as sentenças em uma mesma ndarray. Perceba que também teremos uma ndarray para indicar se o texto é formal ou não. Começamos armazenando o corpus em lists. Vamos usar apenas 500 elementos de cada, para fins didáticos.</p>
Step2:  <p>Em seguida, transformamos essas listas em ndarrays, para usarmos nas etapas de pré-processamento que já conhecemos.</p>
Step3:  <b>2. Dividindo em datasets de treino e teste</b>
<p>Para que a pesquisa seja confiável, precisamos avaliar os resultados em um dataset de teste. Por isso, vamos dividir os dados aleatoriamente, deixando 80% para treino e o demais para testar os resultados em breve.</p>
Step4:  <b>3. Treinando o classificador</b>
<p>Para tokenização, vamos usar a mesma função do tutorial anterior
Step5:  <p>Mas agora vamos criar um <b>pipeline</b> contendo o vetorizador TF-IDF, o SVD para redução de atributos e um algoritmo de classificação. Mas antes, vamos encapsular nosso algoritmo para escolher o número de dimensões para o SVD em uma classe que pode ser utilizada com o pipeline
Step6:  <p>Finalmente podemos criar nosso pipeline
Step7:  <p>Estamos quase lá... Agora vamos criar um objeto <b>RandomizedSearchCV</b> que fará a seleção de hiper-parâmetros do nosso classificador (aka. parâmetros que não são aprendidos durante o treinamento). Essa etapa é importante para obtermos a melhor configuração do algoritmo de classificação. Para economizar tempo de treinamento, vamos usar um algoritmo simples o <i>K nearest neighbors (KNN)</i>.
Step8:  <p>E agora vamos treinar nosso algoritmo, usando o pipeline com seleção de atributos
Step9:  <b>4. Testando o classificador</b>
<p>Agora vamos usar o classificador com o nosso dataset de testes, e observar os resultados
Step10:  <b>5. Serializando o modelo</b><br>
Step11:  <b>6. Abrindo e usando um modelo salvo </b><br>
<ASSISTANT_TASK:>
Python Code:
import nltk
nltk.download('nps_chat')
from nltk.corpus import nps_chat
print(nps_chat.fileids())
Explanation: <h1 align="center"> Introdução ao Processamento de Linguagem Natural (PLN) Usando Python </h1>
<h3 align="center"> Professor Fernando Vieira da Silva MSc.</h3>
<h2>Problema de Classificação</h2>
<p>Neste tutorial vamos trabalhar com um exemplo prático de problema de classificação de texto. O objetivo é identificar uma sentença como escrita "formal" ou "informal".</p>
<b>1. Obtendo o corpus</b>
<p>Para simplificar o problema, vamos continuar utilizando o corpus Gutenberg como textos formais e vamos usar mensagens de chat do corpus <b>nps_chat</b> como textos informais.</p>
<p>Antes de tudo, vamos baixar o corpus nps_chat:</p>
End of explanation
import nltk
x_data_nps = []
for fileid in nltk.corpus.nps_chat.fileids():
    x_data_nps.extend([post.text for post in nps_chat.xml_posts(fileid)])
y_data_nps = [0] * len(x_data_nps)
x_data_gut = []
for fileid in nltk.corpus.gutenberg.fileids():
    x_data_gut.extend([' '.join(sent) for sent in nltk.corpus.gutenberg.sents(fileid)])
    
y_data_gut = [1] * len(x_data_gut)
x_data_full = x_data_nps[:500] + x_data_gut[:500]
print(len(x_data_full))
y_data_full = y_data_nps[:500] + y_data_gut[:500]
print(len(y_data_full))
Explanation: <p>Agora vamos ler os dois corpus e armazenar as sentenças em uma mesma ndarray. Perceba que também teremos uma ndarray para indicar se o texto é formal ou não. Começamos armazenando o corpus em lists. Vamos usar apenas 500 elementos de cada, para fins didáticos.</p>
End of explanation
import numpy as np
x_data = np.array(x_data_full, dtype=object)
#x_data = np.array(x_data_full)
print(x_data.shape)
y_data = np.array(y_data_full)
print(y_data.shape)
Explanation: <p>Em seguida, transformamos essas listas em ndarrays, para usarmos nas etapas de pré-processamento que já conhecemos.</p>
End of explanation
train_indexes = np.random.rand(len(x_data)) < 0.80
print(len(train_indexes))
print(train_indexes[:10])
x_data_train = x_data[train_indexes]
y_data_train = y_data[train_indexes]
print(len(x_data_train))
print(len(y_data_train))
x_data_test = x_data[~train_indexes]
y_data_test = y_data[~train_indexes]
print(len(x_data_test))
print(len(y_data_test))
Explanation: <b>2. Dividindo em datasets de treino e teste</b>
<p>Para que a pesquisa seja confiável, precisamos avaliar os resultados em um dataset de teste. Por isso, vamos dividir os dados aleatoriamente, deixando 80% para treino e o demais para testar os resultados em breve.</p>
End of explanation
from nltk import pos_tag
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
from nltk.tokenize import word_tokenize
import string
from nltk.corpus import wordnet
stopwords_list = stopwords.words('english')
lemmatizer = WordNetLemmatizer()
def my_tokenizer(doc):
    words = word_tokenize(doc)
    
    pos_tags = pos_tag(words)
    
    non_stopwords = [w for w in pos_tags if not w[0].lower() in stopwords_list]
    
    non_punctuation = [w for w in non_stopwords if not w[0] in string.punctuation]
    
    lemmas = []
    for w in non_punctuation:
        if w[1].startswith('J'):
            pos = wordnet.ADJ
        elif w[1].startswith('V'):
            pos = wordnet.VERB
        elif w[1].startswith('N'):
            pos = wordnet.NOUN
        elif w[1].startswith('R'):
            pos = wordnet.ADV
        else:
            pos = wordnet.NOUN
        
        lemmas.append(lemmatizer.lemmatize(w[0], pos))
    return lemmas
    
    
Explanation: <b>3. Treinando o classificador</b>
<p>Para tokenização, vamos usar a mesma função do tutorial anterior:</p>
End of explanation
from sklearn.decomposition import TruncatedSVD
class SVDDimSelect(object):
    def fit(self, X, y=None):               
        self.svd_transformer = TruncatedSVD(n_components=X.shape[1]/2)
        self.svd_transformer.fit(X)
        
        cummulative_variance = 0.0
        k = 0
        for var in sorted(self.svd_transformer.explained_variance_ratio_)[::-1]:
            cummulative_variance += var
            if cummulative_variance >= 0.5:
                break
            else:
                k += 1
                
        self.svd_transformer = TruncatedSVD(n_components=k)
        return self.svd_transformer.fit(X)
    
    def transform(self, X, Y=None):
        return self.svd_transformer.transform(X)
        
    def get_params(self, deep=True):
        return {}
Explanation: <p>Mas agora vamos criar um <b>pipeline</b> contendo o vetorizador TF-IDF, o SVD para redução de atributos e um algoritmo de classificação. Mas antes, vamos encapsular nosso algoritmo para escolher o número de dimensões para o SVD em uma classe que pode ser utilizada com o pipeline:</p>
End of explanation
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.pipeline import Pipeline
from sklearn import neighbors
clf = neighbors.KNeighborsClassifier(n_neighbors=10, weights='uniform')
my_pipeline = Pipeline([('tfidf', TfidfVectorizer(tokenizer=my_tokenizer)),\
                       ('svd', SVDDimSelect()), \
                       ('clf', clf)])
Explanation: <p>Finalmente podemos criar nosso pipeline:</p>
End of explanation
from sklearn.grid_search import RandomizedSearchCV
import scipy
par = {'clf__n_neighbors': range(1, 60), 'clf__weights': ['uniform', 'distance']}
hyperpar_selector = RandomizedSearchCV(my_pipeline, par, cv=3, scoring='accuracy', n_jobs=2, n_iter=20)
Explanation: <p>Estamos quase lá... Agora vamos criar um objeto <b>RandomizedSearchCV</b> que fará a seleção de hiper-parâmetros do nosso classificador (aka. parâmetros que não são aprendidos durante o treinamento). Essa etapa é importante para obtermos a melhor configuração do algoritmo de classificação. Para economizar tempo de treinamento, vamos usar um algoritmo simples o <i>K nearest neighbors (KNN)</i>.
End of explanation
#print(hyperpar_selector)
hyperpar_selector.fit(X=x_data_train, y=y_data_train)
print("Best score: %0.3f" % hyperpar_selector.best_score_)
print("Best parameters set:")
best_parameters = hyperpar_selector.best_estimator_.get_params()
for param_name in sorted(par.keys()):
    print("\t%s: %r" % (param_name, best_parameters[param_name]))
Explanation: <p>E agora vamos treinar nosso algoritmo, usando o pipeline com seleção de atributos:</p>
End of explanation
from sklearn.metrics import *
y_pred = hyperpar_selector.predict(x_data_test)
print(accuracy_score(y_data_test, y_pred))
Explanation: <b>4. Testando o classificador</b>
<p>Agora vamos usar o classificador com o nosso dataset de testes, e observar os resultados:</p>
End of explanation
import pickle
string_obj = pickle.dumps(hyperpar_selector)
model_file = open('model.pkl', 'wb')
model_file.write(string_obj)
model_file.close()
Explanation: <b>5. Serializando o modelo</b><br>
End of explanation
model_file = open('model.pkl', 'rb')
model_content = model_file.read()
obj_classifier = pickle.loads(model_content)
model_file.close()
res = obj_classifier.predict(["what's up bro?"])
print(res)
res = obj_classifier.predict(x_data_test)
print(accuracy_score(y_data_test, res))
res = obj_classifier.predict(x_data_test)
print(res)
formal = [x_data_test[i] for i in range(len(res)) if res[i] == 1]
for txt in formal:
    print("%s\n" % txt)
informal = [x_data_test[i] for i in range(len(res)) if res[i] == 0]
for txt in informal:
    print("%s\n" % txt)
res2 = obj_classifier.predict(["Emma spared no exertions to maintain this happier flow of ideas , and hoped , by the help of backgammon , to get her father tolerably through the evening , and be attacked by no regrets but her own"])
print(res2)
Explanation: <b>6. Abrindo e usando um modelo salvo </b><br>
End of explanation
<END_TASK>