After removing standard stop words, web artifacts and a custom list of filler terms, the 25 most frequent headline words point to three main clusters of coverage connected to Trump. The largest is foreign affairs and conflict. “Iran” tops the chart and “war,” “oil,” “China,” “Canada” and “deal” also rank highly, which suggests coverage often linked Trump to military tension, energy concerns, and trade negotiations. The second cluster is partisan politics.. Words such as “House,” “Senate,” “GOP,” “Democrats,” “Republicans,” “midterm(s),” and “election” show heavy attention to the approaching midterms. The third is the courts: “court,” “Supreme,” and “judge” suggest frequent legal disputes over administration actions. “AI” is a major keyword right now and is featured often.
From a second-level agenda setting perspective, these patterns suggest the news media most often placed Trump in contexts of conflict, partisan competition and legal challenge. Those associations can change how the public perceives him.
My filtering decisions shapes these results. I removed words like Trump, Donald and president because every single story mentioned those. Trump would’ve dominated the chart and compressed everything else. I also dropped verbs such as “says” and broadcast words such as “live” and “video” because they describe how stories are presented rather than what they cover. I kept “U.S.” “Antarctica” and “administration” although they are fairly generic.
Unigrams also have limits “White” and “House” almost certainly come from “White House” and “Supreme” is from “Supreme Court,” so some counts overlap.
download.file(
url = "https://github.com/drkblake/Data/raw/refs/heads/main/Trump_story_headlines.rds",
destfile = "Trump_story_headlines.rds",
mode = "wb"
)
headlines <- readRDS("Trump_story_headlines.rds")
# ---- Packages ----
if (!require("tidyverse")) install.packages("tidyverse")
if (!require("tidytext")) install.packages("tidytext")
library(tidyverse)
library(tidytext)
# ---- Load headlines ----
headlines <- readRDS("Trump_story_headlines.rds")
# ---- Custom words to drop (frequent but not meaningful) ----
custom_stop <- tibble(word = c(
"trump", "donald", "president", # the search term itself
"says", "said", "say", "saying", "told", # attribution verbs
"news", "report", "reports", "update", "updates",
"live", "video", "watch", "breaking", "exclusive", "opinion",
"new", "latest", "today", "day", "week", "time", "amid"
))
# ---- Clean social media / web artifacts ----
headlines_clean <- headlines %>%
mutate(title = title %>%
str_remove_all("https?://\\S+|www\\.\\S+") %>% # URLs
str_remove_all("@\\w+") %>% # @mentions
str_remove_all("#") %>% # hashtag symbols
str_replace_all("&|&#\\d+;", " ") %>% # HTML entities
str_replace_all("[\u2018\u2019]", "'")) # curly apostrophes
# ---- Tokenize into unigrams and filter ----
words <- headlines_clean %>%
unnest_tokens(word, title) %>%
mutate(word = str_remove(word, "'s$")) %>% # trump's -> trump
filter(!str_detect(word, "^[0-9]+$"), # drop pure numbers
nchar(word) > 1,
!word %in% c("rt", "amp", "http", "https")) %>%
anti_join(stop_words, by = "word") %>%
anti_join(custom_stop, by = "word")
# ---- Count ----
word_counts <- words %>% count(word, sort = TRUE)
top25 <- word_counts %>% slice_max(n, n = 25, with_ties = FALSE)
# ---- Plot ----
word_plot <- ggplot(top25, aes(x = reorder(word, n), y = n)) +
geom_col(fill = "#0066CC") +
coord_flip() +
labs(title = "25 Most Common Words in Trump-Related Headlines",
subtitle = "Aug. 3 – Oct. 4, 2026 (54,686 headlines)",
x = NULL, y = "Frequency") +
theme_minimal(base_size = 12)