0Pricing
R Academy · Aula

Análise de sentimentos em R

Combine tokens com léxicos de sentimentos para medir o tom positivo ou negativo.

Análise de sentimentos em R é uma aula grátis de R Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de R Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de R Academy inclui 4 aulas no total.

Visão geral da análise de sentimentos

A análise de sentimentos atribui uma valência emocional ao texto. A abordagem do tidytext compara palavras individuais com um léxico de sentimentos e agrega as pontuações. Há três léxicos integrados disponíveis: AFINN (pontuações numéricas), Bing (positivo/negativo) e NRC (categorias de emoções).

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')

O léxico AFINN atribui pontuações inteiras de −5 (muito negativo) a +5 (muito positivo) a 2.477 palavras em inglês. Ele foi compilado por Finn Årup Nielsen e funciona bem com textos de redes sociais e avaliações.

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')

O léxico Bing (Bing Liu e colaboradores) classifica 6.786 palavras como positivas ou negativas. Ele é maior que o AFINN e adequado para avaliações de produtos e comentários de clientes quando uma polaridade simples é suficiente.

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: Pontuando palavras

inner_join(tokens, afinn, by = 'word') mantém apenas os tokens que aparecem no léxico AFINN, acrescentando suas pontuações. As palavras que não estão no léxico são descartadas silenciosamente — isso é tanto uma vantagem (concentra-se em palavras de sentimento conhecidas) quanto uma limitação.

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')])

Sentimento líquido por documento

Some as pontuações AFINN por documento com group_by(document) |> summarise(sentiment = sum(value)) para obter uma pontuação de sentimento líquido. Somas positivas indicam um sentimento geral positivo; somas negativas indicam um sentimento 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)

Sentimento Bing: contagens positivas versus negativas

Com o léxico Bing, compare as contagens de palavras positivas e negativas por documento. Calcule sentiment = positive_n - negative_n para obter uma pontuação de polaridade líquida ou represente ambas as contagens como barras agrupadas para visualizar a composição.

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)

Sentimento por capítulo ou seção

Para acompanhar o sentimento ao longo do arco narrativo, calcule o sentimento líquido por capítulo ou em uma janela móvel. Isso revela a estrutura emocional: ação ascendente, clímax e resolução. Use ggplot2 com geom_line() ou geom_bar() para visualizar o 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: categorias de emoções

O léxico NRC (Saif Mohammad e Peter Turney) categoriza 13.901 palavras em oito emoções (raiva, expectativa, repulsa, medo, alegria, tristeza, surpresa e confiança), além de positivo/negativo. Filtre por emoção com 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()

Aplicando o NRC a um corpus

Associe o texto tokenizado ao NRC para pontuar cada emoção separadamente. Agregue por documento e emoção usando count(doc_id, sentiment) para ver quais emoções predominam em 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)

Conceito de nuvem de palavras

Uma nuvem de palavras visualiza as frequências das palavras como texto cujo tamanho é proporcional à contagem. Os pacotes wordcloud ou wordcloud2 as geram a partir de um quadro de dados de palavras/frequências. Dê cores às palavras de acordo com o sentimento usando o léxico Bing para criar uma nuvem colorida por sentimento.

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)

Limitações do sentimento baseado em léxico

A análise de sentimento baseada em léxico apresenta falhas conhecidas: negação ("não é bom" é pontuado como positivo), sarcasmo ("ah, ótimo, outro erro"), incompatibilidade de domínio ("sick" é positivo em gírias) e palavras fora do vocabulário. Considere essas limitações ao interpretar os 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')

Verificação rápida

Você usa inner_join(tokens, afinn, by = 'word') para pontuar o sentimento. O que acontece com as palavras presentes nos seus tokens que NÃO estão no léxico AFINN?

Recapitulação: análise de sentimento

Principais conclusões:

  • Três léxicos principais: AFINN (pontuações de −5 a +5), Bing (positivo/negativo) e NRC (8 emoções)
  • get_sentiments('afinn') / 'bing' / 'nrc' recupera o léxico como um tibble
  • inner_join(tokens, lexicon, by = 'word') pontua apenas as palavras correspondentes (as não correspondentes são descartadas)
  • Sentimento líquido = group_by(doc) |> summarise(sentiment = sum(value))
  • Bing: compare as contagens de palavras positive - negative por documento ou seção
  • NRC: filtre pelo nome da emoção para isolar medo, alegria, raiva etc.
  • Limitação principal: os métodos baseados em léxico não lidam com negação, sarcasmo ou gírias específicas do domínio
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()

Perguntas Frequentes

A aula “Análise de sentimentos em R” é grátis?

Sim — o texto completo de “Análise de sentimentos em R” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de R Academy, atualize para CoddyKit PRO. O curso de R Academy inclui 4 aulas no total.

O que vou aprender em “Análise de sentimentos em R”?

Combine tokens com léxicos de sentimentos para medir o tom positivo ou negativo. Você pratica R Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar R Academy?

Nenhuma experiência prévia é necessária. R Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Análise de sentimentos em R”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de R Academy?

Sim. Cada aula de R Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Tokenização e remoção de palavras irrelevantes
  2. TF-IDF e análise de frequência de termos
  3. Análise de sentimentos em R
  4. Modelagem de tópicos com LDA
← Voltar para R Academy