ANÁLISIS DE SENTIMIENTOS BANDA BON JOVI

Mineria de texto | Hernán Darío Vargas Molina | Universidad de la Salle

Especializacióin en Análisis Estadístico para Ciencia de Datos

Docente: MARTHA TATIANA PAMELA JIMENEZ VALDERRAMA

BON JOVI

BON JOVI

Introducción

El proyecto del curso será el análisis de sentimientos a las letras de canciones de la banda de rock Bon Jovi con más de 40 años de trayectoria, esto con el fin de observar los cambios en los sentimientos de sus composiciones a través de las décadas. Se utilizarán en su desarrollo las técnicas de Minería de Textos observadas en clase y como base bibliográfica el texto guía del curso -Minería de textos en R- (Silge & Robinson, 2017).

Pregunta de investigación

¿En qué medida el análisis de polaridad y emocional mediante minería de texto respalda la narrativa de ‘optimismo’ en la discografía de Bon Jovi, y cómo este ADN emocional ha influido en la vigencia de sus mayores éxitos?

Librerias

library(readxl)
library(dplyr)
library(quanteda)
library(quanteda.textstats)
library(ggplot2)
library(tidyr)
library(tidytext)
library(wordcloud) 
library(wordcloud2)
library(knitr)
library(scales)

Dataset de canciones de Bon Jovi

ds_bonjoviletras <- read_excel("BonJoviLetras.xlsx")

Exploración del dataset

summary(ds_bonjoviletras)
##     Álbum                Año          Década            Canción         
##  Length:268         Min.   :1984   Length:268         Length:268        
##  Class :character   1st Qu.:1992   Class :character   Class :character  
##  Mode  :character   Median :2000   Mode  :character   Mode  :character  
##                     Mean   :2001                                        
##                     3rd Qu.:2010                                        
##                     Max.   :2025                                        
##                                                                         
##     Letra           Escuchas_Spotify   
##  Length:268         Min.   :9.244e+05  
##  Class :character   1st Qu.:4.088e+06  
##  Mode  :character   Median :1.212e+07  
##                     Mean   :9.900e+07  
##                     3rd Qu.:3.845e+07  
##                     Max.   :2.234e+09  
##                     NA's   :151

Se tiene que el dataset que incluye la letra de 268 canciones, desde 1984 a 2025 con datos de spotify para 117 canciones con un mínimo de reproducciones de 924 mil, un máximo de 2.233 millones, promedio de 9.9 millones y una mediana de 12.12 millones (corte a 2 de mayo de 2026).

Este dataset tiene varias posibilidades de análisis textual, puede darse por título, década, álbum y canciones más reproducidas. Por lo tanto se hará un exploración inicial de sentimientos por los títulos de las canciones que se comparará luego con los resultados de análisis de sentimientos obtenidos para álbumes y décadas; y por ultimo se análizará el sentimiento de las 20 canciones más escuchadas en spotify

ANÁLISIS DE PRODUCCIÓN MUSICAL

Producción músical por año

# Conteo de canciones por año

composiciones_por_ano <- ds_bonjoviletras %>%
  filter(!is.na(Año)) %>%
  count(Año, name = "Total_Canciones")

composiciones_por_ano %>%
  ggplot(aes(x = Año, y = Total_Canciones)) +
  geom_col(fill = "navy", alpha = 0.8) +
  
  # Etiquetas
  
  geom_text(aes(label = Total_Canciones), vjust = -0.5, size = 3) +
  
  # Títulos
  
  labs(title = "Producción Musical de Bon Jovi",
       subtitle = "Cantidad de canciones registradas por año",
       x = "Año",
       y = "Número de Canciones") +
  
  # Ajustar el eje X a 5 años
  
  scale_x_continuous(breaks = seq(min(composiciones_por_ano$Año), 
                                  max(composiciones_por_ano$Año), 
                                  by = 5)) +
  
  # Diseño
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5))

Producción musical por década

# Conteo de canciones por década
canciones_por_decada <- ds_bonjoviletras %>%
  filter(!is.na(Década)) %>%
  
  # CONVERTIR A FACTOR: Forzar orden cronológico exacto
  mutate(Década = factor(Década, levels = c("80s", "90s", "00s", "10s", "20s"))) %>%
  
  # Contar canciones por década
  count(Década, name = "Total_Canciones")

# Gráfico
canciones_por_decada %>%
  ggplot(aes(x = Década, y = Total_Canciones, fill = Década)) +
  geom_col(show.legend = FALSE, alpha = 0.85) +
  
  # Etiquetas de barras
  geom_text(aes(label = Total_Canciones), vjust = -0.5, size = 4, fontface = "bold") +
  
  # Títulos
  labs(title = "Producción Musical de Bon Jovi por Década",
       subtitle = "Cantidad total de canciones registradas",
       x = "Década",
       y = "Número de Canciones") +
  
  # Diseño
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5))

El conteo de canciones por año y década evidencia que la etapa más prolífica de la banda ocurrió en los años 90. Posteriormente, se observa una clara adaptación a los cambios de la industria musical; a partir de la década de los 2000, con la disrupción de las descargas digitales (ej. Napster), el modelo de negocio migró de la venta de discos hacia la venta de experiencias en vivo. Esto explica la tendencia a la baja en la cantidad total de composiciones por década, manteniendo un patrón de publicación bianual o trianual donde los años sin registros corresponden a los extensos periodos de la banda realizando giras mundiales.

ANÁLISIS DE TÍTULOS DE CANCIONES

Títulos de canciones de BJ

Títulos de canciones de BJ

Primero se cargará el diccionarios de stopwords en inglés

data("stop_words")

En canciones suelen aparecer fonemas que se repiten por cuenta de rimas o estribillos que finalmente no aportan nada al análisis como “ah”, “yeah”, “na” por lo que deben ser incluidos en el stop_word

stopwords_ad <- tibble(
  word = c("yeah", "oh", "ohh", "ooh", "ah", "na", "hey", "la", "halle", "sha"), # Palabras adicionales
  lexicon = "personalizado"                 # Solo para identificarlas
  
)
stop_words_ampliado <- bind_rows(stop_words, stopwords_ad) #unión de stopwords

Tokenización de títulos

titulos_limpios <- ds_bonjoviletras %>%
  select(Canción) %>%                  # Seleccionar columna a tokenizar
  unnest_tokens(word, Canción) %>%     # Separ en palabras
  anti_join(stop_words_ampliado, by = "word")   # Eliminar stopwords

head(titulos_limpios)
## # A tibble: 6 × 1
##   word    
##   <chr>   
## 1 runaway 
## 2 roulette
## 3 shot    
## 4 heart   
## 5 love    
## 6 lies

Conteo de palabras en los títulos

conteo_palabras_titulos <- titulos_limpios %>%
  count(word, sort = TRUE)

