First-level agenda-setting theory suggests that topics receiving more attention in news coverage can become more important in the public’s mind. My project uses this theory to compare how much attention U.S. news media give to AI Job Loss vs. AI Jobs.
The AI employment coverage I’ve noticed focuses more on people losing jobs or being replaced than on jobs available. Comparing weekly story counts will help me see how much attention each topic receives in the news. This analysis measures news coverage, not public opinion or why journalists choose particular stories.
The average weekly U.S. news coverage of AI job loss will be higher than coverage of AI jobs during the period studied.
The independent variable is the coverage topic, which I measured in two categories: AI Job Loss and AI Jobs. The dependent variable is weekly coverage volume that I chose to measure as the number of news stories matching each search.
I used R and RStudio to retrieve daily story counts from MediaCloud’s United States–National news collection for January 5, 2025, through October 17, 2026. Then I combined the daily counts into weekly totals and created an interactive graph and summary table using an adapted version of the script provided.
The AI Job Loss search looked for stories containing any of these phrases: “AI job losses,” “AI job layoffs,” “AI job cuts,” “artificial intelligence jobs,” “artificial intelligence layoffs,” “AI displacement,” “AI replacing workers,” or “AI job loss and cuts.”
The AI Job search looked for stories containing any of these phrases: “AI jobs,” “AI career,” “AI job posting,” “AI job opening,” “AI roles,” “artificial intelligence jobs,” “AI hiring,” “AI job creation,” “AI skills and jobs,” “AI skills and hiring,” or “artificial intelligence hiring.”
A media story could match both searches. These counts measure coverage containing the selected terms but not whether a story presents AI positively or negatively.
The AI Jobs search returned 950 stories, averaging 10.22 stories per week. The AI Job Loss search returned 339 stories, averaging 3.65 stories per week. I expected more coverage of job losses, so these initial results were the opposite of what I predicted.
AI Jobs also had the higher single-week peak (50 stories versus 21 for AI Job Loss) and higher week-to-week variation (standard deviation of 6.88 versus 4.03).
Using agenda-setting theory, these counts suggest that AI Jobs received more news attention than AI Job Loss during the period studied. Because the two searches are based on different sets of phrases, some stories may have matched both queries. Reading more of the articles would help me see whether the searches found the coverage I intended to measure.
| topic | Total_Stories | Weekly_Minimum | Weekly_Maximum | Weekly_Median | Weekly_Mean | Weekly_SD |
|---|---|---|---|---|---|---|
| AI Jobs | 950 | 0 | 50 | 9 | 10.22 | 6.88 |
| AI Job Loss | 339 | 0 | 21 | 2 | 3.65 | 4.03 |
library(tidyverse)
library(httr2)
library(lubridate)
library(plotly)
library(knitr)
library(kableExtra)
mc_key <- Sys.getenv("MEDIACLOUD_KEY")
start_date <- "2025-01-05"
end_date <- "2026-10-17"
loss_query <-
'("AI job losses" OR "AI job layoffs" OR "AI job cuts" OR
"artificial intelligence jobs" OR "artificial intelligence layoffs" OR
"AI displacement" OR "AI replacing workers" OR
"AI job loss and cuts")'
hiring_query <-
'("AI jobs" OR "AI career" OR "AI job posting" OR
"AI job opening" OR "AI roles" OR
"artificial intelligence jobs" OR "AI hiring" OR
"AI job creation" OR "AI skills and jobs" OR
"AI skills and hiring" OR
"artificial intelligence hiring")'
topics <- c(
"AI Job Loss" = loss_query,
"AI Jobs" = hiring_query
)
mc_counts_over_time <- function(
query, start_date, end_date,
collection_id = 34412234
) {
resp <-
request(
"https://search.mediacloud.org/api/search/count-over-time"
) |>
req_headers(
Authorization = paste("Token", mc_key)
) |>
req_url_query(
q = query,
start = start_date,
end = end_date,
platform = "onlinenews-mediacloud",
cs = collection_id
) |>
req_perform()
results <- resp_body_json(resp)
map_dfr(
results$count_over_time$counts,
as_tibble
) |>
mutate(date = as.Date(date))
}
topic_data <-
imap_dfr(
topics,
function(search_string, topic_name) {
message("Downloading: ", topic_name)
results <- mc_counts_over_time(
query = search_string,
start_date = start_date,
end_date = end_date
)
Sys.sleep(35)
results |>
mutate(topic = topic_name)
}
)
weekly_counts <-
topic_data |>
mutate(
week = floor_date(date, unit = "week")
) |>
group_by(topic, week) |>
summarise(
stories = sum(count),
.groups = "drop"
)
topic_summary <-
weekly_counts |>
group_by(topic) |>
summarise(
Total_Stories = sum(stories),
Weekly_Minimum = min(stories),
Weekly_Maximum = max(stories),
Weekly_Median = median(stories),
Weekly_Mean = round(mean(stories), 2),
Weekly_SD = round(sd(stories), 2),
.groups = "drop"
) |>
arrange(desc(Total_Stories))
Table <-
topic_summary |>
kbl(
caption = "Media Cloud Topic Summary Statistics",
align = "lrrrrrr"
) |>
kable_styling(
full_width = FALSE,
bootstrap_options = c(
"striped", "hover", "condensed"
)
)
Table
Graph <- plot_ly(
data = weekly_counts,
width = 1000,
x = ~week,
y = ~stories,
color = ~topic,
colors = "Set1",
type = "scatter",
mode = "lines+markers"
) |>
layout(
title = "Weekly U.S. News Coverage: AI Employment",
hovermode = "x unified",
xaxis = list(title = "Week"),
yaxis = list(
title = "Weekly Story Count",
separatethousands = TRUE
)
)
Graph