domingo, 16 de octubre de 2016

Sentiment Analysis

El siguiente ejemplo utiliza texto de twitter clasificado previamente como POS, NEG o SEM para predecir si un tweet es positivo, negativo o imparcial sobre amazon. La técnica usada para representar el texto es bag-of-words, donde se mide la aparición de la palabra y no su orden. Estos tweets fueron copiados de la cuenta pública de @amazonPara mismo ejemplo con R ver nota publicada AQUI

El proceso general sigue estos pasos:

1. Cargar Datos de Dropbox
Para este ejemplo, los datos se cargan de un archivo csv en Dropbox, el cual tiene dos columnas: el texto y la clase a predecir. Queda así:
















2. Crear Corpus

El corpus es el conjunto de documentos, que pueden ser artículos periodisticos, noticias, currículos, tweets, chat, o cualquier colección de textos que se vaya a utilizar para predecir/clasificar textos futuros. En este ejemplo se usan tweets, y la columna "texto" del csv será el corpus. Antes de convertir el texto en una matriz numérica, se hacen la siguiente limpieza/transformación: 
   - Se convierte todo el texto en minúscula
   - Se eliminan todos los caracteres que no son letras (números, signos puntuación, etc.)
   - Se elimina el doble espacio entre las palabras


3. Crear Train y Test

En este paso, se divide el dataset en train y test. Esto se hace tanto para el corpus como para la clase a predecir. Conceptualmente queda así:





















4a. Tokenización 
La Tokenización consiste en dividir el texto a su unidad mínima de significado, esto puede ser la palabra o la oración (o token). Para este ejemplo se utilizó la tokenizacion de palabras usando la función "word_tokenize" de la librería nltk. Estos son algunos de los procesos que hace:
• Stopword: utiliza un diccionario de palabras sin significado, como pronombres, artículos, preposiciones, etc. para eliminar estas palabras de los tweets. A este diccionario le dicen stopword, y se utiliza uno especifico según el idioma del corpus. En este ejemplo se usa el stopword que trae la librería nltk para el idioma ingles.
• Stemming: usa una técnica para reducir las palabras a su raíz (o stems en ingles). Un ejemplo de este proceso puede ser la reducción de las palabras "connected", "connecting", "connection", "connections"; todas estas se sustituyen por su palabra raíz: "connect". En este ejemplo se utilizó el algoritmo PorterStemmer de la librería nltk, que usa una lista de sufijos específicos y condiciones especificas para cada sufijo que evaluarán si este debe eliminarse o no, para así obtener la raíz de la palabra. Para detalle del algoritmo PorterStemmer y su creador (Martin Porter), ver referencia Nro.3. Para otros algoritmos de stemming, ver Ref. Nro 4.



4b. Vectorizacion
Luego que se tiene el texto dividido por palabras con significado, se procede a crear un vector que mida la presencia de cada palabra en el tweet, formando una matriz que le dicen "medelo vectorial". Para medir la presencia de una palabra en un texto existen varias métricas. Algunas son estas:
TF(Time Frecuenci): es la frecuencia de la palabra en un texto, es decir, cuantas veces aparece una palabra en un tweet.
IDF (Inverse document frequency): esta medida se calcula para cada palabra, realizando el N/log(n), donde N es el total de documentos (o tweet) y n es la cantidad de veces que aparece la palabra en todos los documentos. Esto mide la presencia de una palabra en el corpus, haciéndola menos importante si aparece en la mayoría de los documentos. Es decir, mide qué tan única es la palabra en la colección de documentos.
TF * IDF: Multiplicación de las dos medidas anteriores. Es una forma de identificar la importancia de cada palabra en cada documento, penalizando palabras que son muy comunes.
FLAG: Esta medida marca 1 si la palabra aparece 1 o mas veces en un tweets, sino marca 0.

Conceptualmente la tokenizacion y vectoriacon quedan así:










5. Modelo
Para este ejemplo se utilizó el algoritmo SVM de la librería sklearn. Para detalle de parámetros y funciones, ver referencia nro.6.


6. Predicción
Para saber que tan bueno es el modelo, se utilizó la matriz de confusión para calcular la eficiencia del modelo en test. 

Al evaluar el modelo se tienen estos resultados. En una siguiente nota, veré como ajustar un modelo a este mismo problema para tener mejores resultados..






















Script:
import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn import svm
from sklearn.metrics import classification_report
import nltk 
from sklearn.cross_validation import train_test_split as tts
import re
#from sklearn.neural_network import MLPClassifier


# FUNCIONES
# ----------------------------------------------------------------------------
def clean_corpus(corpus):
  xcorpus = corpus.get_values()
  for i in range(len(corpus)):
    xcorpus[i] = re.sub("[^a-zA-Z]", " ", corpus[i].lower())
    xcorpus[i] = ' '.join(xcorpus[i].split())
  return xcorpus

def tokenize(text):
    tokens = nltk.word_tokenize(text,  language='english')
    stems = []
    for item in tokens:
        stems.append(nltk.PorterStemmer().stem(item))
    return stems

def train_test_vector(xtrain, xtest):
   vectorizer = TfidfVectorizer(tokenizer=tokenize, max_df = 0.80, use_idf=True,min_df=1)
   #vectorizer    = CountVectorizer(min_df=1,binary=True) # metrica binaria
   vector_train  = vectorizer.fit_transform(xtrain)
   vector_test   = vectorizer.transform(xtest)
   return vector_train, vector_test, vectorizer



# EJECUCION
# ----------------------------------------------------------------------------

# 1. CARGAR DATOS DE DROPBOX
data = pd.read_csv('https://dl.dropboxusercontent.com/u/59930995/python/dataset/amz3.csv')

# 2. CORPUS
corpus = clean_corpus(data['texto'])

# 3. TRAIN TEST
xtrain, xtest, ytrain, ytest = tts(corpus, data['clase'], train_size=0.70)

# 4. TOKENIZACION + VECTORIZACION
xtrain, xtest, vectorizer = train_test_vector(xtrain=xtrain, xtest=xtest)

# 5. MODELO
modelo = svm.SVC(kernel='linear') 
modelo.fit(X=xtrain, y=ytrain)

# 6. PREDICT + METRICAS
prediccion = modelo.predict(xtest)
print(pd.crosstab(ytest, prediccion, rownames=['REAL'], colnames=['PREDICCION']))
print(classification_report(ytest, prediccion))

Referencias
1. http://bbengfort.github.io/tutorials/2016/05/19/text-classification-nltk-sckit-learn.html
2. https://www.kaggle.com/c/word2vec-nlp-tutorial/details/part-1-for-beginners-bag-of-words
3. https://tartarus.org/martin/PorterStemmer/
4. http://www.nltk.org/api/nltk.stem.html
5. https://en.wikipedia.org/wiki/Bag-of-words_model
6. http://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html
7. https://marcobonzanini.com/2015/03/02/mining-twitter-data-with-python-part-1/





 

No hay comentarios:

Publicar un comentario