head(conteo_palabras_titulos, 10)
## # A tibble: 10 × 2
##    word          n
##    <chr>     <int>
##  1 love         22
##  2 night        10
##  3 life          7
##  4 arms          5
##  5 living        5
##  6 beautiful     4
##  7 blood         4
##  8 die           4
##  9 heart         4
## 10 house         4
#Crear porcentajes a partir de frecuencias
conteo_palabras_titulos <- conteo_palabras_titulos %>%
  mutate(porcentaje = round((n / sum(n)) * 100, 2))

head(conteo_palabras_titulos)
## # A tibble: 6 × 3
##   word          n porcentaje
##   <chr>     <int>      <dbl>
## 1 love         22       5.39
## 2 night        10       2.45
## 3 life          7       1.72
## 4 arms          5       1.23
## 5 living        5       1.23
## 6 beautiful     4       0.98
conteo_palabras_titulos %>%
  slice_max(n, n = 10) %>%          
  mutate(word = reorder(word, n)) %>% 
  ggplot(aes(x = n, y = word)) +    
  geom_col(fill = "navy") + 
  geom_text(aes(label = paste0(n, " (", porcentaje, "%)")),  # combinar frecuncia y porcentaje en etiqueta
            hjust = -0.1, size = 4) + 
  expand_limits(x = max(conteo_palabras_titulos$n) * 1.15) + # Expandir eje X
  
  labs(title = "Palabras más frecuentes en los títulos de las canciones",
       x = "Frecuencia",
       y = "Palabra") +
  theme_minimal() + theme(plot.title = element_text(hjust=0.5,face="bold"))

Nube de palabras de los títulos

wordcloud(words = conteo_palabras_titulos$word,freq = conteo_palabras_titulos$n,max.words = 50,colors = brewer.pal(n = 8,"Dark2"),random.color = T,rot.per = 0.35,random.order = F)

Como exploración inicial del dataset, el análisis de los títulos ofrece un primer indicio sobre la polaridad de la banda. Las visualizaciones revelan que “love” es el término predominante absoluto (apareciendo en 22 canciones, doblando a la siguiente palabra más frecuente), el cual, junto a vocablos como “life” y “living”, sugiere una fuerte inclinación hacia emociones positivas. Sin embargo, la aparición de términos como “die” y “blood” introduce matices negativos pero que no son anómalos en el género musical. En conjunto, este vocabulario demuestra que Bon Jovi se enmarca claramente dentro de los tipos clásicos del hard rock, donde el amor, la vitalidad y la rebeldía son temáticas recurrentes.

Frecuencia de palabras por álbum

BON JOVI

BON JOVI

Tokenización y limpieza

albumes_bj <- ds_bonjoviletras %>%
  unnest_tokens(word, Letra) %>%
   anti_join(stop_words_ampliado, by = "word") %>%
count(Álbum, Año, word, sort = TRUE)

albumes_bj
## # A tibble: 10,187 × 4
##    Álbum               Año word      n
##    <chr>             <dbl> <chr> <int>
##  1 Slippery When Wet  1986 love     47
##  2 New Jersey         1988 baby     46
##  3 Keep the Faith     1992 love     43
##  4 Bon Jovi           1984 love     42
##  5 7800° Fahrenheit   1985 night    41
##  6 New Jersey         1988 love     41
##  7 7800° Fahrenheit   1985 fall     40
##  8 These Days         1995 love     38
##  9 2020               2020 love     35
## 10 Have a Nice Day    2005 gonna    35
## # ℹ 10,177 more rows
# Obtener un único año por álbum (por año de lanzamiento más antiguo)
album_años <- ds_bonjoviletras %>%
  group_by(Álbum) %>%
  summarise(Año_Lanzamiento = max(Año, na.rm = TRUE)) # -na.rm- para evitar errores con vacíos

# Conteo original SIN incluir el año para evitar fragmentar las frecuencias
albumes_bj <- ds_bonjoviletras %>%
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  count(Álbum, word, sort = TRUE) %>%
  
  # Unir el año al resultado final
  left_join(album_años, by = "Álbum")
# Gráfico de Frecuencia de Palabras por álbum
albumes_bj %>%
  filter(!is.na(Álbum)) %>%
  filter(!grepl("^[0-9]+$", word)) %>% 
  
  # Convertir 'Álbum' en factor ordenado por año
  mutate(Álbum = forcats::fct_reorder(Álbum, Año_Lanzamiento)) %>% 
  
  group_by(Álbum) %>% 
  slice_max(order_by = n, n = 4, with_ties = FALSE) %>% 
  
  # 2. Ordenar las palabras por frecuencia en cada álbum
  mutate(word = tidytext::reorder_within(word, n, Álbum)) %>% 
  
  ggplot(aes(x = word, y = n, fill = word)) +
  geom_col() +
  coord_flip() +
  
  tidytext::scale_x_reordered() + 
  
  facet_wrap(~Álbum, scales = "free_y") + 
  labs(title = "Letras del Álbum",
       subtitle = "Palabra más frecuente por Álbum (Orden Cronológico)",
       x = "Palabra",
       y = "Frecuencia") +
  
  theme_minimal() +
  theme(legend.position = "none")

El análisis de frecuencias evidencia que “love” se mantiene como el término transversal y predominante a lo largo de la mayor parte de la discografía. Las excepciones a esta regla coinciden de forma consistente con producciones de naturaleza conceptual o temática. Tal es el caso de Bounce, un álbum cuyo vocabulario refleja la influencia de los atentados del 11 de septiembre de 2001 y Young Guns II, una banda sonora del género western donde la lírica se adapta a la narrativa cinematográfica, destacando la aparición de “billy” como el segundo término más recurrente en clara referencia al forajido Billy the Kid.

Palabras más frecuentes en toda la discografía

# Generar la tabla de las 20 palabras más frecuentes
tabla_top_20 <- albumes_bj %>%
  group_by(word) %>%
  summarise(total = sum(n)) %>%
  slice_max(order_by = total, n = 20) %>%
  arrange(desc(total)) # Asegura el orden de mayor a menor

tabla_top_20
## # A tibble: 20 × 2
##    word    total
##    <chr>   <int>
##  1 love      562
##  2 night     279
##  3 gonna     276
##  4 baby      254
##  5 life      240
##  6 time      220
##  7 heart     158
##  8 live      158
##  9 world     152
## 10 tonight   139
## 11 home      134
## 12 wanna     129
## 13 day       127
## 14 eyes      127
## 15 hold      121
## 16 fall      119
## 17 left      118
## 18 run       118
## 19 die       113
## 20 feel      107
# Vectores de Top 20 de palabras para mapas

top_palabras_albumes <- albumes_bj %>%
  group_by(word) %>%
  summarise(total = sum(n)) %>%
  slice_max(order_by = total, n = 20) %>% 
  pull(word)
#Mapa de calor de palabras más frecuentes

