#!/usr/bin/env python
# coding: utf-8

# # Limpieza de datos

# ## Introducción

# En este notebook, vamos a limpiar el texto extraído de una web.  Concretamente tocaremos:
# 
# 1. **Obtención del dato (en este caso vamos a scrappear la info de una web)**
# 2. **Limpieza de los datos**
# 3. **Organización de los datos (para el uso de los datos limpios con otros algoritmos)**
# 
# La salida de este notebook, será un texto, limpio, y con el texto organizado en 2 formas:
# 
# 1. **Corpus** - colección de textos
# 2. **Document-Term Matrix** - Word counts en formato matriz

# ## Problema a resolver

# El objetivo es transcribir los textos de varios cómicos a comprobar sus similitares y diferencias. Compararemos por tanto el estilo de los diferentes cómicos.

# ## Obtención de los datos

# Haremos uso de la web [Scraps From The Loft](http://scrapsfromtheloft.com) que contiene numerosas transcripciones de cómicos.
# 
# La selección de los cómicos, la analizaremos más adelante.

# In[1]:


# Web scraping e importación pickle
import requests
from bs4 import BeautifulSoup
import pickle

# URLs a scrapear
urls = ['http://scrapsfromtheloft.com/2017/05/06/louis-ck-oh-my-god-full-transcript/',
        'http://scrapsfromtheloft.com/2017/04/11/dave-chappelle-age-spin-2017-full-transcript/',
        'http://scrapsfromtheloft.com/2018/03/15/ricky-gervais-humanity-transcript/',
        'http://scrapsfromtheloft.com/2017/08/07/bo-burnham-2013-full-transcript/',
        'http://scrapsfromtheloft.com/2017/05/24/bill-burr-im-sorry-feel-way-2014-full-transcript/',
        'http://scrapsfromtheloft.com/2017/04/21/jim-jefferies-bare-2014-full-transcript/',
        'http://scrapsfromtheloft.com/2017/08/02/john-mulaney-comeback-kid-2015-full-transcript/',
        'http://scrapsfromtheloft.com/2017/10/21/hasan-minhaj-homecoming-king-2017-full-transcript/',
        'http://scrapsfromtheloft.com/2017/09/19/ali-wong-baby-cobra-2016-full-transcript/',
        'http://scrapsfromtheloft.com/2017/08/03/anthony-jeselnik-thoughts-prayers-2015-full-transcript/',
        'http://scrapsfromtheloft.com/2018/03/03/mike-birbiglia-my-girlfriends-boyfriend-2013-full-transcript/',
        'http://scrapsfromtheloft.com/2017/08/19/joe-rogan-triggered-2016-full-transcript/']


# Nombres de los cómicos
comicos = ['louis', 'dave', 'ricky', 'bo', 'bill', 'jim', 'john', 'hasan', 'ali', 'anthony', 'mike', 'joe']


# In[2]:


# Cargamos los datos transcritos previamente
datos = {}
for i, c in enumerate(comicos):
    with open("extracciones/" + c + ".txt", "rb") as file:
        datos[c] = pickle.load(file)


# In[3]:


# Comprobamos que los datos se han cargado correctamente
datos.keys()


# In[4]:


datos['louis'][:2]


# In[5]:


datos


# ## Limpieza de los datos

# Cuando trabajamos con datos numéricos, la limpieza implica habitualmente eliminar valores nulos, datos duplicados, outliers, ...
# 
# En el caso del PLN, hay algunas técnicas de limpieza comunes (preprocesado de textos).  Usaremos las más comunes.
# 
# **Pasos comunes para cualquier texto:**
# * Convertir textos a minúsculas
# * Eliminar signos de puntuación
# * Eliminar valores numéricos
# * Eliminar caracteres especiales (/n)
# * Tokenización del texto
# * Eliminar stopwords
# 
# **Más pasos a ejecutar tras la tokenización:**
# * Análisis lexicográfico
# * Etiquetado gramatical
# * Creación de bigramas y trigramas
# * ...

# In[6]:


# Cambiamos el formato que contiene los textos.  En el diccionario datos, el valor está en formato lista.  Lo pasamos a formato texto
def combinar_texto(lista_de_texto):
    '''Toma una lista de texto y la combina en un sólo chunck de texto.'''
    texto_combinado = ' '.join(lista_de_texto)
    return texto_combinado


# In[7]:


