Media Effects

Author

Lennart Klein

Published

August 8, 2023

1 Setup

Code
raw <- read.delim(here::here("data", "survey", "AR_GN_data_full.txt"))
dat <- raw %>% janitor::clean_names()
Code
dat <- dat %>% mutate(
  # levels sorted 1-7
  news_outlet_view_f = news_outlet_view %>%
    # making sure every level is included even if not present (empty levels)
    factor(levels = 1:7) %>%
    fct_na_value_to_level(level = "NA") %>%
    fct_recode(
      "Strongly condemned the protest" = "1",
      "Condemned the protests" = "2",
      "Somewhat condemned the protests" = "3",
      "Neither condemned nor praised the protests" = "4",
      "Somewhat praised the protests" = "5",
      "Praised the protests" = "6",
      "Strongly praised the protests" = "7",
      "No Response" = "NA"
    ),
  news_view = news_outlet_view %>%
    factor(levels = 1:7) %>%
    fct_recode(
      "Strongly condemned" = "1",
      "Condemned" = "2",
      "Somewhat condemned" = "3",
      "Neither condemned nor praised" = "4",
      "Somewhat praised" = "5",
      "Praised" = "6",
      "Strongly praised" = "7"
      # "No Response" = "NA"
    ),
  support_protest_f = support_protest %>%
    factor(levels = 1:7) %>%
    fct_na_value_to_level(level = "NA") %>%
    fct_recode(
      "Strongly oppose" = "1",
      "Oppose" = "2",
      "Somewhat oppose" = "3",
      "Neither oppose nor support" = "4",
      "Somewhat support" = "5",
      "Support" = "6",
      "Strongly support" = "7",
      "No Response" = "NA"
    ), # maintain ordering
  support_protest_post_descr_f = support_protest_post_descr %>%
    factor(levels = 1:7, ordered = FALSE) %>% # making sure every level is included
    fct_recode(
      "Strongly oppose" = "1",
      "Oppose" = "2",
      "Somewhat oppose" = "3",
      "Neither oppose nor support" = "4",
      "Somewhat support" = "5",
      "Support" = "6",
      "Strongly support" = "7"
    ) %>%
    fct_explicit_na(na_level = "(NA)"), # fct_na_value_to_level
  awareness_ar_f = awareness_ar %>%
    factor(levels = 0:3, ordered = FALSE) %>% # making sure every level is included
    fct_recode(
      "Nothing at all" = "0",
      "Not very much" = "1",
      "A fair amount" = "2",
      "A great deal" = "3"
    ) %>% fct_explicit_na(na_level = "(NA)"),
  awareness_ar_post_f = awareness_ar_w2 %>%
    factor(levels = 0:3, ordered = FALSE) %>% # making sure every level is included
    fct_recode(
      "Nothing at all" = "0",
      "Not very much" = "1",
      "A fair amount" = "2",
      "A great deal" = "3"
    ) %>% fct_explicit_na(na_level = "(NA)"), # fct_na_value_to_level
  news_outlet_f = news_outlet %>% factor() %>%
    fct_explicit_na(na_level = "(NA)") %>%
    fct_infreq(),
  education_f = education %>% fct_recode(
    "Post-graduate degree" = "Post-graduate degree", # Masters, PhD
    "College" = "College or university",
    "Higher education" = "Higher or secondary or further education (A-levels, BTEC, etc.)",
    "Secondary school" = "Secondary school up to 16 years",
    "Primary school" = "Primary school"
  ) %>% fct_relevel("Post-graduate degree", "College", "Higher education", "Secondary school", "Primary school")
)

2 Modelling

2.1 Media Outlet & Protest Support

Code
dat <- dat %>%
  mutate(
    news = news_outlet %>%
      fct_recode(
        "The BBC" = "The BBC",
        "The Guardian" = "The Guardian",
        "Daily Mail" = "Daily Mail or Daily Mail Online",
        "ITV" = "ITV",
        "The Telegraph" = "The Telegraph",
        "Sky News" = "Sky News",
        "The Sun" = "The Sun",
        "Daily Express" = "Daily Express",
        "Mirror" = "Mirror",
        "Other Social Media" = "Social media (but not via any of the above outlets)",
        "Friends or family" = "Through friends or family",
        "The Independent" = "The Independent",
        "Don't remember" = "Don't remember",
        "Other" = "Other (please specify)",
      ) %>% fct_infreq()
  )
