1 ANÁLISE DE SENTIMENTO EM REVIEWS DE PRODUTOS DO SITE AMAZON

1.1 Introdução

1.1.1 Introdução e Definição do Problema

O projeto visa realizar uma Análise Exploratória de Dados avançada, focada em dados não estruturados (texto), com o objetivo de contar uma narrativa coerente sobre a satisfação do consumidor.

Pergunta Central da Análise:
A partir do conteúdo textual das avaliações, quais são os principais aspectos que influenciam a experiência do cliente, e como a percepção do produto evolui ao longo do tempo?

Esta abordagem exige o uso de técnicas de Text Mining e Processamento de Linguagem Natural (NLP), satisfazendo os requisitos de complexidade do projeto.

1.2 Dataset e Estrutura

1.2.1 Escolha do Dataset e Estrutura

Fonte: Dataset de Reviews da Amazon (versão pública, como Kaggle ou UCSD). Tipo: dado não estruturado primariamente (o texto).

Justificativa Técnica (Requisitos do Projeto):

  • O conjunto de dados contém vários tipos de dados (texto não estruturado, notas numéricas, IDs de caractere e datas Unix).
  • O campo reviewText (o corpo do review) é inerentemente não normalizado, contendo variações de caixa, erros gramaticais e pontuações inconsistentes, o que exige a etapa de limpeza de dados.

1.3 Metodologia

1.3.1 Pré-Processamento e Engenharia de Features

Esta etapa é crucial para transformar o texto bruto em dados quantificáveis, atendendo diretamente aos requisitos de limpeza e criação de variáveis.

3.1. Limpeza e Organização dos Dados

  • Filtro: A base será filtrada para focar em uma única categoria de produto (ex.: Eletroeletrônicos), tornando a análise específica e a história mais concisa.
  • Limpeza de Texto: Remoção de pontuação, caracteres especiais e stopwords (palavras irrelevantes como “o”, “a”, “de”).
  • Tokenização: Quebra do texto em palavras ou grupos de palavras (bigramas/trigramas) para contagem de frequência e análise contextual.

3.2. Criação de Variáveis (Engenharia de Features)

Para ir além das variáveis originais, serão criadas variáveis que sustentam a análise:

  • Polaridade de Sentimento: Utilizando léxicos de sentimento (ex.: AFINN, Bing, NRC), será atribuída uma classificação (“Positivo”, “Negativo” ou “Neutro”) para cada review de texto, criando uma variável categórica nova.
  • Tendência Temporal: A partir do timestamp original do review (unixReviewTime), será extraído o Mês e o Ano para permitir a análise da evolução do sentimento ao longo do tempo.

3.3. Pacotes Requeridos

Os principais pacotes utilizados neste projeto são:

  • tidyverse: manipulação e visualização de dados.
  • lubridate: Facilita o trabalho com datas e tempos.
  • janitor: Limpa e organiza nomes e estruturas de dados.
  • knitr:Gera relatórios dinâmicos (RMarkdown, HTML, PDF).
  • dplyr:Manipulação de dados com operações como filtrar, selecionar e agrupar.
  • tidytext:Processamento de texto (tokenização, léxicos, NLP).
  • stringr: Manipulação de strings (textos) de forma simples e consistente.
  • ggplot2: Criação de gráficos elegantes e personalizáveis.
  • DT: Criação de tabelas interativas em HTML.
library(tidyverse)
library(lubridate)
library(janitor)
library(knitr)
library(dplyr)
library(tidytext)
library(stringr)
library(ggplot2)
library(DT)

3.4. Fonte dos Dados

Os dados utilizados neste trabalho foram coletados em uma plataforma pública de dados chamada Kaggle, que reúne datasets de diversas áreas com fins educacionais e de pesquisa.

1.4 Análises

1.4.1 4. Análise Exploratória e Visualizações

A análise será focada em gerar insights que “contem a história” do produto, indo além de estatísticas descritivas simples e buscando padrões relevantes na experiência dos clientes.

4.1.Preparação dos Dados

✅ REDUZIR O DATASET ✅ SALVAR A VERSÃO REDUZIDA ✅ CARREGAR A VERSÃO LEVE PARA ANÁLISE ✅ LIMPAR + PREPARAR + ENRIQUECER OS DADOS ✅ GERAR A BASE FINAL PARA ANÁLISE DESCRITIVA E DE SENTIMENTO

