Análisis de sentimientos en R
Una los tokens con léxicos de sentimientos para medir el tono positivo o negativo.
Análisis de sentimientos en R es una lección gratuita de R Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de R Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de R Academy incluye 4 lecciones en total.
Descripción general del análisis de sentimientos
El análisis de sentimientos asigna una valencia emocional al texto. El enfoque de tidytext compara palabras individuales con un léxico de sentimientos y agrega las puntuaciones. Hay tres léxicos integrados disponibles: AFINN (puntuaciones numéricas), Bing (positivo/negativo) y NRC (categorías emocionales).
library(tidytext)
# Available sentiment lexicons
# AFINN: -5 to +5 numeric score
# Bing: binary positive/negative
# NRC: emotion categories (joy, fear, anger, ...)
# Preview AFINN
afinn_sample <- get_sentiments('afinn')
cat('AFINN rows:', nrow(afinn_sample), '\n')
cat('Score range:', range(afinn_sample$value), '\n')
print(head(afinn_sample, 5))get_sentiments('afinn')
El léxico AFINN asigna puntuaciones enteras de −5 (muy negativo) a +5 (muy positivo) a 2.477 palabras en inglés. Fue compilado por Finn Årup Nielsen y funciona bien con textos de redes sociales y reseñas.
library(tidytext)
library(dplyr)
afinn <- get_sentiments('afinn')
# Most positive and most negative words
cat('Most positive words:\n')
print(afinn |> slice_max(value, n = 5))
cat('\nMost negative words:\n')
print(afinn |> slice_min(value, n = 5))
# Score distribution
cat('\nScore distribution:\n')
print(table(afinn$value))get_sentiments('bing')
El léxico Bing (de Bing Liu y otros autores) clasifica 6.786 palabras como positivas o negativas. Es más extenso que AFINN y resulta adecuado para reseñas de productos y comentarios de clientes cuando basta con una polaridad sencilla.
library(tidytext)
library(dplyr)
bing <- get_sentiments('bing')
cat('Bing lexicon size:', nrow(bing), '\n')
cat('Positive words:', sum(bing$sentiment == 'positive'), '\n')
cat('Negative words:', sum(bing$sentiment == 'negative'), '\n')
# Sample positive and negative words
cat('\nSample positive:', head(bing$word[bing$sentiment == 'positive'], 8), '\n')
cat('Sample negative:', head(bing$word[bing$sentiment == 'negative'], 8), '\n')inner_join: Puntuación de palabras
inner_join(tokens, afinn, by = 'word') conserva únicamente los tokens que aparecen en el léxico AFINN y añade sus puntuaciones. Las palabras que no están en el léxico se descartan silenciosamente; esto es tanto una ventaja (se centra en palabras con sentimiento conocido) como una limitación.
library(tidytext)
library(dplyr)
reviews <- tibble::tibble(
review_id = 1:3,
text = c(
'The product is excellent and outstanding quality',
'Terrible experience, broken and disappointing',
'Good value but slow delivery, acceptable overall'
)
)
scored <- reviews |>
unnest_tokens(word, text) |>
inner_join(get_sentiments('afinn'), by = 'word')
cat('Scored words:\n')
print(scored[, c('review_id', 'word', 'value')])Sentimiento neto por documento
Sume las puntuaciones de AFINN por documento con group_by(document) |> summarise(sentiment = sum(value)) para obtener una puntuación de sentimiento neto. Las sumas positivas indican un sentimiento general positivo; las negativas indican un sentimiento negativo.
library(tidytext)
library(dplyr)
reviews <- tibble::tibble(
review_id = 1:5,
text = c(
'excellent outstanding perfect love best amazing',
'terrible broken horrible awful waste money',
'good acceptable okay decent average',
'brilliant fantastic outstanding love recommend',
'poor bad disappointing slow useless'
)
)
net_sentiment <- reviews |>
unnest_tokens(word, text) |>
inner_join(get_sentiments('afinn'), by = 'word') |>
group_by(review_id) |>
summarise(
sentiment = sum(value),
word_count = n()
) |>
mutate(polarity = ifelse(sentiment > 0, 'positive', 'negative'))
print(net_sentiment)Sentimiento de Bing: recuentos de positivos y negativos
Con el léxico de Bing, compare el recuento de palabras positivas y negativas por documento. Calcule sentiment = positive_n - negative_n para obtener una puntuación de polaridad neta, o represente ambos recuentos como barras agrupadas para observar su composición.
library(tidytext)
library(dplyr)
corpus <- tibble::tibble(
chapter = 1:4,
text = c(
'the hero was brave courageous strong and victorious in battle',
'disaster struck terrible losses failure defeat mourning grief',
'love joy happiness beautiful peaceful wonderful morning',
'evil darkness corrupt wicked terrible pain suffering fear'
)
)
bing_sentiment <- corpus |>
unnest_tokens(word, text) |>
inner_join(get_sentiments('bing'), by = 'word') |>
count(chapter, sentiment) |>
tidyr::pivot_wider(names_from = sentiment, values_from = n, values_fill = 0) |>
mutate(net = positive - negative)
print(bing_sentiment)Sentimiento por capítulo o sección
Para seguir el sentimiento a lo largo del arco narrativo, calcule el sentimiento neto por capítulo o mediante una ventana móvil. Esto revela la estructura emocional: ascenso de la acción, clímax y desenlace. Use ggplot2 con geom_line() o geom_bar() para visualizar el arco.
library(tidytext)
library(dplyr)
library(ggplot2)
# Simulate a 10-chapter story arc
set.seed(42)
chapters <- tibble::tibble(
chapter = 1:10,
text = c(
'peaceful beautiful joy love happy wonderful',
'good friends happy carefree enjoyable fun',
'worried anxious trouble fear uncertain dark',
'danger terrible threat awful pain suffering',
'fear horror disaster terrible devastation loss',
'fight battle struggle hard difficult challenge',
'hope courage determination brave strong resist',
'triumph victory success celebrate joy love',
'relief peace gratitude wonderful blessed happy',
'love joy peace beautiful grateful wonderful'
)
)
arc <- chapters |>
unnest_tokens(word, text) |>
inner_join(get_sentiments('afinn'), by = 'word') |>
group_by(chapter) |>
summarise(net_sentiment = sum(value))
ggplot(arc, aes(chapter, net_sentiment)) +
geom_line(color = 'steelblue', linewidth = 1.2) +
geom_hline(yintercept = 0, linetype = 'dashed') +
labs(x = 'Chapter', y = 'Net Sentiment', title = 'Story Sentiment Arc') +
theme_minimal()Léxico NRC: categorías de emociones
El léxico NRC (Saif Mohammad y Peter Turney) clasifica 13.901 palabras en ocho emociones (ira, anticipación, asco, miedo, alegría, tristeza, sorpresa y confianza), además de positivo/negativo. Filtre por emoción con filter(sentiment == 'joy').
library(tidytext)
library(dplyr)
nrc <- get_sentiments('nrc')
cat('NRC size:', nrow(nrc), '\n')
cat('Emotions:', paste(unique(nrc$sentiment), collapse = ', '), '\n')
# Words associated with 'joy'
joy_words <- nrc |> filter(sentiment == 'joy')
cat('\nJoy words:', nrow(joy_words), '\n')
cat('Sample:', head(joy_words$word, 10), '\n')
# Count words per emotion
nrc |>
count(sentiment, sort = TRUE) |>
print()Aplicar NRC a un corpus
Una el texto tokenizado con NRC para puntuar cada emoción por separado. Agrupe por documento y emoción usando count(doc_id, sentiment) para ver qué emociones predominan en cada documento.
library(tidytext)
library(dplyr)
docs <- tibble::tibble(
doc_id = c(1, 1, 2, 2, 3, 3),
text = c(
'wonderful joyful happy love peace',
'excited surprise anticipation trust',
'fear anger terrible hate disgust',
'dark horrible awful suffering pain',
'curious wonder discovery learning',
'hope trust anticipation future growth'
)
)
nrc_scores <- docs |>
unnest_tokens(word, text) |>
inner_join(get_sentiments('nrc'), by = 'word') |>
filter(!sentiment %in% c('positive', 'negative')) |> # keep only emotions
count(doc_id, sentiment, sort = TRUE)
cat('Emotion counts per document:\n')
print(nrc_scores)Concepto de nube de palabras
Una wordcloud visualiza las frecuencias de las palabras mostrando el texto con un tamaño proporcional al recuento. Los paquetes wordcloud o wordcloud2 las generan a partir de un data frame de palabras y frecuencias. Coloree las palabras según su sentimiento usando el léxico de Bing para crear una nube coloreada por sentimiento.
library(tidytext)
library(dplyr)
# Prepare word frequencies coloured by Bing sentiment
corpus_text <- tibble::tibble(
text = c(
'excellent performance amazing results love beautiful',
'terrible failure poor broken horrible waste',
'brilliant outstanding success happy wonderful joy',
'awful disappointing bad slow useless frustrating'
)
)
word_freq <- corpus_text |>
unnest_tokens(word, text) |>
count(word, sort = TRUE) |>
left_join(get_sentiments('bing'), by = 'word') |>
mutate(
sentiment = replace(sentiment, is.na(sentiment), 'neutral'),
colour = case_when(
sentiment == 'positive' ~ '#2196F3',
sentiment == 'negative' ~ '#F44336',
TRUE ~ '#9E9E9E'
)
)
print(word_freq)
# In practice: wordcloud2(word_freq[, c('word','n')], color = word_freq$colour)Limitaciones del análisis de sentimiento basado en léxicos
El análisis de sentimiento basado en léxicos presenta fallos conocidos: negación ("not good" se puntúa como positivo), sarcasmo ("oh great, another bug"), desajuste de dominio ("sick" es positivo en la jerga) y palabras fuera del vocabulario. Tenga en cuenta estas limitaciones al interpretar los resultados.
library(tidytext)
library(dplyr)
# Negation problem
neg_examples <- tibble::tibble(
text = c(
'not good at all', # negative, but 'good' scores +3
'not bad', # positive, but 'bad' scores -3
'sick beats bro' # slang positive, 'sick' is negative in AFINN
)
)
scored <- neg_examples |>
unnest_tokens(word, text) |>
inner_join(get_sentiments('afinn'), by = 'word')
cat('Lexicon scores (naive - ignores negation):\n')
print(scored[, c('word', 'value')])
cat('\nNote: "not" is a stop word - the negation is lost!\n')Comprobación rápida
Utiliza inner_join(tokens, afinn, by = 'word') para puntuar el sentimiento. ¿Qué ocurre con las palabras de sus tokens que NO están en el léxico AFINN?
Resumen: análisis de sentimiento
Ideas clave:
- Tres léxicos principales: AFINN (puntuaciones de −5 a +5), Bing (positivo/negativo) y NRC (8 emociones)
get_sentiments('afinn')/'bing'/'nrc'recupera el léxico como un tibbleinner_join(tokens, lexicon, by = 'word')puntúa únicamente las palabras coincidentes (las que no coinciden se descartan)- Sentimiento neto =
group_by(doc) |> summarise(sentiment = sum(value)) - Bing: compare los recuentos de palabras
positive - negativepor documento o sección - NRC: filtre por el nombre de la emoción para aislar miedo, alegría, ira, etc.
- Limitación principal: los métodos basados en léxicos no gestionan la negación, el sarcasmo ni la jerga específica del dominio
library(tidytext)
library(dplyr)
tibble::tibble(text = 'excellent amazing love joy beautiful happy') |>
unnest_tokens(word, text) |>
inner_join(get_sentiments('afinn'), by = 'word') |>
summarise(net_sentiment = sum(value)) |>
print()Preguntas frecuentes
¿La lección «Análisis de sentimientos en R» es gratis?
Sí — el texto completo de «Análisis de sentimientos en R» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de R Academy, actualiza a CoddyKit PRO. El curso de R Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Análisis de sentimientos en R»?
Una los tokens con léxicos de sentimientos para medir el tono positivo o negativo. Practicas R Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar R Academy?
No se requiere experiencia previa. R Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Análisis de sentimientos en R»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de R Academy?
Sí. Cada lección de R Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Tokenización y eliminación de palabras vacías
- TF-IDF y análisis de frecuencia de términos
- Análisis de sentimientos en R
- Modelado de temas con LDA