<jupyter_start><jupyter_text>NLP 1. Carga de datosLos datos se encuentran en formato JSON.<jupyter_code># Cargamos las librerías

import itertools

import numpy as np
import pandas as pd

import matplotlib.pyplot as plt
import seaborn as sns
sns.set()

import nltk

nltk.download('punkt')
nltk.download('stopwords') # Cargamos las palabras que vamos a utilizar para hacer stopwords
# Cargamos el Dataset
dataset = pd.read_json('Sarcasm_Headlines_Dataset_v2.json', lines= True)
dataset.head()<jupyter_output><empty_output><jupyter_text>¿Cuántas instancias tiene el dataset? ¿Cuáles son sus columnas? ¿Cuántos titulares hay de cada tipo?<jupyter_code>dataset.shape<jupyter_output><empty_output><jupyter_text>* El Dataset tiene 28.619 instancias.* Sus columnas son 3.* Hay 2 titulares de cada tipo (sarcasmo o no).<jupyter_code>sns.countplot(dataset.is_sarcastic)
plt.show()<jupyter_output>C:\Users\Ale\anaconda3\envs\ds\lib\site-packages\seaborn\_decorators.py:36: FutureWarning: Pass the following variable as a keyword arg: x. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation.
  warnings.warn(<jupyter_text>* El 0 corresponde a No sarcástico y el 1 a sarcástico.* Hay más información correspondiente a titulares no sarcásticos.  2. Breve exploración del datasetSe elige una instancia del dataset al azar y se selecciona el *headline*.<jupyter_code>index_random = np.random.randint(0,high = dataset.shape[0])
titular = dataset.iloc[index_random].headline
print(index_random, titular)<jupyter_output>28079 fox host links immigration reform to upcoming ferguson grand jury decision<jupyter_text>Se comprueba si el headline es sarcástico o no, imprimiendo en la celda de abajo el valor correspondiente del dataset. Si es 0 no será sarcástico, si es 1 será sarcástico.<jupyter_code>print(index_random, dataset.iloc[index_random].is_sarcastic)<jupyter_output>28079 0<jupyter_text>En éste caso, el headline resulta ser No Sarcástico.  3. NLTKSi es difícil para algunos humanos detectar el sarcasmo, probablemente también lo sea para una computadora. De todas formas, se puede hacer el intento. Para ello, es necesario extraer características de cada texto que sirvan para ir apuntando al objetivo.   Tokenización* Tokenizar, significa separar cada unidad semántica, para poder analizarla por separado.* La mayoría de las veces, la unidad semántica es exactamente lo mismo que la unidad léxica (que es una manera elegante de decir `palabra`); entonces tokenizar se parece mucho a `separar un texto en palabras`.* La tokenización puede realizarse:    * Por `Palabra` (word_tokenize);    * Por `Setencia` o por oración (sent_tokenize).Se elige un titular y se prueban distintas herramientas: 1. `sent_tokenize`<jupyter_code>titular_st = nltk.tokenize.sent_tokenize(titular)
titular_st<jupyter_output><empty_output><jupyter_text>* Como el titular es una sola oración, la tokenización no generó cambios en éste caso. 2. `word_tokenize`<jupyter_code>titular_wt = nltk.tokenize.word_tokenize(titular)
titular_wt<jupyter_output><empty_output><jupyter_text>* El resultado, es una lista, donde cada una de las palabras de la oración, van a aparecer como un elemento independiente de la lista.  Normalización* En lenguaje natural, no todas las partes transmiten la misma cantidad de información, algunas son más informativas que otras, es decir, tienen mayor  **carga semántica.*** La __Normalización__ del texto, es el proceso de transformar el texto en una única forma canónica que podría no haber tenido antes. La normalización del texto antes de almacenarlo o procesarlo, garantiza que la entrada sea coherente antes de realizar operaciones en él. Stopwords* Son palabras que No nos proporcionan información: a, ante, cabe, con, contra... etc.* En NLP, muchas veces vamos a querer deshacernos de los tokens de menor carga semántica para trabajar solamente con aquellos de mayor carga. Nos referimos a los tokens descartados como "stop words". Para no tener que hacer el trabajo de identificar y filtrar a mano cada una de las stop words, nltk nos ofrece un catálogo predefinido de  *stop words*  que podemos modificar a gusto según lo necesitemos. Se importan los `stopwords` del inglés y se imprimen.<jupyter_code># Cargamos el 'corpus', el universo de palabras disponibles. Del mismo, sólo seleccionamos las stopwords, para el idioma inglés
stopwords = nltk.corpus.stopwords.words('english')

# Stopwords que no se encuentran en la lista de palabras anterior
stopwords = [word for word in stopwords if 'not' not in word]
stopwords<jupyter_output><empty_output><jupyter_text>Se elimina del titular elegido los stopwords.<jupyter_code>titular_wt_sin_sw = [word for word in titular_wt if word not in stopwords]
titular_wt_sin_sw<jupyter_output><empty_output><jupyter_text>¿Cuál o cuáles palabras se fueron?* To (puede cambiar de acuerdo a la oración elegida).  Frecuencia de palabrasDado el titular ya tokenizado por palabras y sin stopwords, se utiliza `nltk` para extrar la frecuencia con que aparece cada palabras.<jupyter_code>freq = nltk.FreqDist(titular_wt_sin_sw)
freq<jupyter_output><empty_output><jupyter_text>* En éste caso, todas las palabras, se repiten 1 sola vez.  Dataset CompletoAntes de pasar a extraer features de cada instancia del Dataset, podemos hacer un pequeño análisis del dataset en su conjunto. Por ejemplo, una opción es agrupar todos los titulares por tipo y extraer de cada clase las palabras más frecuentes. Para ello:1. Se agrupan los titulares por tipo y se crea un dataframe para cada uno.2. Se crea una lista vacia y se agregan en esa lista, todos los titulares (por tipo/dataframe creado) ya tokenizados (utilizando `RegexpTokenizer`) y filtrando por `stopwords`.3. Se utiliza `FreqDist` (distribución de frecuencia) en esa lista llenada; y se lleva lo que devuelve `FreqDist` a un Dataframe. Ordenar por frecuencia en que aparece cada palabra.4. Se realiza un `barplot` o similar para visualizar.5. Se crea una lista vacía y se agregan a mano. Se agrega en el código que realizaron una línea (similar a la que se usa con `stopwords`) para que también filtre por esas palabras.6. Se vuelve a visualizar. No-Sarcasmo<jupyter_code># La lista 'filtrar', va a contener la palabra 'u' y 'new'
filtrar = []
if True:
    filtrar.append("u") # Textos anteriores
    filtrar.append("new") # Textos nuevos
# Para todo el Dataset, vamos a filtrar por aquellos que sean Sarcásticos
dataset_no_sarcasmo = dataset[dataset.is_sarcastic==0]
display(dataset_no_sarcasmo.head())
print(dataset_no_sarcasmo.shape)
# Para todas las filas (titulares) hacemos lo siguiente:
    # Obtenemos el headline del titular
    # Tokenizamos el titular, pero antes quitamos las expresiones Regulares (que sean letras que van de la A a la Z)
    # Eliminamos las stopwords
    # Las que no están en la lista de filtrado (las que están son u y new)
    # Se agregan todos los titulares no_sarcasmo, luego de todo el preproceso

todos_titulares_no_sarcasmo = []
for i in range(dataset_no_sarcasmo.shape[0]):
    titular = dataset_no_sarcasmo.iloc[i].headline
    titular = nltk.tokenize.RegexpTokenizer("[\w]+").tokenize(titular)
    titular = [word for word in titular if word not in stopwords]
    titular = [word for word in titular if word not in filtrar]

    todos_titulares_no_sarcasmo.append(titular)
# print (todos_titulares_no_sarcasmo)
# Es una lista con listas, como palabras tiene cada una de las frases en el Dataset
todos_titulares_no_sarcasmo = list(itertools.chain(*todos_titulares_no_sarcasmo))
todos_titulares_no_sarcasmo[0:10] # Primeras 10 palabras, correspondientes al primer elemento de no sarcasmo
# Cantidad veces aparece cada palabra
freq_no_sarcasmo = nltk.FreqDist(todos_titulares_no_sarcasmo)
freq_no_sarcasmo
# Armamos un Dataset, con la frecuencia con la que aparece cada palabra
df_no_sarcasmo = pd.DataFrame(list(freq_no_sarcasmo.items()), columns = ["Word","Frequency"])
df_no_sarcasmo.head()
# Lo ordenamos de mayor a menor
df_no_sarcasmo.sort_values('Frequency',ascending=False, inplace = True)
df_no_sarcasmo.head()
# Eliminamos los índices, y luego los regeneramos pero en Órden y desde 0
df_no_sarcasmo.reset_index(drop = True, inplace=True)
df_no_sarcasmo.head()<jupyter_output><empty_output><jupyter_text>* De ésta manera, ahora podemos graficar las palabras por su óden de frecuencia.<jupyter_code># Graficamos las primeras 30 palabras
plt.figure(figsize = (15,8))
plot = sns.barplot(x  = df_no_sarcasmo.iloc[:30].Word, y = df_no_sarcasmo.iloc[:30].Frequency)
for item in plot.get_xticklabels():
    item.set_rotation(90)
plt.show()<jupyter_output><empty_output><jupyter_text>En los headlines **no sarcásticos**, la palabra que más se repite es "trump".  Sarcasmo<jupyter_code>dataset_sarcasmo = dataset[dataset.is_sarcastic==1]
dataset_sarcasmo.head()
todos_titulares_sarcasmo = []
for i in range(dataset_sarcasmo.shape[0]):
    titular = dataset_sarcasmo.iloc[i].headline
    titular = nltk.tokenize.RegexpTokenizer("[\w]+").tokenize(titular)
    titular = [word for word in titular if word not in stopwords]
    titular = [word for word in titular if word not in filtrar]
    todos_titulares_sarcasmo.append(titular)
todos_titulares_sarcasmo = list(itertools.chain(*todos_titulares_sarcasmo))
todos_titulares_sarcasmo[0:10]
freq_sarcasmo = nltk.FreqDist(todos_titulares_sarcasmo)
freq_sarcasmo
df_sarcasmo = pd.DataFrame(list(freq_sarcasmo.items()), columns = ["Word","Frequency"])
df_sarcasmo.head()
df_sarcasmo.sort_values('Frequency',ascending=False, inplace = True)
df_sarcasmo.head()
df_sarcasmo.reset_index(drop = True, inplace=True)
df_sarcasmo.head()
plt.figure(figsize = (15,8))
plot = sns.barplot(x  = df_sarcasmo.iloc[:30].Word, y = df_sarcasmo.iloc[:30].Frequency)
for item in plot.get_xticklabels():
    item.set_rotation(90)
plt.show()<jupyter_output><empty_output><jupyter_text>En los headlines **sarcásticos**, la palabra que más se repite es "man".  4. StemmingPor razones gramaticales muchas palabras pueden escribirse de manera distinta (debido a conjugación, género, número) pero tener el mismo significado para el texto. Por ejemplo si decimos "jugar", "jugando" o "juega", debido a como estan conjugadas, la computadora puede tratarlas como palabras distintas. Pero, en términos de significado, todas estan relacionadas al verbo Jugar. Muchas veces nos va a convenir unir todas estos términos en uno solo.Una de las manera de hacer esto es por "STEMMING". El Stemming es un proceso eurístico que recorta la terminación de las palabras, agrupándolas por su raiz (no se convierte necesariamente en una palabra real).* Ventaja: Es un proceso bastante rápido a la hora de encontrar la raíz de las palabras.* Desventaja: tiene muchos errores en la determinación de las nuevas palabras.1. Se importa nuevamente el dataset completo<jupyter_code>dataset = pd.read_json('Sarcasm_Headlines_Dataset_v2.json', lines= True)
dataset.head()<jupyter_output><empty_output><jupyter_text>2. Se toma del `dataset` solo las columnas de interés<jupyter_code># Se concatenan los headlines que corresponden a sarcasmo y no sarcasmo para que formen parte del mismo dataframe
# Luego, se elimina la columna que no nos sirve que es el link del artículo
# Se reordena
dataset=pd.concat([dataset.headline,dataset.is_sarcastic],axis=1)
dataset.dropna(axis=0,inplace=True)  # Si hay alguna nan, tiramos esa instancia
dataset.head()<jupyter_output><empty_output><jupyter_text>3. Antes de realizar el proceso de Stemming, se normaliza el texto. Se agrega en este caso el uso de la libreria `re`, que permite sacar del texto todos los caracteres que no sean palabras. Notar que hay veces que no conviene quitar estos caracteres ya que, por ejemplo, no se podrá distiguir preguntas (?) o exclamaciones (!).<jupyter_code># Se importa la libreria que nos permite reemplzar caracteres
import re

# Se importa la función que nos permite Stemmizar de nltk y se define el stemmer
from nltk.stem import PorterStemmer
stemmer = PorterStemmer() # Forma eurística (va aprendiendo a partir de lo ocurrido) para hacer stemización

# Se traen nuevamente las stopwords
stopwords = nltk.corpus.stopwords.words('english')
#stopword.remove('no')
#stopword.remove('not')
# Se recorren todos los títulos y se va aplicando la Normalizacion y luego el Stemming a cada una de las palabras
# Se confecciona una lista donde van a estar todos los titulares, luego de haber sido preprocesados
titular_list=[]
for titular in dataset.headline: # Ya es un Dataframe, por eso headline
    # Vamos a reemplzar los caracteres que no sean letras por espacios
    titular=re.sub("[^a-zA-Z]"," ",str(titular))
    # Pasamos todo a minúsculas
    titular=titular.lower()
    # Tokenizamos para separar las palabras del titular
    titular=nltk.word_tokenize(titular)
    # Eliminamos las palabras de menos de 3 letras
    titular = [palabra for palabra in titular if len(palabra)>3]
    # Sacamos las Stopwords
    titular = [palabra for palabra in titular if not palabra in stopwords]
    
    ## Hasta acá Normalizamos, ahora a Stemmizar cada una de esas palabras
    
    # Aplicamos la funcion para buscar la raiz de las palabras
    titular=[stemmer.stem(palabra) for palabra in titular]
    # Por ultimo volvemos a unir el titular, separando con un espacio a cada una de ellas
    titular=" ".join(titular)
    
    # Vamos armando una lista con todos los titulares
    titular_list.append(titular)
    #dataset["titular_normalizado"] = titular_list<jupyter_output><empty_output><jupyter_text>4. Se agrega al Dataset una columna llamado `titular_stem` que contenga los titulares stemmizados<jupyter_code>dataset["titular_stem"] = titular_list
dataset.tail()<jupyter_output><empty_output><jupyter_text>5. Se arma un nuevo dataset llamado `dataset_stem` que contenga solo las columnas `titular_stem` e `is_sarcastic`<jupyter_code># Se eliminan los titulares vacíos
# Se concatenan todos los titulares stemizados
dataset_stem=pd.concat([dataset.titular_stem,dataset.is_sarcastic],axis=1)
dataset_stem.dropna(axis=0,inplace=True)  # Por si quedaron titulares vacios
dataset_stem.head()<jupyter_output><empty_output><jupyter_text>5. LemmatizationOtra manera de llevar distintas palabras a un raíz común en la que comparten un significado es mediante el procezo de 'Lemmatizar' el texto. Es similar al 'Stemming' pero un poco más educado, ya que intenta realizar el proceso teniendo en cuenta cuál es el rol que la palabra cumple en el texto. Esto quiere decir que su accionar será distinto si la palabra a lemmantizar está actuando como verbo, sustantivo, etc. Para usar las funciones que ofrece `nltk` para lemmantizar, es necesario descargar la libreria `Wordnet` que se encuentra en la solapa 'corpora' y las librerias 'maxent_treebank_pos_' y 'averaged_perceptron_tagger' que se encuentra en la solapa 'Models'. Para ello, se ejecuta la siguiente celda:<jupyter_code>nltk.download('wordnet')
nltk.download('averaged_perceptron_tagger')
# Importamos esta libreria que nos permite reemplzar caracteres
import re

# Importamos el lemmatizar de NLTK, y creamos el objeto
from nltk.stem import WordNetLemmatizer
wordnet_lemmatizer = WordNetLemmatizer()<jupyter_output><empty_output><jupyter_text>Vemos cómo actúa el lemmatizer sobre una frase de ejemplo.<jupyter_code># Oracion que usaremos como ejemplo
frase = "He was running and eating at same time. He has bad habit of swimming after playing long hours in the Sun."

# Hay que regularizar el texto. Dejar solo letra, pasar a minúsculas y tokenizar:

# Sacamos todos los caracteres que no sean letras (los puntos, por ej., van a desaparecer)
frase = re.sub("[^a-zA-Z]"," ",str(frase))
# Pasamos a minúsculas
frase = frase.lower()
# Tokenizamos
frase_tokens = nltk.word_tokenize(frase)

# Veamos como cambians las palabras al lemmatizar
print("{0:20}{1:20}".format("Word","Lemma"))
for palabra in frase_tokens:
    print ("{0:20}{1:20}".format(palabra,wordnet_lemmatizer.lemmatize(palabra)))<jupyter_output>Word                Lemma               
he                  he                  
was                 wa                  
running             running             
and                 and                 
eating              eating              
at                  at                  
same                same                
time                time                
he                  he                  
has                 ha                  
bad                 bad                 
habit               habit               
of                  of                  
swimming            swimming            
after               after               
playing             playing             
long                long                
hours               hour                
in                  in                  
the                 the                 
sun                 sun<jupyter_text>No cambiaron casi nada (solo se fueron las "s" del final). El problema es que es necesario darle información extra al Lemmatizer, decirle qué rol está cumpliendo la palabra en la oración. Ésto se hace pasandole un argumento extra a la función llamado POS (Part Of Speech).Hay distintos metodos que intentan averiguar el rol que cumple una palabra en una oración. En éste caso se utilizará uno que viene incorporado en NLTK llamado pos_tag.<jupyter_code># Se aplica una etiqueta, donde expone a qué tipo de palabra es cada una
print(nltk.pos_tag(frase_tokens))<jupyter_output>[('he', 'PRP'), ('was', 'VBD'), ('running', 'VBG'), ('and', 'CC'), ('eating', 'VBG'), ('at', 'IN'), ('same', 'JJ'), ('time', 'NN'), ('he', 'PRP'), ('has', 'VBZ'), ('bad', 'JJ'), ('habit', 'NN'), ('of', 'IN'), ('swimming', 'NN'), ('after', 'IN'), ('playing', 'VBG'), ('long', 'JJ'), ('hours', 'NNS'), ('in', 'IN'), ('the', 'DT'), ('sun', 'NN')]<jupyter_text>Las etiquetas refieren al tipo de palabra. Se define una función para traducir estas etiquetas a los valores de POS que entiende `wordnet_lemmatizer`.<jupyter_code>from nltk.corpus import wordnet

# Transformamos las palabras lematizadas, a través de una f(x), que nos permita determinar qué es c/u de ellas en cada posición
def get_wordnet_pos(word):
    """Map POS tag to first character lemmatize() accepts"""
    tag = nltk.pos_tag([word])[0][1][0].upper()
    tag_dict = {"J": wordnet.ADJ,
                "N": wordnet.NOUN,
                "V": wordnet.VERB,
                "R": wordnet.ADV}

    return tag_dict.get(tag, wordnet.NOUN)<jupyter_output><empty_output><jupyter_text>Ahora, nuestro ejemplo para UNA SOLA FRASE.<jupyter_code># Se toma cada palabra y se almacena en w
# Se pasan por la función get_wordnet_pos, que nos dice qué tipo de palabra es, en c/u de las posiciones
# Volvemos a llamar al lematizador, pero también le pasamos la palabra, sino qué tipo es
# Luego volvemos a tokenizar
frase_lemma = [wordnet_lemmatizer.lemmatize(w, get_wordnet_pos(w)) for w in nltk.word_tokenize(frase)]
tipo_palabra = [get_wordnet_pos(w) for w in nltk.word_tokenize(frase)]

# Veamos como cambiaron las palabras
print("{0:20}{1:20}{2:20}".format("Palabra:","Tipo:","Lemma:"))
for i in range(len(frase_tokens)):
    print ("{0:20}{1:20}{2:20}".format(frase_tokens[i],tipo_palabra[i],frase_lemma[i]))<jupyter_output>Palabra:            Tipo:               Lemma:              
he                  n                   he                  
was                 v                   be                  
running             v                   run                 
and                 n                   and                 
eating              v                   eat                 
at                  n                   at                  
same                a                   same                
time                n                   time                
he                  n                   he                  
has                 v                   have                
bad                 a                   bad                 
habit               n                   habit               
of                  n                   of                  
swimming            v                   swim                
after               n                   after               
playing             v   [...]<jupyter_text>Ahora toca aplicar todo esto a nuestro Dataset. Se vuelve a importar y se realiza un procedimiento análogo al ya hecho para la parte de Stemming.<jupyter_code># Importamos el lemmatizar de NLTK, y creamos el objeto
from nltk.stem import WordNetLemmatizer
wordnet_lemmatizer = WordNetLemmatizer()

# Importamos esta libreria que nos permite reemplzar caracteres
import re

dataset = pd.read_json('Sarcasm_Headlines_Dataset_v2.json', lines= True)
dataset = pd.concat([dataset.headline,dataset.is_sarcastic],axis=1)
dataset.dropna(axis=0,inplace=True)

# Traemos nuevamente las stopwords
stopwords = nltk.corpus.stopwords.words('english')
#stopword.remove('no')
#stopword.remove('not')
titular_list=[]
for titular in dataset.headline:
    # Vamos a reemplzar los caracteres que no sean leras por espacios
    titular=re.sub("[^a-zA-Z]"," ",str(titular))
    # Pasamos todo a minúsculas
    titular=titular.lower()
    # Tokenizamos para separar las palabras
    titular=nltk.word_tokenize(titular)
    
    # Aplicamos el Lemmatizer (Esto puede tardar un ratito)
    frase_lemma = [wordnet_lemmatizer.lemmatize(w, get_wordnet_pos(w)) for w in titular]
    
    
    # Eliminamos las palabras d emenos de 3 letras
    titular = [palabra for palabra in titular if len(palabra)>3]
    # Sacamos las Stopwords
    titular = [palabra for palabra in titular if not palabra in stopwords]
    
    # Por ultimo volvemos a unir el titular
    titular=" ".join(titular)
    #dataset["titular_normalizado"] = titular_list
    titular_list.append(titular)
# Se construye un Dataframe
dataset["titular_lemm"] = titular_list # Se incluye la versión del titular, pero Lematizado
dataset.tail()<jupyter_output><empty_output><jupyter_text>Por último, se arma un nuevo dataset llamado `dataset_lem` que tenga solo las columnas `titular_lemm` y `is_sarcastic`.<jupyter_code>dataset_lemm = pd.concat([dataset.titular_lemm,dataset.is_sarcastic],axis=1)
dataset_lemm.dropna(axis=0,inplace=True)  # Por si quedaron titulares vacios
dataset_lemm.head()<jupyter_output><empty_output><jupyter_text>6. VectorizarEn éste apartado, se construye el modelo con bolsa de palabras.Hasta ahora, tenemos un grupo de palabras por cada titular (bag of words), ya sea *lemmatizado* o *stemmizado*.  La idea ahora es representar esta lista de palabras como un vector. Para ésto, se utilizará la función `CountVectorizer` de Scikit-Learn, la cual permite representar cada título por un vector con un `1` en las palabras que contienen sarcasmo  y un `0` en las que no.  Además, se trabajará únicamente con las palabras que aparecen más veces en el texto, ya que las que aparecen una única vez o pocas veces no nos van a brindar información que se pueda generalizar.1. Lista de palabras y el vector que nos dice si es o no sarcástico el título<jupyter_code># Lista de palabras y el vector que nos dice si el título es o no sarcástico
list_titulos = list(dataset_lemm['titular_lemm'].values) # Lista
is_sarc = dataset_lemm['is_sarcastic'].values # Serie

## Para probar con Stemmizer:
#list_titulos = list(dataset_stem'titular_stem'].values)
#is_sarc = dataset_stem['is_sarcastic'].values
print (len(list_titulos))<jupyter_output>28619<jupyter_text>2. Conversor de bag of words a vectores que se obtiene de de sklearn. `CountVectorizer` posee varias funcionalidades que pueden determinarse a partir de parámetros.<jupyter_code>from sklearn.feature_extraction.text import CountVectorizer

# Es un vector que indica en cada posición, cuántas veces aparece cada palabra (bolsa de palabras)
# Se considerarán, solo las 1000 palabras con más frecuencia en todo el corpus para generar los vectores
max_features=1000

# Es decir que cada instancia, de la clase vectorizador, tendrá 1000 features (con conteo más alto)
cou_vec=CountVectorizer(max_features=max_features) # Predet: stop_words="english" ; ngram_range=(1, 2) -cuántas veces aparecen combinaciones de 2 palabras consecutivas-<jupyter_output><empty_output><jupyter_text>Desde `CountVectorizer` se pueden quitar las stopwords (algo que ya hicimos con `nltk`) e incluir los n_gramas automáticamente.3. Se generan los vectores para cada título a partir del corpus total.<jupyter_code>matriz_titulos = cou_vec.fit_transform(list_titulos) # Matriz de titulos

# Todas las palabras. Cada palabra es como un feature diferente
all_words = cou_vec.get_feature_names()

# Se visualizan las 50 palabras mas usadas, que más aparecen
print("50 palabras mas usadas: ",all_words[0:50])<jupyter_output>50 palabras mas usadas:  ['abortion', 'abuse', 'accidentally', 'accused', 'across', 'action', 'activists', 'actor', 'actually', 'address', 'adds', 'administration', 'admits', 'adorable', 'advice', 'ahead', 'airport', 'album', 'allegations', 'almost', 'already', 'also', 'always', 'amazing', 'amazon', 'america', 'american', 'americans', 'amid', 'among', 'anniversary', 'announce', 'announces', 'another', 'anti', 'anyone', 'anything', 'apartment', 'apologizes', 'apparently', 'apple', 'area', 'around', 'arrested', 'artist', 'asked', 'asking', 'asks', 'assault', 'attack']<jupyter_text>7. Modelar 7.1 Se dividen los datos en test y train.<jupyter_code>x = matriz_titulos.toarray() # Matriz de titulos convertida a un arreglo
y = is_sarc # Si es sarcasmo o no

from sklearn.model_selection import train_test_split
xtrain, xtest, ytrain, ytest = train_test_split(x,y,test_size=0.2,random_state=42,stratify=y)<jupyter_output><empty_output><jupyter_text>Se define una función que nos permite plotear los resultados en una matriz de confusión.<jupyter_code>from sklearn.metrics import confusion_matrix
import seaborn as sns

# Defino para luego construir la matriz de confusión (clasificador)
def confusion(ytest,y_pred):
    names=["No Sarcastico","Sarcastico"]
    cm=confusion_matrix(ytest,y_pred)
    f,ax=plt.subplots(figsize=(5,5))
    sns.heatmap(cm,annot=True,linewidth=.5,linecolor="r",fmt=".0f",ax=ax)
    plt.xlabel("y_pred")
    plt.ylabel("y_true")
    ax.set_xticklabels(names)
    ax.set_yticklabels(names)
    plt.show()

    return<jupyter_output><empty_output><jupyter_text>7.2 Naive BayesSe aplica Naive Bayes Gaussiana para tener un benchmark de referencia para el accuracy.<jupyter_code>from sklearn.naive_bayes import GaussianNB
nb = GaussianNB()
nb.fit(xtrain,ytrain)
print("acc : ", nb.score(xtest,ytest))<jupyter_output>acc :  0.7071977638015374<jupyter_text>Matriz de confusión:<jupyter_code>y_pred=nb.predict(xtest)
confusion(ytest,y_pred)<jupyter_output><empty_output><jupyter_text>7.3 Random Forest1. Aplicamos random forest para predecir el sarcasmo de una nota en base a su titular.<jupyter_code>from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import confusion_matrix

rf = RandomForestClassifier(n_estimators = 50, random_state=42) # 50 árboles de decisión diferentes
rf.fit(xtrain,ytrain)
print("acc: ",rf.score(xtest,ytest))<jupyter_output>acc:  0.6972396925227113<jupyter_text>2. Matriz de confusión:<jupyter_code>y_pred=rf.predict(xtest)
confusion(ytest,y_pred)<jupyter_output><empty_output><jupyter_text>3. Vemos en este caso cuales son las palabras que mayormente determinan el sarcasmo de una nota para este clasificador.<jupyter_code># Le preguntamos la importancia de cada feature (cada palabra)
importances = rf.feature_importances_
# Tomamos la lista de palabras
all_words = cou_vec.get_feature_names()
columns = all_words

# Ordenamos por importnacia y tomamos las 20 primeras
indices = np.argsort(importances)[::-1]
indices = indices[:20]
selected_columns = [columns[i] for i in indices]
selected_importances = importances[indices]

# Por ultimo graficamos
plt.figure(figsize = (15,8))
sns.barplot(selected_columns, selected_importances)
plt.show()<jupyter_output>C:\Users\Ale\anaconda3\envs\ds\lib\site-packages\seaborn\_decorators.py:36: FutureWarning: Pass the following variables as keyword args: x, y. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation.
  warnings.warn(<jupyter_text>* La palabra más importante, para determinar si es un Sarcasmo, es `Área`.  7.4 SVMPor último se utilizará uno de los modelos mas prometedores para este tipo de datos donde el numero de features es comparable al número de instancias: SVM. 1. Se entrena un modelo de SVM Lineal y calcule su accuracy para C = 1.<jupyter_code># Notar que en vez de utilizar SVC, vamos a usar LinearSVC. 
# Para el Kernel Lineal, esta función es MUCHO más rapida que la tradicional SVC.
from sklearn.svm import LinearSVC

svc = LinearSVC(C = 1)
svc.fit(xtrain,ytrain)
svc.score(xtest,ytest)<jupyter_output><empty_output><jupyter_text>2. Matriz de confusión:<jupyter_code>y_pred=svc.predict(xtest)
confusion(ytest,y_pred)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0813250944043941, 'fraction_numerical': 0.008341915550978372, 'mean_word_length': 4.201964285714285, 'pattern_counts': {'":': 4, '<': 138, '<?xml version=': 0, '>': 140, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 41, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '37', 'dir': 'jupyter-structured-clean-dedup', 'id': '527353', 'license': 'MIT', 'n_tokens_mistral': 10048, 'n_tokens_neox': 9804, 'n_words': 3140, 'path': 'nlp-news-headlines-dataset-for-sarcasm-detection.ipynb', 'repo_name': 'alseveso/nlp-news-headlines-dataset-for-sarcasm-detection', 'size': '29130'}