albumes_bj %>%
  filter(!is.na(Álbum), word %in% top_palabras_albumes) %>%
  
  # Ordenar usando el año representativo
  mutate(Álbum = forcats::fct_reorder(Álbum, Año_Lanzamiento)) %>% 
  
  ggplot(aes(x = word, y = Álbum, fill = n)) + 
  geom_tile(color = "white", linewidth = 0.5) + 
  scale_fill_gradient(low = "white", high = "red") + 
  labs(title = "Distribución de las palabras más populares en BJ",
       subtitle = "Frecuencia por álbum (Orden cronológico)",
       x = "Palabra",
       y = "Álbum",
       fill = "Repeticiones") +
  theme_minimal() +
  theme(
    axis.text.y = element_text(size = 8),  
    axis.text.x = element_text(angle = 45, hjust = 1, size = 9),  
    panel.grid = element_blank()
  )

El mapa de calor revela una anomalía evidente en “100,000,000 Bon Jovi Fans Can’t Be Wrong”, el cual se visualiza como el álbum de mayor densidad (‘caliente’) para el vocabulario frecuente. No obstante, al tratarse de un recopilatorio de cuatro discos con material descartado, su volumen masivo de texto genera un sesgo predecible a su favor que debe aislarse del análisis temporal.

Descartando dicha anomalía, se observa un fenómeno interesante con ‘love’, la palabra más predominante de la discografía: su uso se ‘enfría’ notablemente en los años 2000 (desde Crush en el 2000 hasta What About Now en 2013), para luego retomar su preponderancia desde mediados de la década de los 2010.

Por otro lado, resalta el clúster formado por la palabra ‘gonna’, la cual presenta una alta incidencia aglomerada en Crush, Bounce, Have a Nice Day y The Circle. Este periodo (2000-2009) coincide con la adopción de narrativas marcadamente motivacionales por parte de la banda. Finalmente, a diferencia de los picos emocionales, palabras como ‘time’ exhiben una temperatura media pero constante a lo largo de los años, demostrando una regularidad estructural en casi todos los álbumes de su trayectoria.

Palabras más frecuentes por década

# Ajustar el orden de las décadas y contar las palabras
palabras_por_decada <- ds_bonjoviletras %>%
  filter(!is.na(Década)) %>%
  
  # CONVERTIR A FACTOR: forzando el orden cronológico exacto
  mutate(Década = factor(Década, levels = c("80s", "90s", "00s", "10s", "20s"))) %>%
  
  # Tokenizar y limpiar
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  filter(!grepl("^[0-9]+$", word)) %>%
  
  # Contar por década
  count(Década, word, sort = TRUE)

# Seleccionar el Top 10 por década y graficar
palabras_por_decada %>%
  group_by(Década) %>%
  slice_max(order_by = n, n = 10, with_ties = FALSE) %>% 
  
  # Ordenar cada década
  mutate(word = tidytext::reorder_within(word, n, Década)) %>% 
  
  # Graficar
  ggplot(aes(x = n, y = word, fill = Década)) +
  geom_col(show.legend = FALSE) + 
  tidytext::scale_y_reordered() + 
  
  # facet_wrap respetará el orden del factor definido
  facet_wrap(~ Década, scales = "free_y") + 
  
  labs(title = "Evolución de las letras de Bon Jovi",
       subtitle = "Top 10 de palabras más frecuentes por década",
       x = "Frecuencia",
       y = "Palabra") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5))

El análisis por décadas reafirma la supremacía del vocablo “love”, el cual lidera casi todos los periodos. La anomalía estadística más significativa ocurre en la década de los 2000, donde “gonna” y “life” desplazan a “love” al tercer puesto, validando la hipótesis de que este ciclo representó la etapa lírica más motivacional y enérgica de la agrupación.

Posteriormente, a partir de la década de los 10s, se observa un giro narrativo: el léxico se torna más introspectivo con la escalada de términos temporales (“time”, “day”) y espaciales/familiares (“home”, “house”), sugiriendo una transición hacia temáticas más íntimas y maduras en la etapa reciente de la banda.

ANÁLISIS DE SENTIMIENTOS

ANALISIS DE POLARIDAD CON BING

# Cargar el léxico y calcular polaridad
polaridad_decada <- ds_bonjoviletras %>%
  filter(!is.na(Década)) %>%
  
  # Forzar el orden cronológico desde el principio
  mutate(Década = factor(Década, levels = c("80s", "90s", "00s", "10s", "20s"))) %>%
  
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  
  # Unir con el diccionario BING
  inner_join(get_sentiments("bing"), by = "word") %>%
  
  # Contar palabras positivas y negativas por década
  count(Década, sentiment) %>%
  
  # Transformar los datos para poder restar positivo - negativo
  pivot_wider(names_from = sentiment, values_from = n, values_fill = 0) %>%
  mutate(Sentimiento_Neto = positive - negative)

# 2. Graficar la polaridad
polaridad_decada %>%
  ggplot(aes(x = Década, y = Sentimiento_Neto, fill = Sentimiento_Neto > 0)) +
  geom_col(show.legend = FALSE) +
  
  # Colores: Verde para positivo, Rojo para negativo
  scale_fill_manual(values = c("TRUE" = "seagreen", "FALSE" = "firebrick")) +
  
  labs(title = "Polaridad de Sentimiento en Bon Jovi por Década",
       subtitle = "Basado en el léxico BING (Positivo - Negativo)",
       x = "Década",
       y = "Sentimiento Neto") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5))

A primera vista, el gráfico de polaridad neta parece contradecir la narrativa histórica de Bon Jovi como una banda ‘optimista’. Sin embargo, este resultado contraintuitivo se explica por las limitaciones inherentes del léxico BING, el cual evalúa unigramas sin considerar el contexto. El algoritmo es incapaz de procesar metáforas o giros narrativos, como ocurre en Livin’ on a Prayer, donde la letra inicia describiendo tiempos difíciles (puntuando negativo) para culminar en un mensaje de esperanza y superación que el modelo no logra capturar en su suma final.

Más allá de esta limitación del algorítmo, el gráfico revela correctamente a los 90s como la década más ‘pesimista’ de su trayectoria. Este pico negativo coincide con la disrupción del movimiento Grunge, cuyas narrativas apáticas y de descontento obligaron a las bandas de hard rock a adaptarse para sobrevivir. Bon Jovi respondió a este cambio de la industria con álbumes de fuerte crítica social, como Keep The Faith y These Days, justificando el marcado descenso en la polaridad de sus composiciones.

Finalmente, desde una perspectiva estadística, es crucial señalar que la profundidad de la barra de los años 90 presenta un sesgo de volumen. Al tratarse de una métrica de sentimiento neto basada en frecuencias absolutas, esta década está sobrerrepresentada en el gráfico simplemente porque *corresponde a la etapa más prolífica de la banda+ en cuanto a cantidad de canciones publicadas.

Ánalisis de contribución de sentimiento lexico BING

