Airline Customer Sentiment

Author

Allison Shrivastava

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.6
✔ forcats   1.0.1     ✔ stringr   1.6.0
✔ ggplot2   4.0.3     ✔ tibble    3.3.0
✔ lubridate 1.9.4     ✔ tidyr     1.3.1
✔ purrr     1.2.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(plotly)

Attaching package: 'plotly'

The following object is masked from 'package:ggplot2':

    last_plot

The following object is masked from 'package:stats':

    filter

The following object is masked from 'package:graphics':

    layout
airline <- read.csv("Tweets.csv", stringsAsFactors = FALSE)

airline_data <- airline %>%
  select(airline, airline_sentiment, text)
sentiment_summary <- airline_data %>%
  group_by(airline, airline_sentiment) %>%
  summarise(
    Count = n(),
    Example = first(text),
    .groups = "drop"
  ) %>%
  group_by(airline) %>%
  mutate(
    Percentage = Count / sum(Count) * 100
  ) %>%
  ungroup()

airline_order <- sentiment_summary %>%
  filter(airline_sentiment == "negative") %>%
  arrange(desc(Percentage)) %>%
  pull(airline)

sentiment_summary <- sentiment_summary %>%
  mutate(
    airline = factor(airline, levels = airline_order),
    airline_sentiment = factor(
      airline_sentiment,
      levels = c("negative", "neutral", "positive")
    ),
    sentiment_label = case_when(
      airline_sentiment == "negative" ~ "Negative",
      airline_sentiment == "neutral"  ~ "Neutral",
      airline_sentiment == "positive" ~ "Positive"
    ),
    short_example = ifelse(
      nchar(Example) > 140,
      paste0(substr(Example, 1, 140), "..."),
      Example
    ),
    label = ifelse(
      airline_sentiment == "negative",
      paste0(round(Percentage, 1), "%"),
      ""
    )
  )
airline_order <- sentiment_summary %>%
  filter(airline_sentiment == "negative") %>%
  arrange(desc(Percentage)) %>%
  pull(airline)

sentiment_summary <- sentiment_summary %>%
  mutate(
    airline = factor(airline, levels = airline_order),
    airline_sentiment = factor(
      airline_sentiment,
      levels = c("negative", "neutral", "positive")
    ),
    sentiment_label = case_when(
      airline_sentiment == "negative" ~ "Negative",
      airline_sentiment == "neutral"  ~ "Neutral",
      airline_sentiment == "positive" ~ "Positive"
    ),
    short_example = ifelse(
      nchar(Example) > 140,
      paste0(substr(Example, 1, 140), "..."),
      Example
    ),
    
    label = ifelse(
      airline_sentiment == "negative",
      paste0(round(Percentage, 1), "%"),
      ""
    )
  )
sent_plot <- plot_ly(
  data = sentiment_summary,
  x = ~airline,
  y = ~Percentage,
  color = ~airline_sentiment,
  
  colors = c(
    "negative" = "#CC79A7",
    "neutral"  = "#999999",
    "positive" = "#0072B2"
  ),
  
  type = "bar",
  
  text = ~label,
  textposition = "outside",
  cliponaxis = FALSE,
  
  hovertext = ~paste(
    "<b>", airline, "</b>",
    "<br>Sentiment: ", sentiment_label,
    "<br>Percentage: ", sprintf("%.1f%%", Percentage),
    "<br>Tweets: ", Count,
    "<br><br><b>Example Tweet</b><br>",
    short_example
  ),
  hoverinfo = "text"
) %>%
  layout(
    
    title = list(
      text = paste0(
        "<b>Negative tweets outnumbered positive tweets for every airline</b>",
        "<br><span style='font-size:14px;'>",
        "Tweet sentiment by airline (16–24 February 2015)",
        "</span>"
      ),
      x = 0.5,
      xanchor = "center",
      font = list(size = 22)
    ),
    
    barmode = "group",
    bargap = 0.25,
    
    paper_bgcolor = "white",
    plot_bgcolor = "white",
    
    margin = list(
      t = 120,
      b = 160,
      l = 70,
      r = 30
    ),
    
    xaxis = list(
      title = "",
      tickangle = -20,
      showgrid = FALSE,
      zeroline = FALSE,
      categoryorder = "array",
      categoryarray = airline_order
    ),
    
    yaxis = list(
      title = "",
      range = c(0, 105),
      ticksuffix = "%",
      dtick = 20,
      showgrid = TRUE,
      gridcolor = "#EFEFEF",
      gridwidth = 1,
      zeroline = FALSE
    ),
    
    legend = list(
      title = list(text = ""),
      orientation = "h",
      x = 0.5,
      xanchor = "center",
      y = -0.28,
      yanchor = "top"
    ),
    
    annotations = list(
      list(
        x = 0,
        y = -0.57,
        xref = "paper",
        yref = "paper",
        showarrow = FALSE,
        xanchor = "left",
        text = "Source: Twitter US Airline Sentiment dataset (Kaggle)",
        font = list(
          size = 11,
          color = "gray50"
        )
      )
    )
  )

sent_plot