domingo, 6 de noviembre de 2016

Text Mining con Twiter

El siguiente ejemplo utiliza textos de twitter clasificados 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 @amazon.

NOTAS:
Para mismo ejemplo en PYTHON, ver nota publicada AQUI
El excel con las imágenes se puede descargar AQUI
Para este ejemplo se utilizó la libreria tm_0.6-2

El proceso general sigue estos pasos:

1. Cargar Datos
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. Conceptualmente queda así:












2. Crear Corpus
El corpus es un conjunto de documentos, que pueden ser artículos periodísticos, noticias, currículos, tweets, chat, o cualquier colección de textos que se vaya a utilizar para predecir/clasificar. En este ejemplo se usan tweets, y la columna "texto" del csv será el corpus.

Una forma de crear el corpus en R es usando la libreria tm de la siguiente forma:
- Crear un objeto VectorSource que será el origen de datos que luego se utiliza para crear un corpus volatil o vcorpus
- Crear un objeto VCorpus que es un corpus que se guarda en memoria, con lo cual es volatil. En este objeto se considera cada observación (tweet para este ejemplo) como un documento. El origen de datos para crear un vcorpus siempre será un VectorSource.
Para detalle sobre estos objetos, ver Referencia No.2

Conceptualmente seria así:












3. Limpiar Corpus
Luego que se tiene el VCorpus, se procede "limpiar" el corpus de la siguiente forma:
- Se sustituyen los signos de puntuación por espacios (replacePunctuation)
- Se eliminan los numeros (removeNumbers)
- Se elimina el doble espacio (stripWhitespace)
- Se convierte en minúscula todas las palabras (tolower)
- Se sustituyen algunas palabras abreviadas (stri_replace_all_fixed)
- Se transforma en documento plano (PlainTextDocument). Esto para cuando se usan funciones que no retornan un TextDocuments. Para detalle ver Ref. Nro 3
- Se eliman los sufijos de las palabras usando el algoritmo PorterStemmer (stemDocument). Para detalle ver referencia Nro. 4
- Se eliminan palabras sin significados, como pronombres, preposiciones, etc. usando el stopwords o lista de palabras que trae la libreria tm (removeWords). Para detalle ver referencia Nro. 4

Conceptualmente sería asi:

















4. Crear DocumentTermMatrix
Con la libreria tm se pueden crear dos objetos para analizar el documento:
- TermDocumentMatrix (TDM) donde las filas son los términos o palabras (token) y las columnas los documentos o tweet. Este objeto se usa para analizar frecuencia y asociación de palabras, es decir para "entender" el corpus.
- DocumentTermMatrix (DTM) donde las filas son los documentos o tweets  y las columnas son los terminos o palabras (token). Para este ejemplo se usa la DTM para crear una matriz de datos que luego se usa para modelar el clasificador. En la creacion del DTM se eliman las palabras que solo tienen una ocurrencia, asi como las que tienen pocas letras. Para detalle ver pagina 37 de referencia nro 5. Para gráficos con TDM ver referencia Nro. 6

Conceptualmente los objetos quedan así:















5. Se crea una matriz 
Se usa la DTM para crear la matriz a usar en el clasificador. Queda así:












6. Train Test
Se divide la matriz en dos set de datos: Train y Test, como tambien el vector de la clase para cada  set















7. Modelo
Se usa SVM para crear el clasificador a partir del set de Train, quedando así:














8. Predicción 
Se predice la clase en el set de Test. Luego se crea una matriz de confusion para evaluar el ajuste del modelo, quedando así:












R script:
# LIBRERIAS Y FUNCIONES
libs<-c('tm','SnowballC','tm','e1071','randomForest','stringi')
lapply(libs,require, character.only= TRUE)

clean_corpus <- function(xcorpus){
  # Se agregan palabras al stopword
  stopwords_new= c('amaz','amzn', 'amzns','amazon','amazonc', 'amazons' ,tm::stopwords('english'))
  # Para reemplar algunas palabras:
  xword <- c('goog',  'googleled', 'googlele', 'aapl',  'aples', 'apples', 'amz',    'amzz',  'amazonn','nflx')
  xtran <- c('google','google',     'google',  'apple', 'apple', 'apple',  'amazon', 'amazon','amazon','netflix')
  replacePunctuation <- content_transformer(function(x) {return (gsub("[[:punct:]]"," ", x))})
  xcorpus = tm_map(xcorpus, replacePunctuation) 
  xcorpus = tm_map(xcorpus, content_transformer(tm::removeNumbers))
  xcorpus = tm_map(xcorpus,tm::stripWhitespace)
  xcorpus = tm_map(xcorpus,content_transformer(base::tolower))
  xcorpus = tm_map(xcorpus, function(x) stringi::stri_replace_all_fixed(x, xword, xtran, vectorize_all = FALSE))
  xcorpus = tm_map(xcorpus, PlainTextDocument)
  xcorpus = tm_map(xcorpus, stemDocument, language = "porter")
  xcorpus = tm_map(xcorpus,tm::removeWords,stopwords_new)
  return(xcorpus)
}


# 1. DATOS
df <- read.csv("https://www.dropbox.com/s/qal9dawx67c66wj/amz3.csv?dl=1", sep=",")

# 2. CREAR CORPUS
vsource  <- tm::VectorSource(df$texto)
corpus   <- tm::VCorpus(vsource)

# 3. LIMPIAR CORPUS
corpus   <- clean_corpus(corpus)

# 4. CREAR DocumentTermMatrix
dtm <- DocumentTermMatrix(corpus,
       control = list(
       weight = weightTfIdf,
       bounds = list(global = c(2,Inf)),
       wordLengths=c(4,Inf)
      ))

# 5. MATRIX
mtx = as.matrix(dtm)

# 6. TRAIN TEST
n_train <- sample(nrow(mtx),nrow(mtx)*.7)
xtrain  <- mtx[n_train,]
ytrain  <- as.factor(df[n_train,"clase"])
xtest   <- mtx[-n_train,]
ytest   <- as.factor(df[-n_train,"clase"])


# 7. MODELO
modelo  <- svm(x=xtrain, y=ytrain, kernel = 'linear', scale = FALSE)

# 8. PREDICCION
prediccion <- predict(modelo,xtest)
(mc <- table(ytest,prediccion))
sum(diag(mc))/sum(mc)


# OTROS
findFreqTerms(dtm, dim(dtm)[1] * 0.05) # palabras repetidas en 5% de tweet
findFreqTerms(dtm, lowfreq = 0, highfreq = 4 ) # palabras repetidas en 4 menos tweet




Referencia
1. http://web.letras.up.pt/bhsmaia/EDV/apresentacoes/Bradzil_Classif_withTM.pdf
2. http://stats.stackexchange.com/questions/164372/what-is-vectorsource-and-vcorpus-in-tm-text-mining-package-in-r
3. http://stackoverflow.com/questions/24191728/documenttermmatrix-error-on-corpus-argument
4. http://python-apuntes.blogspot.com.ar/2016/10/sentiment-analysis.html
5. https://cran.r-project.org/web/packages/tm/tm.pdf
6. http://stackoverflow.com/questions/23766124/colors-and-a-plotting-term-document-matrix









1 comentario:

  1. Saludos Enmanuel

    ¿Cómo agregarías un código para crear en este ejemplo un wordcloud?

    ResponderEliminar