# Calcular la frecuencia de palabras por sentimiento (BING)
contribucion_bing <- ds_bonjoviletras %>%
  # Tokenizar y limpiar
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  
  # Unir con BING
  inner_join(get_sentiments("bing"), by = "word") %>%
  
  # Contar la palabra y a qué sentimiento pertenece
  count(word, sentiment, sort = TRUE)

# Seleccionar el Top 10 por sentimiento y graficar
contribucion_bing %>%
  group_by(sentiment) %>%
  slice_max(order_by = n, n = 10, with_ties = FALSE) %>%
  
  # Ordenar las palabras dentro de cada faceta
  mutate(word = tidytext::reorder_within(word, n, sentiment)) %>%
  
  # Generar el gráfico
  ggplot(aes(x = n, y = word, fill = sentiment)) +
  geom_col(show.legend = FALSE, alpha = 0.9) +
  
  # etiquetas
  geom_text(aes(label = n), hjust = -0.1, size = 2.5, fontface = "bold") +
  
  # margen extra
  scale_x_continuous(expand = expansion(mult = c(0, 0.15))) +
  
  # Colores personalizados para mantener la consistencia
  scale_fill_manual(values = c("positive" = "seagreen", "negative" = "firebrick")) +
  
  # Limpiar la etiqueta de reorder_within
  tidytext::scale_y_reordered() +
  
  # Crear los dos recuadros separando por sentimiento
  facet_wrap(~ sentiment, scales = "free_y") +
  
  labs(title = "Palabras que más aportan al sentimiento en Bon Jovi",
       subtitle = "Top 10 de palabras positivas y negativas (Léxico BING)",
       x = "Frecuencia de aparición",
       y = "Palabra") +
  
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5),
        strip.text = element_text(face = "bold", size = 11)) # Resalta los títulos de los recuadros

Entre las palabras positivas y negativas es arrolladora la presencia de “love”. Esto hace que resulte aún más llamativo que el balance general del léxico BING sea negativo, aunque se explica por la variedad y acumulación del resto del vocabulario. A “love” le siguen de lejos “beautiful” y “faith”, cuya preponderancia puede estar fuertemente ligada al álbum conceptual Keep The Faith de 1992. Por el lado de las negativas, existe una frecuencia muy similar en el top 3 para “fall”, “die” y “hard”; vocablos que suelen aparecer en canciones atemporales del género para describir tiempos difíciles, sirviendo a menudo como preludios en letras de resiliencia y esperanza.

ANÁLISIS DE SENTIMIENTOS CON NRC

# Preparar datos con NRC
emociones_decada <- ds_bonjoviletras %>%
  filter(!is.na(Década)) %>%
  mutate(Década = factor(Década, levels = c("80s", "90s", "00s", "10s", "20s"))) %>%
  unnest_tokens(word, Letra) %>%
  
  # Unir con el diccionario NRC
  inner_join(get_sentiments("nrc"), by = "word") %>%
  
  # Filtrar para quitar "positive" y "negative" y dejar 8 emociones puras
  filter(!sentiment %in% c("positive", "negative")) %>%
  
  count(Década, sentiment) %>%
  
  # Calcular el porcentaje de cada emoción dentro de la década
  group_by(Década) %>%
  mutate(Porcentaje = n / sum(n)) %>%
  ungroup()
## Warning in inner_join(., get_sentiments("nrc"), by = "word"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 61 of `x` matches multiple rows in `y`.
## ℹ Row 12263 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
##   "many-to-many"` to silence this warning.
# Gráfico de líneas para ver tendencia de las emociones
emociones_decada %>%
  ggplot(aes(x = Década, y = Porcentaje, group = sentiment, color = sentiment)) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  
  # Separar por recuadros para que no se crucen las líneas
  facet_wrap(~ sentiment, ncol = 4) +
  
  # Formato de porcentaje en el eje Y
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  
  labs(title = "Evolución de las Emociones en las Letras de Bon Jovi",
       subtitle = "Léxico NRC: Proporción de emociones por década",
       x = "Década",
       y = "Proporción de palabras") +
  
  theme_minimal() +
  theme(legend.position = "none",
        plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5),
        axis.text.x = element_text(angle = 45, hjust = 1))

La evolución de las emociones por década mediante el léxico NRC da cuenta de una mayor injerencia de sentimientos positivos como “anticipation”, “joy” y “trust”, las cuales presentan claras tendencias al alza hacia las décadas más recientes. Por el contrario, los sentimientos negativos como “anger” y “fear” tienden a descender significativamente respecto a sus picos en los años 80. Finalmente, la tristeza (“sadness”) muestra una caída después de la primera década y posteriormente se estabiliza, manteniéndose en rangos medios y constantes durante el resto de la carrera musical.

Evolución temporal de emociones

# Calcular la proporción de cada sentimiento por AÑO
evolucion_anual <- ds_bonjoviletras %>%
  filter(!is.na(Año)) %>%
  
  # Tokenizar y limpiar
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  
  # Unir con el diccionario NRC
  inner_join(get_sentiments("nrc"), by = "word") %>%
  
  # Filtrar las 8 emociones base
  filter(!sentiment %in% c("positive", "negative")) %>%
  
  # Contar por año en lugar de década
  count(Año, sentiment) %>%
  
  # Calcular el porcentaje que representa cada emoción por año
  group_by(Año) %>%
  mutate(Porcentaje = n / sum(n)) %>%
  ungroup()
## Warning in inner_join(., get_sentiments("nrc"), by = "word"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 24 of `x` matches multiple rows in `y`.
## ℹ Row 12263 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
##   "many-to-many"` to silence this warning.
# Gráfico de serie de tiempo
evolucion_anual %>%
  ggplot(aes(x = Año, y = Porcentaje, color = sentiment)) +
  
  # Línea que conecta los puntos exactos año a año (transparencia)
  geom_line(alpha = 0.4, linewidth = 1) +
  geom_point(size = 1.5, alpha = 0.4) +
  
  # Línea de tendencia suave para ver el patrón general
  geom_smooth(method = "loess", se = FALSE, linewidth = 1.2, linetype = "solid") +
  
  # Separar cada emoción en su propio mini-gráfico
  facet_wrap(~ sentiment, ncol = 4) +
  
  # Formato del eje Y como porcentaje
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  
  # Ajustar el eje X para que no se amontonen los años
  scale_x_continuous(breaks = seq(min(evolucion_anual$Año, na.rm = TRUE), 
                                  max(evolucion_anual$Año, na.rm = TRUE), 
                                  by = 10)) +
  
  labs(title = "Evolución Anual de Emociones en Bon Jovi",
       subtitle = "Serie de tiempo con línea de tendencia (Léxico NRC)",
       x = "Año",
       y = "Proporción del vocabulario emocional") +
  
  theme_minimal() +
  theme(legend.position = "none",
        plot.title = element_text(hjust = 0.4, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5),
        strip.text = element_text(face = "bold"))
