Rationale

While first-level agenda setting predicts what issues society considers important — based on the quantity of media coverage of a given topic — second-level agenda-setting impacts what attributes or subcategories we think are important within those issues.

Public education is a popular topic of media coverage because it affects nearly everyone at one point during their lives, either directly or indirectly. Within the overarching topic of education, there are multiple subcategories that receive attention from the media. For my project, I plan to explore the effects of second-level agenda setting within two of those subcategories — funding and school violence — to determine how coverage of those attributes affects public discussion.

The results will enhance theoretical understanding about how two different aspects of education correlate with media coverage, and thereby influence the topics within education that are prominent in the public’s eye.

Hypothesis

Weekly APNews.com coverage volume of two education subtopics — funding and school violence — affects the prominence of those topics within society during the first nine months of 2025.

Variables & method

Weekly APNews.com education subtopics of funding and school violence are categorical and served as the analysis’ dependent variable. The independent variable is continuous because it uses the volume of stories published each week over the nine-month period between January and September 2025.

Further along in this analysis, I will use a paired t-test to measure the statistical significance that the amount of media coverage on each attribute affects public salience.

Results & discussion

The figure below summarizes the total number of stories during the time period on the topic of education, and then within that coverage, summarizes the number of stories dedicated to each subtopic or attribute — school funding verses school violence. Visually, it appears that the attribute of school violence tended to receive a higher volume of media coverage with several spikes in coverage. These spikes likely correlate with occasions of a school shooting or attack. There are a few weeks — notably weeks 10, 14, and 27 — when school funding received more coverage than school violence.

Further analysis is needed to understand these patterns.

As part of this analysis, certainly key words were used to filter the media coverage from APNews.com. For the “funding” attribute, the keywords used were: fund, funds, funding, grant, grants, pay, salary, salaries, service, services, lunch, lunches, and special education. For the “violence” attribute, the keywords used were: shoot, shooting, shooter, shot, gun, rifle, weapon, kill, and killed.

Code:

# ============================================
# APNews text analysis (Second-level agenda-setting theory version)
# ============================================

# ============================================
# --- Load required libraries ---
# ============================================

if (!require("tidyverse")) install.packages("tidyverse")
if (!require("tidytext")) install.packages("tidytext")
if (!require("plotly")) install.packages("plotly")

library(tidyverse)
library(tidytext)
library(plotly)

# ============================================
# --- Define Custom Topic Labels ---
# ============================================

# You can change these labels to anything you want.
# They will appear in the chart legend and title.
topic_labels <- list(
  Topic1 = "All education",
  Topic2 = "Violence",
  Topic3 = "Money"
)

# ============================================
# --- Load the APNews data ---
# ============================================

FetchedData <- readRDS(url("https://github.com/drkblake/Data/raw/refs/heads/main/APNews.rds"))
saveRDS(FetchedData, file = "APNews.rds")
rm(FetchedData)

APNews <- readRDS("APNews.rds")

# ============================================
# --- Define and apply FilterTopic ---
# ============================================

FilterTopic_phrases <- c(
  "education", "educational", "educator", "educators",
  "school", "schools", "classroom", "classrooms",
  "teacher", "teachers"
)

escaped_FilterTopic <- str_replace_all(
  FilterTopic_phrases,
  "([\\^$.|?*+()\\[\\]{}\\\\])", "\\\\\\1"
)

FilterTopic_pattern <- paste0("\\b", escaped_FilterTopic, "\\b", collapse = "|")

APNews <- APNews %>%
  mutate(
    Full.Text.clean = str_squish(Full.Text),
    FilterTopic = if_else(
      str_detect(Full.Text.clean, regex(FilterTopic_pattern, ignore_case = TRUE)),
      "Yes", "No"
    )
  )

TopicNews <- APNews %>% filter(FilterTopic == "Yes")

# ============================================
# --- Define Topic1 (Education) ---
# ============================================