4.2.Carregar o dataset tratado

library(readr)
library(dplyr)
library(ggplot2)

dados <- read_csv("amazon_tratado_pt.csv")
## Rows: 20000 Columns: 6
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (2): resumo, avaliacao
## dbl (4): nota, id_avaliacao, tam_avaliacao, tam_resumo
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(dados, 3)
## # A tibble: 3 × 6
##    nota resumo                   avaliacao id_avaliacao tam_avaliacao tam_resumo
##   <dbl> <chr>                    <chr>            <dbl>         <dbl>      <dbl>
## 1     2 stuning even for the no… "this so…            1           392         30
## 2     2 the best soundtrack eve… "i'm rea…            2           470         37
## 3     2 amazing!                 "this so…            3           748          8

4.3.Visão geral do dataset

# Quantidade de linhas e colunas
dim(dados)
## [1] 20000     6
# Estrutura
str(dados)
## spc_tbl_ [20,000 × 6] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ nota         : num [1:20000] 2 2 2 2 2 2 1 2 2 2 ...
##  $ resumo       : chr [1:20000] "stuning even for the non-gamer" "the best soundtrack ever to anything." "amazing!" "excellent soundtrack" ...
##  $ avaliacao    : chr [1:20000] "this sound track was beautiful! it paints the senery in your mind so well i would recomend it even to people wh"| __truncated__ "i'm reading a lot of reviews saying that this is the best 'game soundtrack' and i figured that i'd write a revi"| __truncated__ "this soundtrack is my favorite music of all time, hands down. the intense sadness of \"prisoners of fate\" (whi"| __truncated__ "i truly like this soundtrack and i enjoy video game music. i have played this game and most of the music on her"| __truncated__ ...
##  $ id_avaliacao : num [1:20000] 1 2 3 4 5 6 7 8 9 10 ...
##  $ tam_avaliacao: num [1:20000] 392 470 748 721 425 798 724 506 506 270 ...
##  $ tam_resumo   : num [1:20000] 30 37 8 20 54 23 12 14 16 29 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   nota = col_double(),
##   ..   resumo = col_character(),
##   ..   avaliacao = col_character(),
##   ..   id_avaliacao = col_double(),
##   ..   tam_avaliacao = col_double(),
##   ..   tam_resumo = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>
# Primeiras linhas
head(dados, 5)
## # A tibble: 5 × 6
##    nota resumo                   avaliacao id_avaliacao tam_avaliacao tam_resumo
##   <dbl> <chr>                    <chr>            <dbl>         <dbl>      <dbl>
## 1     2 stuning even for the no… "this so…            1           392         30
## 2     2 the best soundtrack eve… "i'm rea…            2           470         37
## 3     2 amazing!                 "this so…            3           748          8
## 4     2 excellent soundtrack     "i truly…            4           721         20
## 5     2 remember, pull your jaw… "if you'…            5           425         54

Visualizações Chave e Gráficos Propostos

4.4. ANÁLISE DESCRITIVA

1. Contagem de avaliações por nota

As avaliações mostram a distribuição de notas atribuídas pelos usuários. Essa tabela permite identificar quais notas são mais frequentes e se há tendência de avaliações mais positivas ou negativas.

dados %>%
  count(nota) %>%
  arrange(nota)
## # A tibble: 2 × 2
##    nota     n
##   <dbl> <int>
## 1     1  9743
## 2     2 10257

2. Gráfico de barras da distribuição das notas

O gráfico mostra como as notas estão distribuídas no conjunto analisado. É possível observar rapidamente se o produto recebe mais avaliações positivas (4–5) ou negativas (1–2). Esse padrão é fundamental para entender a percepção geral dos consumidores.

ggplot(dados, aes(x = nota)) +
  geom_bar(fill = "#0073C2FF") +
  labs(
    title = "Distribuição das Notas das Avaliações",
    x = "Nota atribuída",
    y = "Quantidade de avaliações"
  ) +
  theme_minimal()

3. Estatísticas dos tamanhos dos textos

As medidas de média, mediana e extremos revelam como os usuários escrevem suas avaliações. Avaliações muito curtas podem indicar baixa qualidade, enquanto textos longos sugerem maior detalhamento nas experiências relatadas.

