Rationale

Second-level agenda-setting theory suggests that news coverage can influence which attributes of a topic become important in the public’s mind. My project uses this theory to compare how much attention U.S. news media give to two aspects of AI employment: job losses and job opportunities.

Hypothesis

The average weekly U.S. news coverage of AI job loss will be higher than coverage of AI jobs during the period studied.

Variables and Method

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. I combined the daily counts into weekly totals and created a graph and summary table using an adapted version of the script provided.

The AI Job Loss search looked for stories mentioning AI or artificial intelligence along with terms related to replacing workers, displacement, layoffs, job losses, unemployment, or threatened jobs.

The AI Jobs search looked for stories mentioning AI or artificial intelligence along with terms related to job creation, hiring, opportunities, demand for skills, or employment growth.

A news story could match both searches, so the counts measure coverage containing the selected terms rather than whether a story presents AI positively or negatively.

Initial Results and Discussion

The AI Job Loss search returned 80,892 stories, averaging 869.81 stories per week. The AI Jobs search returned 67,150 stories, averaging 722.04 stories per week.

AI Job Loss also had the higher single-week peak (1,310 stories compared with 1,077 for AI Jobs) and more week-to-week variation (standard deviation of 184.42 compared with 156.55 for AI Jobs).

Using agenda-setting theory, these results suggest that AI Job Loss received more news attention than AI Jobs during the period studied. Because the two searches use different terms, some stories may have matched both. Reading more of the articles would help me see whether the searches found the coverage I intended to measure.

Overall, these results supported my original hypothesis that AI job losses would receive more news coverage than AI job opportunities.


Media Cloud Topic Summary Statistics
topic Total_Stories Weekly_Minimum Weekly_Maximum Weekly_Median Weekly_Mean Weekly_SD
AI Job Loss 80892 458 1310 866 869.81 184.42
AI Jobs 67150 328 1077 711 722.04 156.55

Code

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 OR "artificial intelligence")
AND
(replace* OR displacement OR layoff* OR
"job loss" OR "job losses" OR
eliminat* OR unemployment OR
"threatened jobs" OR
"threatens jobs" OR
"threatening jobs"))'

hiring_query <-
  '((AI OR "artificial intelligence")
AND
("job creation" OR
"create jobs" OR
"creating jobs" OR
hiring OR
opportunity* OR
"demand for skills" OR
"workforce growth" OR
"employment growth"))'

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"
) |>
  plotly::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