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 losses versus AI hiring and job creation.
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 losses will be higher than coverage of AI hiring and job creation during the period studied.
The independent variable is the coverage topic, which I measured in two categories: AI job losses and AI hiring and job creation. 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.
Both job-loss and job-hiring searches required a reference to AI or artificial intelligence. The job-loss search included terms such as layoffs, job cuts, displacement, and replacing workers. The hiring search included terms such as hiring, job creation, openings, careers, and AI skills. 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 job-hiring search returned 23,494 stories, averaging 252.62 stories per week. The job-loss search showed 16,578 stories, averaging 178.26 per week. I expected more coverage of job losses, so these initial results were the opposite of what I predicted.
Even though hiring had more stories overall, job losses had the highest count in a single week, with 499 stories compared with 432 for hiring. Job-loss coverage also changed more from week to week. Its standard deviation was 75.60, compared with 63.71 for hiring.
Using agenda-setting theory, these counts suggest that hiring and job opportunities received more news attention during the period studied. The hiring search did include careers and AI skills along with new jobs. Some of the stories could appear in both searches, and a story about hiring could still discuss AI negatively. 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 Hiring and Job Creation | 23494 | 127 | 432 | 250 | 252.62 | 63.71 |
| AI Job Losses | 16578 | 68 | 499 | 165 | 178.26 | 75.60 |
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 <-
'(("artificial intelligence" OR AI) AND
(layoff* OR "job cuts" OR "job loss" OR
"job losses" OR "job displacement" OR
"worker displacement" OR "AI displacement" OR
"replacing workers"))'
hiring_query <-
'(("artificial intelligence" OR AI) AND
(hiring OR "job creation" OR "new jobs" OR
"job openings" OR "job postings" OR
"AI jobs" OR "artificial intelligence jobs" OR
"AI career" OR "AI careers" OR
"AI job posting" OR "AI job opening" OR
"AI roles" OR
("AI skills" AND (jobs OR hiring))))'
topics <- c(
"AI Job Losses" = loss_query,
"AI Hiring and Job Creation" = 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
htmltools::HTML("<div style='height:30px;'></div>")
Graph <- plot_ly(
data = weekly_counts,
width = 900,
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",
legend = list(
orientation = "h",
x = 0.5,
xanchor = "center",
y = -0.4
),
xaxis = list(
title = "Week",
dtick = "M1",
tickformat = "%b %Y",
tickangle = -45
),
yaxis = list(
title = "Weekly Story Count",
separatethousands = TRUE
)
)
Graph