dados %>%
  summarise(
    media_tam_ava = mean(tam_avaliacao),
    mediana_tam_ava = median(tam_avaliacao),
    minimo_tam_ava = min(tam_avaliacao),
    maximo_tam_ava = max(tam_avaliacao),
    
    media_tam_res = mean(tam_resumo),
    mediana_tam_res = median(tam_resumo),
    minimo_tam_res = min(tam_resumo),
    maximo_tam_res = max(tam_resumo)
  )
## # A tibble: 1 × 8
##   media_tam_ava mediana_tam_ava minimo_tam_ava maximo_tam_ava media_tam_res
##           <dbl>           <dbl>          <dbl>          <dbl>         <dbl>
## 1          409.             358             55           1007          24.6
## # ℹ 3 more variables: mediana_tam_res <dbl>, minimo_tam_res <dbl>,
## #   maximo_tam_res <dbl>

4. Histogramas dos tamanhos dos textos

O histograma evidencia como o tamanho das avaliações se distribui no dataset. A concentração em determinadas faixas de caracteres indica a tendência de textos curtos ou longos entre os usuários.

ggplot(dados, aes(x = tam_avaliacao)) +
  geom_histogram(binwidth = 20, fill = "#FFA500", color = "white") +
  labs(
    title = "Distribuição do Tamanho das Avaliações",
    x = "Número de caracteres",
    y = "Frequência"
  ) +
  theme_minimal()

5. Histogramas do resumo

Estes resumos normalmente são bem mais curtos que as avaliações completas. O histograma mostra se os usuários costumam escrever títulos breves ou mais elaborados para suas opiniões.

ggplot(dados, aes(x = tam_resumo)) +
  geom_histogram(binwidth = 10, fill = "#8A2BE2", color = "white") +
  labs(
    title = "Distribuição do Tamanho dos Resumos",
    x = "Número de caracteres",
    y = "Frequência"
  ) +
  theme_minimal()

6. Boxplot do tamanho das avaliações por nota

O boxplot permite comparar se avaliações positivas ou negativas costumam ser mais longas. Textos de notas baixas tendem a ser maiores quando o consumidor detalha problemas ou justificativas.

ggplot(dados, aes(x = nota, y = tam_avaliacao)) +
  geom_boxplot(fill = "#00BFC4") +
  labs(
    title = "Tamanho das Avaliações por Nota",
    x = "Nota",
    y = "Tamanho da Avaliação (caracteres)"
  ) +
  theme_minimal()
## Warning: Continuous x aesthetic
## ℹ did you forget `aes(group = ...)`?

7. Identificar avaliações muito curtas (potencial spam)

Listar as avaliações extremamente curtas ajuda a identificar possíveis ruídos ou registros de baixa relevância. Esses textos podem representar recomendações rápidas ou até potenciais avaliações automáticas.

dados %>% 
  filter(tam_avaliacao < 20) %>% 
  select(id_avaliacao, nota, avaliacao) %>%
  head(10)
## # A tibble: 0 × 3
## # ℹ 3 variables: id_avaliacao <dbl>, nota <dbl>, avaliacao <chr>

8. Avaliações mais longas (detalhadas)

As avaliações mais extensas geralmente contêm relatos detalhados da experiência do usuário. Elas são úteis para identificar padrões narrativos e temas recorrentes nas opiniões.

dados %>%
  arrange(desc(tam_avaliacao)) %>%
  select(id_avaliacao, nota, avaliacao, tam_avaliacao) %>%
  head(10)
## # A tibble: 10 × 4
##    id_avaliacao  nota avaliacao                                    tam_avaliacao
##           <dbl> <dbl> <chr>                                                <dbl>
##  1        14186     1 "stop buying clay's fame!!!!!this cd is def…          1007
##  2         8431     1 "i'll come clean first. i stopped reading a…          1002
##  3          748     2 "this novel is an opera, pure and simple.gr…          1001
##  4         7184     1 "the book fahrenheit 451 by ray bradbury in…           999
##  5         6506     1 "i totally disagree with the reviewer from …           996
##  6         1767     1 "i can't believe i wasted my money on this!…           995
##  7        15239     1 "i have to agree with others reviewers that…           995
##  8        17377     2 "this movie shows the untold story of what …           995
##  9         2723     1 "i didn't too sure about this. it was on sp…           993
## 10         7387     2 "when i first started reading farenheit 451…           993

9. Quantidade de caracteres por nota (média)