## `geom_smooth()` using formula = 'y ~ x'

# Análisis de la emoción "Sorpresa" en el álbum "Forever"
sorpresa_forever <- ds_bonjoviletras %>%
  # Filtrar específicamente el último álbum
  filter(Álbum == "Forever") %>%
  
  # Tokenizar y limpiar las letras
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  
  # Unir con el léxico NRC
  inner_join(get_sentiments("nrc"), by = "word") %>%
  
  # Aislar la emoción objetivo
  filter(sentiment == "surprise") %>%
  
  # Contar la frecuencia de aparición
  count(word, sort = TRUE)
## Warning in inner_join(., get_sentiments("nrc"), by = "word"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 2 of `x` matches multiple rows in `y`.
## ℹ Row 11374 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
##   "many-to-many"` to silence this warning.
print(sorpresa_forever)
## # A tibble: 14 × 2
##    word         n
##    <chr>    <int>
##  1 feeling      7
##  2 kiss         6
##  3 surprise     4
##  4 leave        3
##  5 sun          3
##  6 sweet        3
##  7 tree         3
##  8 hope         2
##  9 smile        2
## 10 catch        1
## 11 dawn         1
## 12 laugh        1
## 13 pray         1
## 14 trip         1

Al desglosar la serie de tiempo anual, se observan con mayor detalle las variaciones e inflexiones de las emociones a lo largo de la trayectoria de la banda. En este sentido, destacan los picos de la emoción fear (miedo), la cual experimenta un repunte notable en la última década coincidiendo con el álbum 2020; un trabajo donde se aborda vocabulario asociado a crisis globales como la pandemia, los tiroteos escolares en Estados Unidos y el estrés postraumático en veteranos de guerra.

Por otro lado, la faceta de surprise (sorpresa) exhibe su pico histórico más alto en el último lanzamiento de la banda (2024). Para el album Forever, esta métrica está fuertemente impulsada por el vocablo feeling, el cual domina la canción “Hollow Man”. No obstante, la obra aborda paradójicamente la falta de sorpresa de un individuo que ya lo ha vivido todo y se encuentra anestesiado, a la espera de un estímulo que le devuelva la capacidad de asombro; una metáfora directa al agotamiento del artista en su etapa madura tras alcanzar la cima de la industria. Esta contradicción evidencia que el algoritmo contabiliza el unigrama correctamente, pero es incapaz de capturar el aturdimiento emocional y la vulnerabilidad que subyacen en el contexto de la pieza musical.

Finalmente, a nivel visual, en la década de los 90s presenta el valor atípico más importante de todo el panel, disparando de forma aislada la emoción joy (alegría) por encima del 40% de proporción en el vocabulario. A continuación, se realizará un acercamiento a este punto específico del dataset para auditar los datos y verificar la causa matemática y contextual de este comportamiento anómalo.

Gráfico detallado de “Joy”

# Calcular proporciones y luego aislar "joy"
aislar_joy <- ds_bonjoviletras %>%
  filter(!is.na(Año)) %>%
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  
  # Unir con NRC y contar
  inner_join(get_sentiments("nrc"), by = "word") %>%
  filter(!sentiment %in% c("positive", "negative")) %>%
  count(Año, sentiment) %>%
  
  # Calcular el porcentaje de las emociones
  group_by(Año) %>%
  mutate(Porcentaje = n / sum(n)) %>%
  ungroup() %>%
  
  # Filtrar "joy"
  filter(sentiment == "joy")
## Warning in inner_join(., get_sentiments("nrc"), by = "word"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 24 of `x` matches multiple rows in `y`.
## ℹ Row 12263 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
##   "many-to-many"` to silence this warning.
# Generar el gráfico enfocado
aislar_joy %>%
  ggplot(aes(x = Año, y = Porcentaje)) +
  
  # Línea y puntos con colores para "alegría"
  geom_line(color = "#00BFC4", linewidth = 1, alpha = 0.8) +
  geom_point(color = "steelblue", size = 2.5) +
  
  # Línea de tendencia suavizada para ver el comportamiento
  geom_smooth(method = "loess", se = FALSE, color = "black", linetype = "dashed", linewidth = 0.8) +
  
  # Formato de ejes
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  scale_x_continuous(breaks = seq(min(aislar_joy$Año), max(aislar_joy$Año), by = 2)) + # Marcas cada 2 años para más precisión
  
  labs(title = "Evolución de la Alegría ('Joy') en Bon Jovi",
       subtitle = "Proporción de palabras de alegría frente al total emocional anual",
       x = "Año",
       y = "Porcentaje de 'Joy'") +
  
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
        plot.subtitle = element_text(hjust = 0.5),
        # Poner el eje X a 45 grados para evitar traslapos
        axis.text.x = element_text(angle = 45, hjust = 1))
## `geom_smooth()` using formula = 'y ~ x'

# Filtrar y mostrar las canciones del año 1991
canciones_1991 <- ds_bonjoviletras %>%
  filter(Año == 1991) %>%
  select(Canción, Álbum) %>%
  distinct() # distinct() asegura que no salgan repetidas

print(canciones_1991)
## # A tibble: 1 × 2
##   Canción                   Álbum                    
##   <chr>                     <chr>                    
## 1 If I Can't Have Your Love 100,000,000 Bon Jovi Fans
# Extraer las palabras que aportaron a "joy" en 1991
palabras_joy_1991 <- ds_bonjoviletras %>%
  filter(Año == 1991) %>%
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  inner_join(get_sentiments("nrc"), by = "word") %>%
  
  # Filtrar la emoción
  filter(sentiment == "joy") %>%
  count(word, sort = TRUE)
## Warning in inner_join(., get_sentiments("nrc"), by = "word"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 10 of `x` matches multiple rows in `y`.
## ℹ Row 967 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
##   "many-to-many"` to silence this warning.
# Ver el Top 10 de palabras alegres
head(palabras_joy_1991, 10)
## # A tibble: 3 × 2
##   word      n
##   <chr> <int>
## 1 baby      7
## 2 love      6
## 3 kiss      2

Al aislar los datos para investigar el valor atípico del año 1991, se descubre un problema estadístico de varianza por tamaño de muestra. En el dataset, la única canción registrada para ese año es If I Can’t Have Your Love (incluida posteriormente en el recopilatorio 100,000,000 Bon Jovi Fans Can’t Be Wrong). Al contar con una sola composición en ese periodo, cualquier repetición léxica sesga la proporción porcentual. En este caso, el algoritmo tomó vocablos recurrentes en la letra como baby, love y kiss y los clasificó como emociones de alegría.

