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()
)
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")
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()