Minería de Datos en Redes Sociales

Cristian Gaviria y Juan Pablo Gómez

Noviembre de 2023

Minería de Datos en Redes Sociales

En éste documento revisaremos cómo realizar análisis de sentimientos usando R.

Contexto:

Twitter es actualmente una dinámica e ingente fuente de contenidos que, dada su popularidad e impacto, se ha convertido en la principal fuente de información para estudios de Análisis de redes sociales.

Los tweets pertenecen a:

Link Tweets: https://www.kaggle.com/datasets/micheldc55/tweets-from-bill-gates-elon-musk-and-ed-lee/download?datasetVersionNumber=1

Objetivos

  • Crear un modelo de machine learning capaz de clasificar la autoría de las publicaciones en base a su texto.

  • Determinar la variación del sentimiento promedio de los tweets agrupados por intervalos de un mes para cada uno de los usuarios.

Paquetes

library(slam)
library(ggrepel)
library(lubridate)
library(tidyverse)
library(ggplot2)
library(ggthemes)
library(e1071)
library(caret)
library(tm)
library(readr)
library(dplyr)
library(anytime)
library(plotly)
library(gridExtra)
library(scales)
library(knitr)
library(kableExtra)

Extracción datos de Twitter (Opcional)

  1. Creamos una cuenta de desarrollador en https://developer.twitter.com/en y entramos en la sección “Portal del Desarrollador”.

  2. Una vez creada la cuenta nos genera la API Key y Tokens de acceso para ingresar desde R a la API:

    Api Key Token

  3. En nuestro R cargamos la librería “rtweet”, ésta es la conexión a la API de Twitter para la extracción de datos.

    # Instalar las librerías necesarias
    install.packages("rtweet")
    
    # Importar las librerías
    library(rtweet)
    
    # Definir las credenciales de acceso
    api_key <- "YOUR_API_KEY"
    api_secret <- "YOUR_API_SECRET"
    access_token <- "YOUR_ACCESS_TOKEN"
    access_token_secret <- "YOUR_ACCESS_TOKEN_SECRET"
    
    # Configurar la librería
    setup_twitter_oauth(api_key, api_secret, access_token, access_token_secret)
    
    # extraer los 100 últimos tweets sobre Popayán en español
    tweets <- search_tweets("Popayán", n = 100, lang = "es")

De esta manera obtenemos datos de la App de Twitter, anteriormente de manera gratutita. Luego esta red social cambió las políticas de seguridad y es necesario pagar USD 100 dolares para acceder a estos datos.

Para el caso de TikTok, requiere los siguiente:

Para continuar con éste estudio, procedemos con nuestro conjuto de datos de tweets de Elon Musk (@elonmusk), Bill Gates (@BillGates) y Mayor Ed Lee (@mayoredlee) a análizar su distribución temporal por año.

Distribución temporal de los tweets por año:

  • Bill Gates ha mantenido una actividad constante de tweets por años durante todo el periodo estudiado.

  • Elon Musk mostró una actividad inicial por debajo de la de Bill Gates, pero a partir de 2016 incrementó notablemente el número de tweets publicados.

  • Ed Lee tiene una actividad muy alta, especialmente en 2017.

Limpieza y Tokenización

La tokenización es el proceso de dividir un texto en unidades básicas, denominadas tokens. Un token puede ser una palabra, una frase o un número.

La función limpiar_tokenizar() elimina el símbolo @ y # de las palabras a las que acompañan.

Por ejemplo, si tenemos el texto : "Esto es 1 ejemplo de l'limpieza de6 TEXTO https://t.co/rnHPgyhx4Z @cienciadedatos #textmining"

El resultado sería:

[1] "esto"           "es"             "ejemplo"        "de"             "limpieza"       "de"             "texto"          
[8] "cienciadedatos" "textmining" 

Luego de aplicar la función nuestro texto queda de la siguiente manera:

texto texto_tokenizado
“If one day, my words are against science, choose science.” Mustafa Kemal Atatürk if , one , day , my , words , are , against, science, choose , science, mustafa, kemal , atatürk

I placed the flowers

Three broken ribs A pierced lung And still he fought For peace at… https://t.co/MeEKf2ZntM
placed , the , flowers, three , broken , ribs , pierced, lung , and , still , he , fought , for , peace , at
Atatürk Anıtkabir https://t.co/al3wt0njr6 atatürk , anıtkabir
@Bob_Richards One rocket, slightly toasted bob , richards, one , rocket , slightly, toasted
@uncover007 500 ft so far. Should be 2 miles long in three or four months and hopefully stretch the whole 405 N-S c… https://t.co/BfoqYKJg3u uncover , ft , so , far , should , be , miles , long , in , three , or , four , months , and , hopefully, stretch , the , whole
Picture of The Boring Company LA tunnel taken yesterday https://t.co/TfdVKyXFsJ picture , of , the , boring , company , la , tunnel , taken , yesterday