Topic1_phrases <- c(
  "education", "educational", "educator", "educators",
  "school", "schools", "classroom", "classrooms",
  "teacher", "teachers"
)

Topic1_pattern <- paste0("\\b", str_replace_all(Topic1_phrases,
                                                "([\\^$.|?*+()\\[\\]{}\\\\])", "\\\\\\1"
), "\\b", collapse = "|")

TopicNews <- TopicNews %>%
  mutate(
    Topic1 = if_else(
      str_detect(Full.Text.clean, regex(Topic1_pattern, ignore_case = TRUE)),
      "Yes", "No"
    )
  )

# ============================================
# --- Define Topic2 (Shootings) ---
# ============================================

Topic2_phrases <- c(
  "shoot", "shooting", "shooter", "shot",
  "gun", "rifle", "weapon", "kill", "killed"
)

Topic2_pattern <- paste0("\\b", str_replace_all(Topic2_phrases,
                                                "([\\^$.|?*+()\\[\\]{}\\\\])", "\\\\\\1"
), "\\b", collapse = "|")

TopicNews <- TopicNews %>%
  mutate(
    Topic2 = if_else(
      str_detect(Full.Text.clean, regex(Topic2_pattern, ignore_case = TRUE)),
      "Yes", "No"
    )
  )

# ============================================
# --- Define Topic3 (Economy) ---
# ============================================

Topic3_phrases <- c(
  "fund", "funds", "funding",
  "grant", "grants", "pay",
  "salary", "salaries", "service",
  "services", "lunch", "lunches",
  "special education"
)

Topic3_pattern <- paste0("\\b", str_replace_all(Topic3_phrases,
                                                "([\\^$.|?*+()\\[\\]{}\\\\])", "\\\\\\1"
), "\\b", collapse = "|")

TopicNews <- TopicNews %>%
  mutate(
    Topic3 = if_else(
      str_detect(Full.Text.clean, regex(Topic3_pattern, ignore_case = TRUE)),
      "Yes", "No"
    )
  )

# ============================================
# --- Summarize weekly counts for all topics ---
# ============================================

Topic1_weekly <- TopicNews %>%
  filter(Topic1 == "Yes") %>%
  group_by(Week) %>%
  summarize(Count = n(), .groups = "drop") %>%
  mutate(Topic = topic_labels$Topic1)

Topic2_weekly <- TopicNews %>%
  filter(Topic2 == "Yes") %>%
  group_by(Week) %>%
  summarize(Count = n(), .groups = "drop") %>%
  mutate(Topic = topic_labels$Topic2)

Topic3_weekly <- TopicNews %>%
  filter(Topic3 == "Yes") %>%
  group_by(Week) %>%
  summarize(Count = n(), .groups = "drop") %>%
  mutate(Topic = topic_labels$Topic3)

Weekly_counts <- bind_rows(Topic1_weekly, Topic2_weekly, Topic3_weekly) %>%
  tidyr::complete(
    Topic,
    Week = full_seq(range(Week), 1),
    fill = list(Count = 0)
  ) %>%
  arrange(Topic, Week)

# ============================================
# --- Visualize the results ---
# ============================================

AS2 <- plot_ly(
  data = Weekly_counts,
  x = ~Week,
  y = ~Count,
  color = ~Topic,
  colors = c("steelblue", "seagreen", "firebrick"),
  type = "scatter",
  mode = "lines+markers",
  line = list(width = 2),
  marker = list(size = 6)
) %>%
  layout(
    title = paste(
      "Weekly Counts of",
      paste(unlist(topic_labels), collapse = ", "),
      "Stories (Filtered Dataset)"
    ),
    xaxis = list(title = "Week Number (starting with Week 1 of 2025)", dtick = 1),
    yaxis = list(title = "Number of Articles"),
    legend = list(title = list(text = "Topic")),
    hovermode = "x unified"
  )

# ============================================
# --- Display the chart ---
# ============================================

AS2