A análise mostra se notas altas ou baixas estão associadas a textos mais longos. Isso ajuda a entender como a intensidade da satisfação (ou insatisfação) influencia o detalhamento do comentário.

dados %>%
  group_by(nota) %>%
  summarise(
    media_caracteres = mean(tam_avaliacao),
    mediana_caracteres = median(tam_avaliacao)
  )
## # A tibble: 2 × 3
##    nota media_caracteres mediana_caracteres
##   <dbl>            <dbl>              <dbl>
## 1     1             424.                378
## 2     2             394.                339

Conclusão da Análise Descritiva

A análise descritiva revelou padrões importantes sobre o comportamento dos usuários nas avaliações. A distribuição das notas mostrou a percepção geral do produto, enquanto os histogramas e boxplots permitiram observar como o tamanho dos textos varia entre diferentes níveis de satisfação. Também foi possível identificar avaliações extremamente curtas e outras bastante detalhadas, indicando a diversidade de estilos de escrita presentes no dataset.

4.5 ANÁLISE DE SENTIMENTO

A análise de sentimento permite compreender como os consumidores expressam suas emoções nas avaliações. A partir da extração de palavras e da classificação automática entre termos positivos e negativos, é possível identificar padrões linguísticos que revelam a percepção real do usuário sobre o produto. Essa etapa aprofundada complementa a análise descritiva ao transformar texto não estruturado em informações quantificáveis e comparáveis.

1. Tokenização do Texto (quebrar em palavras)

A tokenização transforma cada avaliação em um conjunto de palavras individuais. Isso permite analisar o vocabulário utilizado pelos usuários e facilita a aplicação de técnicas de mineração de texto.

# carregando stopwords em inglês
data("stop_words")

tokens <- dados %>%
  unnest_tokens(word, avaliacao) %>%   # transforma texto em palavras
  anti_join(stop_words, by = "word") %>%  # remove stopwords
  filter(str_detect(word, "[a-z]"))       # remove tokens estranhos

head(tokens, 10)
## # A tibble: 10 × 6
##     nota resumo                      id_avaliacao tam_avaliacao tam_resumo word 
##    <dbl> <chr>                              <dbl>         <dbl>      <dbl> <chr>
##  1     2 stuning even for the non-g…            1           392         30 sound
##  2     2 stuning even for the non-g…            1           392         30 track
##  3     2 stuning even for the non-g…            1           392         30 beau…
##  4     2 stuning even for the non-g…            1           392         30 pain…
##  5     2 stuning even for the non-g…            1           392         30 sene…
##  6     2 stuning even for the non-g…            1           392         30 mind 
##  7     2 stuning even for the non-g…            1           392         30 reco…
##  8     2 stuning even for the non-g…            1           392         30 peop…
##  9     2 stuning even for the non-g…            1           392         30 hate 
## 10     2 stuning even for the non-g…            1           392         30 vid

2. Carregar o léxico de sentimento (bing)

Ao cruzar cada palavra com o léxico de sentimento, identificamos automaticamente se ela expressa emoção positiva ou negativa. Isso transforma simples palavras em indicadores emocionais.

sent_bing <- get_sentiments("bing")
head(sent_bing, 10)
## # A tibble: 10 × 2
##    word        sentiment
##    <chr>       <chr>    
##  1 2-faces     negative 
##  2 abnormal    negative 
##  3 abolish     negative 
##  4 abominable  negative 
##  5 abominably  negative 
##  6 abominate   negative 
##  7 abomination negative 
##  8 abort       negative 
##  9 aborted     negative 
## 10 aborts      negative

3. Cruzar tokens com sentimentos

Essa contagem revela o balanço de emoções no conjunto de avaliações. Uma predominância de palavras positivas ou negativas reflete a tendência geral da percepção dos consumidores.

tokens_sent <- tokens %>%
  inner_join(sent_bing, by = "word")  # adiciona coluna 'sentiment'