Análisis Exploratorio

Es interesante estudiar qué palabras emplea cada autor, con qué frecuencia, así como el significado de las mismas.

tweets_tidy
autor fecha id año mes token
1 elonmusk 2017-11-09 9.286758e+17 2017 noviembre if
2 elonmusk 2017-11-09 9.286758e+17 2017 noviembre one
3 elonmusk 2017-11-09 9.286758e+17 2017 noviembre day
4 elonmusk 2017-11-09 9.286758e+17 2017 noviembre my
5 elonmusk 2017-11-09 9.286758e+17 2017 noviembre words
6 elonmusk 2017-11-09 9.286758e+17 2017 noviembre are
106902 BillGates 2011-09-30 1.195196e+17 2011 septiembre local
106903 BillGates 2011-09-30 1.195196e+17 2011 septiembre efforts
106904 BillGates 2011-09-30 1.195196e+17 2011 septiembre to
106905 BillGates 2011-09-30 1.195196e+17 2011 septiembre finish
106906 BillGates 2011-09-30 1.195196e+17 2011 septiembre the
106907 BillGates 2011-09-30 1.195196e+17 2011 septiembre job

Frecuencia de palabras

Palabras totales utilizadas por cada autor

--------------------------
Palabras totales por autor
--------------------------
autor
BillGates     31500
elonmusk      33609
mayoredlee    41878
Name: token

Palabras distintas utilizadas por cada autor

Elon Musk utiliza un vocabulario más amplio que otros usuarios de Twitter, a pesar de publicar menos tweets o de que estos sean más cortos.

Longitud media de tweets

autor mean_length std_dev_length
BillGates 15.17837 3.352386
elonmusk 12.63718 6.899293
mayoredlee 17.12838 3.455373

La longitud de los tweets de Bill Gates y Ed Lee es similar, con una media entre 15 y 17 palabras. Elon Musk, por su parte, publica tweets de longitud más variable, con una media de 12 palabras.

Palabras mas utilizadas por autor

A continuación presentamos el Top 5 de las palabras mas utilizadas por cada autor:

autor token count
BillGates the 1195
BillGates to 1117
BillGates of 670
BillGates in 591
BillGates is 453
elonmusk the 988
elonmusk to 916
elonmusk of 638
elonmusk is 543
elonmusk in 478
mayoredlee to 1693
mayoredlee the 1355
mayoredlee amp 1212
mayoredlee our 1104
mayoredlee sf 944

Puede observarse que los términos más frecuentes en todos los usuarios se corresponden con artículos, preposiciones, pronombres… (Stopwords).

Para cada idioma existen distintos listados de stopwords, además, dependiendo del contexto, puede ser necesario adaptar el listado.

# Crear la lista de stopwords en inglés
stop_words <- stopwords("en")

# Añadir stopwords adicionales: amp, ax, ex
stop_words <- c(stop_words, "amp", "xa", "xe")

# Imprimir las primeras 10 stopwords
print(head(stop_words, 10))
##  [1] "i"         "me"        "my"        "myself"    "we"        "our"      
##  [7] "ours"      "ourselves" "you"       "your"
  • Mayor Ed Lee es alcalde de San Francisco (sf), por lo que sus tweets están relacionados con la ciudad, residentes, familias, casas…

  • Elon Musk dirige varias empresas tecnológicas entre las que destacan Tesla y SpaceX, dedicadas a los coches y a la aeronáutica.

  • Por último, Bill Gates, además de propietario de microsoft, dedica parte de su capital a fundaciones de ayuda, de ahí las palabras mundo, polio, ayuda…

Correlación entre autores

Para poder generar los estudios de correlación se necesita disponer de cada variable en una columna. En este caso, las variables a correlacionar son los autores.

Palabras Comunes

Palabras comunes entre Elon Musk y Ed Lee: 1761

Palabras comunes entre Elon Musk y Bill Gates: 1783 

Palabras comunes entre Ed Lee y Bill Gates: 1716 

Top 10 palabras más diferenciadoras

token elonmusk mayoredlee log_odds abs_log_odds autor_frecuente
tesla 0.0122480 0.0000368 5.807402 5.807402 elonmusk
residents 0.0000447 0.0099014 -5.400437 5.400437 mayoredlee
yes 0.0054088 0.0000368 4.990065 4.990065 elonmusk
rocket 0.0049171 0.0000368 4.894755 4.894755 elonmusk
community 0.0000447 0.0058893 -4.880899 4.880899 mayoredlee
sf 0.0002682 0.0347836 -4.865151 4.865151 mayoredlee
spacex 0.0046042 0.0000368 4.829003 4.829003 elonmusk
falcon 0.0036655 0.0000368 4.600994 4.600994 elonmusk
landing 0.0029502 0.0000368 4.383929 4.383929 elonmusk
housing 0.0000894 0.0067727 -4.327514 4.327514 mayoredlee

Top 15 palabras mas diferenciadores de cada autor