Code
dat %>%
  count(news) %>%
  knitr::kable()
news n
The BBC 565
ITV 192
Don't remember 162
Other Social Media 156
Other 91
Sky News 86
Daily Mail 75
The Guardian 57
Friends or family 43
The Sun 15
The Telegraph 6
Mirror 4
Daily Express 3
The Independent 3
NA 262
  • beware of small frequency of some of the outlets

2.1.1 Model

Code
lm_news <- lm(support_protest ~ news, data = dat)
# summary(lm_news)

# https://www.danieldsjoberg.com/gtsummary/articles/tbl_regression.html
gtsummary::tbl_regression(lm_news, intercept = TRUE) %>%
  add_significance_stars(pattern = "{p.value}{stars}", hide_p = FALSE) %>%
  bold_p() %>%
  italicize_levels() %>%
  modify_caption("Effect of News Media Consumption on Support of Protest")
Effect of News Media Consumption on Support of Protest
Characteristic Beta SE1 p-value2
(Intercept) 3.7 0.076 <0.001***
news
    The BBC
    ITV -0.61 0.151 <0.001***
    Don't remember 0.22 0.161 0.2
    Other Social Media 0.66 0.163 <0.001***
    Other 0.16 0.204 0.4
    Sky News 0.21 0.209 0.3
    Daily Mail -0.30 0.222 0.2
    The Guardian 1.2 0.251 <0.001***
    Friends or family 1.5 0.285 <0.001***
    The Sun 0.04 0.472 >0.9
    The Telegraph -0.86 0.740 0.2
    Mirror 0.31 0.905 0.7
    Daily Express 1.3 1.04 0.2
    The Independent 0.98 1.04 0.4
1 SE = Standard Error
2 *p<0.05; **p<0.01; ***p<0.001
  • The BBC is the reference category here

2.1.2 Pairwise Comparisons

Code
plot(factorplot::factorplot(lm_news, factor.variable = "news"))

Code
# incremental F-test

car::Anova(lm_news)
Anova Table (Type II tests)

Response: support_protest
          Sum Sq   Df F value    Pr(>F)    
news       323.4   13  7.6433 8.035e-15 ***
Residuals 4700.3 1444                      
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

2.2 Media Views & Protest Support

Code
# https://quarto.org/docs/computations/execution-options#figure-options

dat %>%
  select(news, news_outlet_view) %>%
  drop_na() %>%
  ggplot(aes(x = fct_reorder(news, news_outlet_view, .fun = mean), y = news_outlet_view)) +
  stat_summary(fun.data = "mean_se", color = scl_colors["logo"]) +
  coord_flip() +
  labs(x = "News Outlet/Source", y = "Judged View of the Protests", caption = "[1] Strongly condemned - [4] Neither condemned nor praised the protests - [7] Strongly praised") +
  theme_scl()

Code
lm1 <- lm(support_protest ~ news_view, data = dat)

lm2 <- lm(support_protest ~ news_view + broken_bond, data = dat)

lm3 <- lm(support_protest ~ news_view + broken_bond + need_change_entertainment, data = dat)

lm4 <- lm(support_protest ~ news_view + broken_bond + need_change_entertainment + animals_entertainment, data = dat)

lm5 <- lm(support_protest ~ news_view + broken_bond + need_change_entertainment + animals_entertainment + animals_for_food, data = dat)