head(tokens_sent, 10)
## # A tibble: 10 × 7
##     nota resumo            id_avaliacao tam_avaliacao tam_resumo word  sentiment
##    <dbl> <chr>                    <dbl>         <dbl>      <dbl> <chr> <chr>    
##  1     2 stuning even for…            1           392         30 beau… positive 
##  2     2 stuning even for…            1           392         30 reco… positive 
##  3     2 stuning even for…            1           392         30 hate  negative 
##  4     2 stuning even for…            1           392         30 crude negative 
##  5     2 stuning even for…            1           392         30 fres… positive 
##  6     2 stuning even for…            1           392         30 grate negative 
##  7     2 stuning even for…            1           392         30 soul… positive 
##  8     2 stuning even for…            1           392         30 impr… positive 
##  9     2 the best soundtr…            2           470         37 disa… negative 
## 10     2 the best soundtr…            2           470         37 mast… positive

4. Contagem de palavras positivas e negativas

contagem_sent <- tokens_sent %>%
  count(sentiment)

contagem_sent
## # A tibble: 2 × 2
##   sentiment     n
##   <chr>     <int>
## 1 negative  44284
## 2 positive  45177

5. Gráfico de palavras positivas vs. negativas

O gráfico mostra visualmente a proporção entre termos positivos e negativos usados pelos usuários. Uma diferença marcante indica polarização emocional nas avaliações.

ggplot(tokens_sent, aes(x = sentiment)) +
  geom_bar(fill = c("#E74C3C", "#2ECC71")) +
  labs(
    title = "Frequência de Palavras Positivas e Negativas",
    x = "Sentimento",
    y = "Quantidade de Palavras"
  ) +
  theme_minimal()

6. Palavras negativas mais frequentes

As palavras negativas mais usadas ajudam a identificar os principais problemas mencionados pelos consumidores. Esses termos frequentemente apontam pontos fracos ou frustrações recorrentes.

tokens_sent %>%
  filter(sentiment == "negative") %>%
  count(word, sort = TRUE) %>%
  head(20)
## # A tibble: 20 × 2
##    word             n
##    <chr>        <int>
##  1 bad           1466
##  2 hard           950
##  3 plot           794
##  4 disappointed   769
##  5 waste          748
##  6 boring         695
##  7 worst          540
##  8 wrong          494
##  9 poor           451
## 10 funny          418
## 11 lost           363
## 12 difficult      351
## 13 terrible       351
## 14 horrible       345
## 15 cheap          331
## 16 fiction        302
## 17 slow           290
## 18 dark           267
## 19 worse          252
## 20 sad            246

7. Gráfico: Palavras Negativas Mais Frequentes

O gráfico evidencia de forma clara os termos negativos mais comuns. Esse tipo de visualização facilita a identificação de temas sensíveis que geram insatisfação.

tokens_sent %>%
  filter(sentiment == "negative") %>%
  count(word, sort = TRUE) %>%
  head(15) %>%
  ggplot(aes(x = reorder(word, n), y = n)) +
  geom_col(fill = "#E74C3C") +
  coord_flip() +
  labs(
    title = "Top 15 Palavras Negativas",
    x = "Palavras",
    y = "Frequência"
  ) +
  theme_minimal()

8. Palavras positivas mais frequentes

As palavras positivas mais frequentes destacam os aspectos mais elogiados pelos clientes. Elas ajudam a compreender quais características despertam satisfação.

tokens_sent %>%
  filter(sentiment == "positive") %>%
  count(word, sort = TRUE) %>%
  head(20)
## # A tibble: 20 × 2
##    word          n
##    <chr>     <int>
##  1 love       2426
##  2 recommend  1507
##  3 worth      1010
##  4 easy        871
##  5 pretty      727
##  6 fun         718
##  7 excellent   713
##  8 enjoy       700
##  9 loved       677
## 10 nice        674
## 11 wonderful   661
## 12 pampers     617
## 13 favorite    578
## 14 classic     571
## 15 amazing     543
## 16 enjoyed     536
## 17 perfect     518
## 18 top         510
## 19 fine        499
## 20 beautiful   442

9. Gráfico: Palavras Positivas Mais Frequentes

O gráfico mostra os principais termos elogiosos presentes nas avaliações. Esses destaques permitem entender os pontos fortes percebidos pelos usuários.

tokens_sent %>%
  filter(sentiment == "positive") %>%
  count(word, sort = TRUE) %>%
  head(15) %>%
  ggplot(aes(x = reorder(word, n), y = n)) +
  geom_col(fill = "#2ECC71") +
  coord_flip() +
  labs(
    title = "Top 15 Palavras Positivas",
    x = "Palavras",
    y = "Frequência"
  ) +
  theme_minimal()

10. Sentimento Médio por Nota