No obstante, la revisión cualitativa revela un falso positivo semántico. Esta composición, interpretada a piano por el guitarrista Richie Sambora, aborda la vulnerabilidad y el miedo ante la hipotética pérdida de su pareja. Acá el léxico NRC lee literalmente la palabra baby (asociándola a la alegría literal de un bebé), ignorando el contexto del hard rock donde opera como un apelativo cariñoso. Este hallazgo plantea la pertinencia metodológica de incluir baby en el diccionario de stop-words personalizado; pero esta es una decisión en la que se debe ser cauteloso, toda vez que es un término recurrente en las power ballads del género, y su eliminación podría desvirtuar el peso real de las composiciones.

Gráfico detallado de anticipation

# Extraer las palabras que más aportaron a "anticipación" en una década específica
auditoria_anticipacion <- ds_bonjoviletras %>%
  # Cambia "10s" por la década que quieras revisar
  filter(Década == "10s") %>% 
  
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  inner_join(get_sentiments("nrc"), by = "word") %>%
  
  # Filtrar solo anticipación
  filter(sentiment == "anticipation") %>%
  count(word, sort = TRUE)
## Warning in inner_join(., get_sentiments("nrc"), by = "word"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 6 of `x` matches multiple rows in `y`.
## ℹ Row 7729 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
##   "many-to-many"` to silence this warning.
# Ver los resultados
head(auditoria_anticipacion, 10)
## # A tibble: 10 × 2
##    word         n
##    <chr>    <int>
##  1 time        50
##  2 tomorrow    23
##  3 coming      19
##  4 start       16
##  5 bless       12
##  6 god         12
##  7 kiss        12
##  8 hope        11
##  9 labor       11
## 10 alive        9
# Calcular proporciones y aislar "anticipation"
aislar_anticipation <- ds_bonjoviletras %>%
  filter(!is.na(Año)) %>%
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  
  # Unir con NRC y contar
  inner_join(get_sentiments("nrc"), by = "word") %>%
  filter(!sentiment %in% c("positive", "negative")) %>%
  count(Año, sentiment) %>%
  
  # Calcular el porcentaje de todas las emociones primero
  group_by(Año) %>%
  mutate(Porcentaje = n / sum(n)) %>%
  ungroup() %>%
  
  # Filtrar exclusivamente "anticipation"
  filter(sentiment == "anticipation")
## Warning in inner_join(., get_sentiments("nrc"), by = "word"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 24 of `x` matches multiple rows in `y`.
## ℹ Row 12263 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
##   "many-to-many"` to silence this warning.
# Gráfico enfocado
aislar_anticipation %>%
  ggplot(aes(x = Año, y = Porcentaje)) +
  
  # Línea y puntos con colores
  geom_line(color = "#CD9600", linewidth = 1, alpha = 0.8) +
  geom_point(color = "darkorange", size = 2.5) +
  
  # Línea de tendencia suavizada para ver el comportamiento
  geom_smooth(method = "loess", se = FALSE, color = "black", linetype = "dashed", linewidth = 0.8) +
  
  # Formato de ejes
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  scale_x_continuous(breaks = seq(min(aislar_joy$Año), max(aislar_joy$Año), by = 2)) + # Marcas cada 2 años para más precisión
  
  # Textos
  labs(title = "Evolución de la Expectativa ('Anticipation') en Bon Jovi",
       subtitle = "Proporción de palabras de expectativa frente al total emocional anual",
       x = "Año",
       y = "Porcentaje de 'Anticipation'") +
  
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
        plot.subtitle = element_text(hjust = 0.5),
        # Poner el eje X a 45 grados para que los años no se pisen si hay muchos
        axis.text.x = element_text(angle = 45, hjust = 1))
## `geom_smooth()` using formula = 'y ~ x'

El análisis aislado de la emoción anticipation evidencia una clara tendencia al alza a lo largo de la carrera musical, destacándose un pico máximo entre los años 2016 y 2018. Para la interpretación semántica de este periodo resulta fundamental el contexto del álbum This House Is Not For Sale (2016). Este fue el primer trabajo de estudio sin la presencia del guitarrista Richie Sambora (quien abandonó la agrupación en 2013) y coincidió con el inminente término contractual con su sello discográfico histórico.

Esta notable ausencia y la incertidumbre contractual influyeron directamente en las composiciones, dotándolas de un fuerte tono de expectativa frente al futuro de la banda. En este caso, el léxico NRC logra capturar la emoción de manera precisa, reflejando el espíritu de un álbum enfocado en la resistencia, la resiliencia y la firme convicción de continuar con el legado a pesar de los cambios abruptos.

El TOP con léxico NCR

# Calcular la frecuencia de palabras para 3 emociones específicas (NRC)
top_nrc <- ds_bonjoviletras %>%
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  inner_join(get_sentiments("nrc"), by = "word") %>%
  
  # FILTRO 3 emociones más relevantes
  filter(sentiment %in% c("joy", "anticipation", "anger")) %>%
  
  # Contar la palabra y la emoción
  count(word, sentiment, sort = TRUE)
## Warning in inner_join(., get_sentiments("nrc"), by = "word"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 24 of `x` matches multiple rows in `y`.
## ℹ Row 12263 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
##   "many-to-many"` to silence this warning.
# Seleccionar el Top 10 por emoción y graficar
top_nrc %>%
  group_by(sentiment) %>%
  slice_max(order_by = n, n = 10, with_ties = FALSE) %>%
  
  # Ordenar las palabras dentro de cada faceta
  mutate(word = tidytext::reorder_within(word, n, sentiment)) %>%
  
  # Generar el gráfico
  ggplot(aes(x = n, y = word, fill = sentiment)) +
  geom_col(show.legend = FALSE, alpha = 0.9) +
  
  # Colores personalizados para cada emoción
  scale_fill_manual(values = c("joy" = "#00BFC4", 
                               "anticipation" = "#CD9600", 
                               "anger" = "#F8766D")) +
  
  # Limpiar la etiqueta de reorder_within
  tidytext::scale_y_reordered() +
  
  # Crear los recuadros y traducir títulos con labeller
  facet_wrap(~ sentiment, scales = "free_y", 
             labeller = as_labeller(c("joy" = "Alegría (Joy)", 
                                      "anticipation" = "Anticipación", 
                                      "anger" = "Ira (Anger)"))) +
  
  labs(title = "ADN del Vocabulario Emocional en Bon Jovi",
       subtitle = "Top 10 de palabras que más aportan a emociones clave (Léxico NRC)",
       x = "Frecuencia de aparición",
       y = "Palabra") +
  
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5),
        strip.text = element_text(face = "bold", size = 11))

ANALISIS DE SENTIMIENTOS CRUZADO CON REPRODUCCIONES EN SPOTIFY

BON JOVI

BON JOVI

# Calcular el sentimiento neto por cada CANCIÓN
sentimiento_Escuchas_Spotify <- ds_bonjoviletras %>%
  
  # Filtrar solo las canciones que tienen datos de Spotify
  filter(!is.na(Escuchas_Spotify)) %>% 
  
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  inner_join(get_sentiments("bing"), by = "word") %>%
  
  # Contar positivos y negativos por canción
  count(Canción, Escuchas_Spotify, sentiment) %>%
  pivot_wider(names_from = sentiment, values_from = n, values_fill = 0) %>%
  mutate(Sentimiento_Neto = positive - negative)