support_models <- list(lm1, lm2, lm3, lm4, lm5)
modelsummary(support_models, stars = TRUE, output = "gt", statistic = NULL)
(1) (2) (3) (4) (5)
(Intercept) 3.052*** 1.196*** -0.203 2.385*** 3.740***
news_viewSomewhat condemned 0.686*** 0.562*** 0.578*** 0.501** 0.519***
news_viewNeither condemned nor praised 0.883*** 0.791*** 0.799*** 0.718*** 0.686***
news_viewSomewhat praised 1.859*** 1.622*** 1.653*** 1.573*** 1.548***
news_viewPraised 2.641*** 2.234*** 2.265*** 1.974*** 1.889***
news_viewStrongly praised 3.256*** 3.036*** 3.041*** 2.871*** 2.675***
broken_bond 0.442*** 0.318*** 0.284*** 0.195***
need_change_entertainment 0.334*** 0.120** 0.108**
animals_entertainment -0.359*** -0.274***
animals_for_food -0.240***
Num.Obs. 1369 1369 1369 1369 1369
R2 0.078 0.201 0.244 0.311 0.344
R2 Adj. 0.074 0.198 0.240 0.307 0.340
AIC 5408.8 5213.9 5140.1 5016.5 4949.8
BIC 5445.3 5255.7 5187.1 5068.7 5007.3
Log.Lik. -2697.390 -2598.951 -2561.064 -2498.259 -2463.918
RMSE 1.74 1.62 1.57 1.50 1.46
+ p < 0.1, * p < 0.05, ** p < 0.01, *** p < 0.001
Code
lm6 <- lm(support_protest ~ news_view + broken_bond + need_change_entertainment + animals_entertainment + animals_for_food + age, data = dat)

lm7 <- lm(support_protest ~ news_view + broken_bond + need_change_entertainment + animals_entertainment + animals_for_food + age + gender, data = dat)

lm8 <- lm(support_protest ~ news_view + broken_bond + need_change_entertainment + animals_entertainment + animals_for_food + age + gender + education_f, data = dat)

support_models2 <- list("(6)" = lm6, "(7)" = lm6, "(8)" = lm8)
modelsummary(support_models2, stars = TRUE, output = "gt", statistic = NULL)
(6) (7) (8)
(Intercept) 4.520*** 4.520*** 4.677***
news_viewSomewhat condemned 0.477** 0.477** 0.469**
news_viewNeither condemned nor praised 0.699*** 0.699*** 0.679***
news_viewSomewhat praised 1.418*** 1.418*** 1.416***
news_viewPraised 1.814*** 1.814*** 1.791***
news_viewStrongly praised 2.533*** 2.533*** 2.540***
broken_bond 0.170*** 0.170*** 0.168***
need_change_entertainment 0.139*** 0.139*** 0.139***
animals_entertainment -0.236*** -0.236*** -0.237***
animals_for_food -0.255*** -0.255*** -0.252***
age -0.019*** -0.019*** -0.018***
genderMale -0.083
education_fCollege -0.095
education_fHigher education -0.286*
education_fSecondary school -0.284+
education_fPrimary school 1.391
Num.Obs. 1369 1369 1369
R2 0.367 0.367 0.372
R2 Adj. 0.362 0.362 0.365
AIC 4904.0 4904.0 4902.8
BIC 4966.7 4966.7 4991.6
Log.Lik. -2439.999 -2439.999 -2434.423
RMSE 1.44 1.44 1.43
+ p < 0.1, * p < 0.05, ** p < 0.01, *** p < 0.001
  • as we can see the effect of news views remains strong even when controlling for personal attitudes and prominent demographics suggesting there is more than just selective attention/partisan sorting into news outlets and motivated reasoning

  • However, there could be an order bias in our survey since we asked respondents about their own support after asessing the outlet’s view

Code
make_models_tidy <- function(model) {
  model_tidy <- model %>%
    broom::tidy(conf.int = TRUE) %>% # add confint
    mutate(
      stars = symnum(p.value,
        corr = FALSE, na = FALSE,
        cutpoints = c(0, 0.001, 0.01, 0.05, 0.1, 1),
        symbols = c("***", "**", "*", ".", " ")
      ),
      significant = p.value < 0.05,
      outcome = model[["call"]][["formula"]][[2]] %>% as.character()
    ) %>%
    slice(-1) # remove intercept
  return(model_tidy)
}

forest_plotter <- function(tidy_model) {
  name <- tidy_model$outcome[1]
  tidy_model %>%
    ggplot(aes(y = fct_reorder(term, estimate, min), color = significant)) +
    geom_point(aes(x = estimate), size = 2, shape = 15) +
    geom_linerange(aes(xmin = conf.low, xmax = conf.high)) +
    scale_color_manual(values = c("TRUE" = "black", "FALSE" = "grey"), guide = "none") +
    geom_vline(xintercept = 0, linetype = "dashed") +
    labs(title = name, x = "Estimates", y = "") +
    theme_scl()
}

lm8 %>%
  make_models_tidy() %>%
  forest_plotter()