Estas palabras posiblemente tendrán mucho peso a la hora de clasificar los tweets.

Frecuencia del Término y Frecuencia Inversa del Documento

Técnica esencial en el análisis de texto. Evalúa la importancia de las palabras dentro de un documento considerando tanto su frecuencia como su exclusividad en el conjunto de textos.

Por ejemplo, “página” podría aparecer más que “matemáticas” sin reflejar su importancia temática real.

Para resolver esto, se aplica la Inverse Document Frequency (IDF), que reduce el valor de palabras que aparecen en muchos documentos. TF-IDF combina estos conceptos para medir qué tan informativo es un término en un documento considerando su frecuencia relativa y su rareza en otros textos.

id token count total_count tf
5.45967e+17 battery 1 20 0.05
5.45967e+17 beta 1 20 0.05
5.45967e+17 blog 1 20 0.05

Frecuencia inversa de documento

token n_documentos idf
sf 949 2.022949
will 756 2.250317
can 391 2.909651
kable(head(tf_idf), format = "html") %>%
  kable_styling()
id token count total_count tf n_documentos idf tf_idf
1.195196e+17 efforts 1 13 0.0769231 31 5.444371 0.4187978
1.195196e+17 eradicating 1 13 0.0769231 8 6.798916 0.5229936
1.195196e+17 finish 1 13 0.0769231 7 6.932448 0.5332652
1.195196e+17 job 1 13 0.0769231 37 5.267440 0.4051877
1.195196e+17 local 1 13 0.0769231 85 4.435707 0.3412082
1.195196e+17 made 1 13 0.0769231 68 4.658850 0.3583731

Los términos que aparecen una vez tienen el mismo valor de frecuencia de término (TF). Sin embargo, como estos términos no tienen la misma frecuencia en todos los tweets, la corrección de la frecuencia inversa de documentos (IDF) difiere entre ellos.

Clasificación de Tweets

Bag of Words (BoW) es un método utilizado en procesamiento de lenguaje natural que crea un espacio n-dimensional donde cada dimensión representa una palabra.

Train-test

Para este ejercicio se selecciona como test un 20% aleatorio de los tweets.

# Combinar todos los textos de tweets en una sola lista
datos_X <- c(tweets_elonmusk, tweets_mayoredlee)

# Crear un vector de etiquetas para los datos, etiquetando cada tweet con el nombre del autor correspondiente
datos_y <- factor(rep(c("elonmusk", "mayoredlee"), c(length(tweets_elonmusk), length(tweets_mayoredlee))))

# Dividir los datos en conjuntos de entrenamiento y prueba (80% para entrenamiento, 20% para prueba)
split_index <- createDataPartition(datos_y, p = 0.8, list = FALSE)
X_train <- datos_X[split_index]
X_test <- datos_X[-split_index]
y_train <- datos_y[split_index]
y_test <- datos_y[-split_index]

Vectorización tf-idf

Empleando los tweets de entrenamiento se crea un matriz tf-idf en la que cada columna es un término, cada fila un documento y el valor de intersección el tf-idf correspondiente.

tfidf_vectorizador <- 
  DocumentTermMatrix(
    Corpus(VectorSource(X_train)),
    control = list(
      tokenizer = limpiar_tokenizar,
      stopwords = stop_words,
      bounds = list(global = c(3, Inf))
    )
  )

tfidf_train <- as.matrix(tfidf_vectorizador)
tfidf_test <- as.matrix(
  DocumentTermMatrix(
    Corpus(VectorSource(X_test)),
    control = list(
      tokenizer = limpiar_tokenizar,
      stopwords = stop_words,
      dictionary = Terms(tfidf_vectorizador)
    )
  )
)

Modelo SVM lineal

Como módelo de predicción se emplea un SVM. (Support Vector Machine).

# Establecer una semilla para reproducibilidad
set.seed(123)

# Entrenamiento del modelo SVM lineal con ajuste manual de hiperparámetros
# 'y_train': Etiquetas del conjunto de entrenamiento
# 'tfidf_train': Datos de entrenamiento en formato tf-idf (frecuencia de término - frecuencia de documento inversa)
modelo_svm_lineal <- svm(y = y_train, x = tfidf_train, kernel = "linear", cost = 2.154434690031882)

# Realizar predicciones en el conjunto de prueba utilizando el modelo SVM entrenado
predicciones_test <- predict(modelo_svm_lineal, newdata = tfidf_test)

# Imprimir la matriz de confusión para evaluar el modelo
print("Matriz de confusión")
print(table(y_test, predicciones_test))

# Calcular y mostrar el número de clasificaciones erróneas
print(paste("Número de clasificaciones erróneas de un total de", nrow(tfidf_test),
            "clasificaciones:", sum(y_test != predicciones_test)))

# Calcular y mostrar el porcentaje de error del modelo
print(paste("% de error:", 100 * mean(y_test != predicciones_test)))