# Generar el gráfico de dispersión
sentimiento_Escuchas_Spotify %>%
  ggplot(aes(x = Sentimiento_Neto, y = Escuchas_Spotify)) +
  
  # Dibujar los puntos (canciones) coloreados según su polaridad
  geom_point(aes(color = Sentimiento_Neto > 0), size = 3, alpha = 0.7) +
  
  # Línea de tendencia lineal para ver la correlación general
  geom_smooth(method = "lm", color = "black", linetype = "dashed", se = FALSE) +
  
  # Ponerle el nombre a las canciones más extremas para idendivualizarlas
  geom_text(aes(label = Canción), vjust = -1, size = 3, check_overlap = TRUE) +
  
  scale_color_manual(values = c("TRUE" = "seagreen", "FALSE" = "firebrick"),
                     labels = c("TRUE" = "Positiva", "FALSE" = "Negativa")) +
  
  labs(title = "Relación entre Sentimiento y Éxito en Spotify",
       subtitle = "Polaridad BING vs. Número de Escuchas_Spotify",
       x = "Sentimiento Neto (Positivo - Negativo)",
       y = "Escuchas en Spotify",
       color = "Polaridad") +
  
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5),
        legend.position = "bottom")
## `geom_smooth()` using formula = 'y ~ x'

El análisis de dispersión entre la polaridad y el éxito comercial en Spotify revela que el mayor éxito histórico de la banda posee un tinte positivo: Livin’ on a Prayer domina la métrica por un amplio margen, superando los 2.000 millones de reproducciones. En el rango medio-alto (entre 1.000 y 1.600 millones de escuchas) se ubican temas como You Give Love a Bad Name y Always, los cuales presentan una clasificación de polaridad negativa.

La gran masa del corpus musical se concentra por debajo de la barrera de los 500 millones de reproducciones, una zona donde coexisten de manera densa canciones de valencias tanto positivas como negativas. La pendiente casi plana de la línea de tendencia, sugiere una nula correlación entre el sentimiento asignado por el algoritmo y el volumen de consumo de los oyentes. Como se ha expuesto previamente, el léxico BING presenta limitaciones para capturar las metáforas y el contexto del hard rock. Por consiguiente, para validar la precisión del modelo frente a la realidad de las letras, se procederá a aislar el Top 15 de los mayores éxitos comerciales y se realizará una auditoría cualitativa que determine el nivel de acierto real en la polaridad de cada tema.

# Tomar los datos calculadosy extraer el Top 15
top_hits_spotify <- sentimiento_Escuchas_Spotify %>%
  arrange(desc(Escuchas_Spotify)) %>% # Ordenar de mayor a menor éxito
  slice_head(n = 15) # las 15 más escuchadas

# 2. Graficar el Top 15 coloreado por sentimiento
top_hits_spotify %>%
  
  # Ordenar las barras de mayor a menor para que el gráfico se vea escalonado
  mutate(Canción = forcats::fct_reorder(Canción, Escuchas_Spotify)) %>%
  
  ggplot(aes(x = Canción, y = Escuchas_Spotify, fill = Sentimiento_Neto > 0)) +
  geom_col(alpha = 0.9, color = "black", linewidth = 0.2) +
  
  # Voltear el gráfico para leer bien los nombres de las canciones
  coord_flip() +
  
  # Etiquetas de texto con el número exacto del sentimiento neto
  geom_text(aes(label = paste("Sentimiento:", Sentimiento_Neto)), 
            hjust = 1.1, color = "white", size = 3.5, fontface = "bold") +
  
  scale_fill_manual(values = c("TRUE" = "seagreen", "FALSE" = "firebrick"),
                    labels = c("TRUE" = "Neta Positiva", "FALSE" = "Neta Negativa")) +
  
  labs(title = "ADN Emocional de los 15 Mayores Éxitos de Bon Jovi",
       subtitle = "Escuchas_Spotify en Spotify coloreadas por Polaridad (BING)",
       x = "Canción",
       y = "Escuchas_Spotify",
       fill = "Polaridad de la Letra") +
  
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5),
        legend.position = "bottom")

Al realizar la evaluación cualitativa del Top 15 de mayores éxitos en Spotify, se evidencia que, a nivel general, el léxico BING logra una aproximación acertada a la polaridad de las canciones. No obstante, al auditar detalladamente los resultados, emergen tres contradicciones algorítmicas de relevancia: En primer lugar, destaca el caso de It’s My Life, catalogada con un sentimiento neto negativo (-1) pese a poseer una lírica de naturaleza profundamente motivacional y de autoafirmación. Irónicamente, este mensaje fue precisamente el motor que impulsó su éxito masivo en el año 2000, permitiendo a Bon Jovi mantenerse en la cima del mainstream mientras otras agrupaciones del género desaparecían.

Una segunda anomalía se observa con Blaze of Glory. El modelo la clasifica positivamente (+6), ignorando por completo la narrativa del texto: una composición que relata la fatalidad inminente y la posibilidad de morir en un duelo de armas del viejo oeste.

Finalmente, el sesgo algorítmico más drástico se presenta con Bad Medicine, una composición eminentemente festiva del álbum New Jersey que recibe el puntaje negativo más severo de la muestra (-33). Acá el algoritmo resta puntos repetidamente por cada aparición del unigrama ‘bad’ en el estribillo, siendo incapaz de detectar que el vocablo que es un eufemismo de tiente sensual, una metáfora donde lo ‘malo’ describe, en realidad, una atracción física adictiva y pasional que escapa a la comprensión del lexico BING.

Emociónes por canciones más escuchadas

# Identificar el Top 15 de canciones más escuchadas
top_15_canciones <- ds_bonjoviletras %>%
  filter(!is.na(Escuchas_Spotify)) %>%
  select(Canción, Escuchas_Spotify) %>%
  distinct() %>%
  arrange(desc(Escuchas_Spotify)) %>%
  slice_head(n = 15)

# Calcular la emoción dominante para este Top 15
emocion_dominante_top <- ds_bonjoviletras %>%
  filter(Canción %in% top_15_canciones$Canción) %>%
  unnest_tokens(word, Letra) %>%
  anti_join(stop_words_ampliado, by = "word") %>%
  inner_join(get_sentiments("nrc"), by = "word") %>%
  
  # Filtrar las 3 emociones de interés
  filter(sentiment %in% c("joy", "anticipation", "anger")) %>%
  
  # Contar cuántas palabras hay de cada emoción por canción
  count(Canción, sentiment) %>%
  
  # Agrupar la emoción con valor más alto (n) para cada canción
  group_by(Canción) %>%
  slice_max(order_by = n, n = 1, with_ties = FALSE) %>% 
  ungroup() %>%
  rename(Emocion_Dominante = sentiment)