# Combinamos el texto
datos_combinados = {clave: [combinar_texto(valor)] for (clave, valor) in datos.items()}


# In[11]:


# Podemos trabajar con los datos en formato diccionario o dataframe.  En este ejemplo lo haremos en formato dataframe
import pandas as pd
pd.set_option('max_colwidth',150)

datos_df = pd.DataFrame.from_dict(datos_combinados).transpose()
datos_df.columns = ['transcripcion']
datos_df = datos_df.sort_index()
datos_df


# In[12]:


# Miramos la transcripción de Ali...
datos_df['transcripcion'].loc['ali']


# In[13]:


# Primer paso de limpieza
import re
import string

def limpieza_texto1(texto):
    '''Convierte a minúsculas, eliminar corchetes, puntuación, palabras que contienen números.'''
    texto = texto.lower()
    texto = re.sub('\[.*?\]', '', texto)
    texto = re.sub('[%s]' % re.escape(string.punctuation), '', texto)
    texto = re.sub('\w*\d\w*', '', texto)
    return texto

primer_paso = lambda x: limpieza_texto1(x)


# In[14]:


# Comprobamos lo que obtenemos con el primer paso
datos_limpios = pd.DataFrame(datos_df['transcripcion'].apply(primer_paso))
datos_limpios


# In[15]:


# Segundo paso de limpieza
def limpieza_texto2(texto):
    '''Eliminar puntuaciones adicionales y determinados elementos no eliminados en paso 1.'''
    texto = re.sub('[‘’“”…]', '', texto)
    texto = re.sub('\n', '', texto)
    return texto

segundo_paso = lambda x: limpieza_texto2(x)


# In[16]:


# Comprobamos lo que obtenemos con el segundo paso
datos_limpios = pd.DataFrame(datos_limpios ['transcripcion'].apply(segundo_paso))
datos_limpios


# **NOTE:** This data cleaning aka text pre-processing step could go on for a while, but we are going to stop for now. After going through some analysis techniques, if you see that the results don't make sense or could be improved, you can come back and make more edits such as:
# * Mark 'cheering' and 'cheer' as the same word (stemming / lemmatization)
# * Combine 'thank you' into one term (bi-grams)
# * And a lot more...

# ## Organizando los datos

# ### Corpus

# Ya hemos generado el corpus en los pasos previos

# In[17]:


datos_df


# In[18]:


# Añadimos el nombre completo del cómico...
nombres_completos = ['Ali Wong', 'Anthony Jeselnik', 'Bill Burr', 'Bo Burnham', 'Dave Chappelle', 'Hasan Minhaj',
              'Jim Jefferies', 'Joe Rogan', 'John Mulaney', 'Louis C.K.', 'Mike Birbiglia', 'Ricky Gervais']

datos_df['nombre_completo'] = nombres_completos
datos_df


# In[75]:


# Convertirmos el dataframe a formato pickle para más adelante.  Pickle básicamente 'serializa objetos' (guarda cualquier objeto de python como una cadena de bytes)
datos_df.to_pickle("corpus.pkl")


# ### Document-Term Matrix

# El objetivo de este punto, es descomponer el corpus en palabras. Podemos hacerlo con CountVectorizer de scikit-learn.  Cada fila representa un documento diferente y cada columna una palabra distinta.
# 
# Además, con CountVectorizer, podemos eliminar las stop workds.

# In[20]:


from sklearn.feature_extraction.text import CountVectorizer

cv = CountVectorizer(stop_words='english')
datos_cv = cv.fit_transform(datos_limpios ['transcripcion'])
datos_dtm = pd.DataFrame(datos_cv.toarray(), columns=cv.get_feature_names())
datos_dtm.index = datos_limpios.index
datos_dtm


# In[21]:


# Convertimos los datos a formato pickle
datos_dtm.to_pickle("dtm.pkl")


# In[22]:


# Let's also pickle the cleaned data (before we put it in document-term matrix format) and the CountVectorizer object
datos_limpios.to_pickle('datos_limpios.pkl')
pickle.dump(cv, open("cv.pkl", "wb"))


# ## Ejercicios para practicar...

# 1. ¿Se te ocurren otro tipo de expresiones regulares a añadir a la función limpieza_texto2 con el fin de limpiar el texto? Website para testear las expresiones regulares: https://regex101.com
# 2. Juega con los parámetros de CountVectorizer. ¿Qué es ngram_range? ¿Qué es min_df y max_df?