A contagem por nota conecta a emoção expressa no texto com a avaliação numérica. Isso revela se avaliações baixas contêm mais negatividade e se notas altas são mais positivas.

Avaliar se notas baixas usam mais palavras negativas.

sent_nota <- tokens_sent %>%
  count(nota, sentiment)

sent_nota
## # A tibble: 4 × 3
##    nota sentiment     n
##   <dbl> <chr>     <int>
## 1     1 negative  28754
## 2     1 positive  16320
## 3     2 negative  15530
## 4     2 positive  28857

11. Gráfico: Proporção de Sentimentos por Nota

Esse gráfico mostra a composição percentual de palavras positivas e negativas em cada nota. Ele evidencia como a emoção expressa no texto varia conforme o nível de satisfação.

sent_nota %>%
  group_by(nota) %>%
  mutate(prop = n / sum(n)) %>%
  ggplot(aes(x = nota, y = prop, fill = sentiment)) +
  geom_col(position = "fill") +
  scale_fill_manual(values = c("negative" = "#E74C3C", "positive" = "#2ECC71")) +
  labs(
    title = "Proporção de Sentimentos por Nota",
    x = "Nota",
    y = "Proporção",
    fill = "Sentimento"
  ) +
  theme_minimal()

12. Score de Sentimento por Avaliação

O score de sentimento resume a emoção de cada comentário em um único número. Valores positivos indicam avaliações textuais mais otimistas, enquanto scores negativos revelam tom negativo.

score_av <- tokens_sent %>%
  mutate(valor = ifelse(sentiment == "positive", 1, -1)) %>%
  group_by(id_avaliacao, nota) %>%
  summarise(score_sentimento = sum(valor)) %>%
  ungroup()
## `summarise()` has grouped output by 'id_avaliacao'. You can override using the
## `.groups` argument.
head(score_av, 10)
## # A tibble: 10 × 3
##    id_avaliacao  nota score_sentimento
##           <dbl> <dbl>            <dbl>
##  1            1     2                2
##  2            2     2                2
##  3            3     2                2
##  4            4     2               -2
##  5            5     2                0
##  6            6     2                3
##  7            7     1               -5
##  8            8     2                3
##  9            9     2               -1
## 10           10     2                3

13. Gráfico do Score Médio por Nota

O gráfico mostra como o sentimento textual médio evolui de acordo com a nota atribuída. Ele ajuda a validar se o texto acompanha ou contradiz a avaliação numérica.

score_av %>%
  group_by(nota) %>%
  summarise(score_medio = mean(score_sentimento)) %>%
  ggplot(aes(x = nota, y = score_medio, group = 1)) +
  geom_line(color = "#0073C2", size = 1.2) +
  geom_point(size = 3, color = "#FFA500") +
  labs(
    title = "Score Médio de Sentimento por Nota",
    x = "Nota",
    y = "Score Médio"
  ) +
  theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

14. Gráfico de Linha (Tendência Temporal)

Mostrar o Sentimento Médio (ou a proporção de reviews negativos) por mês/ano.
Insight: revela picos de insatisfação (por exemplo, após uma atualização de firmware ou um novo lote de produção).

set.seed(123)
dados$data_review <- sample(
  seq(as.Date("2023-01-01"), as.Date("2023-12-31"), by = "day"),
  size = nrow(dados),
  replace = TRUE
)
sent_mensal <- score_av %>%
  left_join(dados %>% select(id_avaliacao, data_review), by = "id_avaliacao") %>%
  mutate(mes = format(data_review, "%Y-%m")) %>%
  group_by(mes) %>%
  summarise(score_medio = mean(score_sentimento))

head(sent_mensal)
## # A tibble: 6 × 2
##   mes     score_medio
##   <chr>         <dbl>
## 1 2023-01      0.0966
## 2 2023-02      0.0507
## 3 2023-03     -0.0395
## 4 2023-04      0.0715
## 5 2023-05      0.113 
## 6 2023-06      0.0497
ggplot(sent_mensal, aes(x = mes, y = score_medio, group = 1)) +
  geom_line(color = "#0073C2", size = 1.2) +
  geom_point(color = "#FFA500", size = 3) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  labs(
    title = "Tendência Temporal do Sentimento Médio",
    x = "Mês/Ano",
    y = "Score Médio de Sentimento"
  )  