## Warning in inner_join(., get_sentiments("nrc"), by = "word"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 24 of `x` matches multiple rows in `y`.
## ℹ Row 12263 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
##   "many-to-many"` to silence this warning.
# Unir los datos de Spotify con la emoción dominante y graficar
top_15_canciones %>%
  left_join(emocion_dominante_top, by = "Canción") %>%
  
  # Si no es alguna d elas 3 emociones poner "Otra"
  mutate(Emocion_Dominante = replace_na(Emocion_Dominante, "Otra")) %>%
  
  # Ordenar de las barras por reproducciones
  mutate(Canción = forcats::fct_reorder(Canción, Escuchas_Spotify)) %>%
  
  ggplot(aes(x = Canción, y = Escuchas_Spotify, fill = Emocion_Dominante)) +
  geom_col(alpha = 0.9, color = "white", linewidth = 0.2) +
  coord_flip() +
  
# Agregar las etiquetas de texto acotadas en millones
  geom_text(aes(label = paste0(round(Escuchas_Spotify / 1e6, 0), " M")), 
            hjust = -0.1,  # Desplaza el texto ligeramente a la derecha de la barra
            size = 2, 
            color = "black")+
  
  # Formatear el eje inferior y expandir el límite derecho para que el texto no se corte
  scale_y_continuous(labels = comma, expansion(mult = c(0, 0.2))) +
  
  # Personalizar los colores y las etiquetas de la leyenda
  scale_fill_manual(values = c("joy" = "#00BFC4", 
                               "anticipation" = "#CD9600", 
                               "anger" = "#F8766D",
                               "Otra" = "grey70"),
                    labels = c("joy" = "Alegría", 
                               "anticipation" = "Anticipación", 
                               "anger" = "Ira",
                               "Otra" = "Otra emoción")) +
  
  labs(title = "ADN Emocional de los 15 Mayores Éxitos de Bon Jovi",
       subtitle = "Color según la emoción dominante (Alegría, Anticipación o Ira)",
       x = "Canción",
       y = "Total de Escuchas en Spotify",
       fill = "Emoción Dominante") +
  
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5),
        legend.position = "bottom")

El análisis mediante el léxico NRC demuestra ser cualitativamente más preciso que la métrica unidimensional de BING. Al evaluar tres emociones específicas en la discografía (ira, expectativa y alegría), se hace notoria la abrumadora predominancia de una valencia positiva, consolidando a la alegría (joy) como la emoción dominante en el Top de mayores éxitos en Spotify. A diferencia del modelo anterior, NRC logra clasificar correctamente a It’s My Life dentro de este sentimiento, capturando al fin su esencia motivacional. No obstante, persiste el sesgo del algoritmo para Bad Medicine, la cual vuelve a ser penalizada y etiquetada bajo la emoción de ira (anger).

Por su parte, la expectativa (anticipation) es menos frecuente y rige como emoción principal en dos éxitos puntuales. En Wanted Dead or Alive, este resultado es coherente y parece estar anclado al vocablo wanted, un unigrama del estribillo que hace referencia a la búsqueda de un personaje forajido que destaca sobre la multitud. Sin embargo, en el caso de Runaway, se detecta un desfase semántico del algoritmo. La conexión con la expectativa resulta difusa frente a una narrativa lírica que aborda el abandono parental y la huida de una joven hacia el mundo de la noche. Este caso particular sugiere que ciertas palabras de acción ligadas al escape pueden engañar al léxico al ser extraídas de su contexto original

CONCLUSIONES

Frente a la hipótesis planteada, el análisis de polaridad unidimensional (léxico BING) sugiere que Bon Jovi no es una banda de naturaleza positiva ni optimista, arrojando una valencia neta negativa para todas las décadas. Sin embargo, como se evidenció durante el estudio, este comportamiento obedece a que dicho léxico evalúa unigramas de forma aislada, siendo incapaz de captar adecuadamente las figuras retóricas, las metáforas y el contexto literario que otorgan el verdadero sentido a las composiciones del género.

Por otro lado, la aproximación facetada mediante el léxico NRC revela una realidad analítica distinta. Este modelo evidencia efectivamente una mayor prevalencia de emociones con valencia positiva; la alta frecuencia de palabras asociadas a la alegría, la expectativa y la confianza validan sólidamente la hipótesis inicial y el autoconcepto de “banda optimista” que destaca su líder, Jon Bon Jovi.

Respecto al análisis de frecuencias en títulos y líricas, se establece inequívocamente que el término más utilizado en toda la discografía es love. Este dominio absoluto solo fue desplazado por vocablos como gonna y life durante la década de los 2000, un periodo en el cual la agrupación presentó mensajes marcadamente motivacionales de manera reiterada, impulsados en gran medida por el éxito comercial masivo que supuso el lanzamiento de la canción It’s My Life.

Al cruzar la clasificación emocional con las métricas de éxito comercial, se concluye que el algoritmo logra una precisión considerable al identificar el sentimiento general de las pistas más populares. Asimismo, los datos confirman que las composiciones donde predomina la “alegría” generan un mayor impacto y volumen de escucha entre la audiencia global de la banda en Spotify.

A nivel general, el presente ejercicio demuestra que las técnicas de minería de textos sí lograron capturar la esencia del ADN musical de la agrupación, permitiendo incluso establecer claras conexiones con el contexto sociocultural de lanzamientos específicos evaluados puntualmente. No obstante, se advierte que para alcanzar un análisis analítico superior, resultaría imperativo construir un léxico de sentimientos y un diccionario de stop-words especializados y entrenados específicamente para este género musical.

Finalmente, las metodologías implementadas a lo largo de este proyecto constituyen una base para futuras investigaciones. Expandir este análisis textual mediante la integración de variables acústicas estructurales —como el tono, el ritmo, las melodías y la interpretación vocal— permitiría el desarrollo de modelos pedictivos complejos orientados a la analítica musical y la proyección de éxito comercial.

REFERENCIAS BIBLIOGRÁFICAS

Letras.com. (s.f.). Jon Bon Jovi - Discografía. Recuperado el 28 de abril de 2026, de https://www.letras.com/jon-bon-jovi/discografia/

Piqueras, R. (30 de septiembre de 2020). Jon Bon Jovi: “La piedra angular de la música de Bon Jovi siempre ha sido el optimismo”. RockFM. https://www.rockfm.fm/al-dia/noticias/jon-bon-jovi-piedra-angular-musica-bon-jovi-siempre-sido-optimismo-20200930_919524

Silge, J., & Robinson, D. (2017). Text mining with R: A tidy approach. O’Reilly Media. https://www.tidytextmining.com/

Spotify. (s.f.). Resultados de búsqueda para “bon jovi”. Recuperado el 2 de mayo de 2026, de https://open.spotify.com/search/bon%20jovi