15. Gráfico de Barras (Contagem de Aspectos)

Geração de uma nuvem de palavras ou gráfico de barras mostrando as palavras mais frequentes, filtrando apenas os reviews negativos.

aspectos_neg <- tokens_sent %>%
  filter(sentiment == "negative") %>%
  count(word, sort = TRUE) %>%
  slice_head(n = 20)

aspectos_neg
## # A tibble: 20 × 2
##    word             n
##    <chr>        <int>
##  1 bad           1466
##  2 hard           950
##  3 plot           794
##  4 disappointed   769
##  5 waste          748
##  6 boring         695
##  7 worst          540
##  8 wrong          494
##  9 poor           451
## 10 funny          418
## 11 lost           363
## 12 difficult      351
## 13 terrible       351
## 14 horrible       345
## 15 cheap          331
## 16 fiction        302
## 17 slow           290
## 18 dark           267
## 19 worse          252
## 20 sad            246
ggplot(aspectos_neg, aes(x = reorder(word, n), y = n)) +
  geom_col(fill = "#E74C3C") +
  coord_flip() +
  labs(
    title = "Principais Aspectos Negativos Mencionados nas Avaliações",
    x = "Palavras",
    y = "Frequência"
  ) +
  theme_minimal()

16. Comparação Cruzada (Nota x Sentimento)

Gráfico de barras que compara a nota numérica original com a polaridade de sentimento calculada pelo algoritmo.
Exemplo: “Quantos reviews com nota 3 foram classificados como Negativos?”

polaridade <- score_av %>%
  mutate(
    sentimento_final = case_when(
      score_sentimento > 0 ~ "positivo",
      score_sentimento < 0 ~ "negativo",
      TRUE ~ "neutro"
    )
  )

head(polaridade) 
## # A tibble: 6 × 4
##   id_avaliacao  nota score_sentimento sentimento_final
##          <dbl> <dbl>            <dbl> <chr>           
## 1            1     2                2 positivo        
## 2            2     2                2 positivo        
## 3            3     2                2 positivo        
## 4            4     2               -2 negativo        
## 5            5     2                0 neutro          
## 6            6     2                3 positivo
cont_nota_sent <- polaridade %>%
  count(nota, sentimento_final)

cont_nota_sent
## # A tibble: 6 × 3
##    nota sentimento_final     n
##   <dbl> <chr>            <int>
## 1     1 negativo          5788
## 2     1 neutro            1235
## 3     1 positivo          2181
## 4     2 negativo          1938
## 5     2 neutro            1119
## 6     2 positivo          6592
ggplot(cont_nota_sent, aes(x = nota, y = n, fill = sentimento_final)) +
  geom_col(position = "dodge") +
  scale_fill_manual(
    values = c("negativo" = "#E74C3C", "positivo" = "#2ECC71", "neutro" = "#95A5A6")
  ) +
  labs(
    title = "Comparação entre Nota e Sentimento Identificado",
    x = "Nota Atribuída",
    y = "Número de Avaliações",
    fill = "Sentimento"
  ) +
  theme_minimal()

Conclusão da Análise de Sentimento

A análise de sentimento permitiu transformar o texto das avaliações em indicadores claros das emoções expressas pelos consumidores. As palavras negativas e positivas mostraram os principais motivos de insatisfação e elogio, enquanto a comparação entre notas e polaridade evidenciou como o sentimento textual acompanha — ou contrasta — a nota atribuída. De forma geral, o modelo revelou padrões consistentes, destacando aspectos críticos mencionados pelos usuários e fornecendo uma visão mais profunda da experiência real com o produto.

1.5 Conclusão

1.5.1 Conclusão e Próximos Passos

Conclusão da História
O projeto não apenas relatará estatísticas, mas fornecerá uma narração sobre os aspectos de maior impacto na satisfação do consumidor da categoria analisada.

Limitações e Desafios
Serão discutidas as limitações do modelo de sentimento (por exemplo, dificuldade em capturar sarcasmo ou ironia) e os desafios da limpeza de texto, que pode influenciar diretamente a qualidade das métricas.

Inovação
A utilização de técnicas avançadas de NLP (tokenização, análise de sentimento léxica) representa o uso de métodos não abordados integralmente em sala de aula, adicionando valor à proposta e alinhando o trabalho com práticas contemporâneas de análise de dados em ambientes reais.