-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathICE_Norway.Rmd
executable file
·636 lines (485 loc) · 23.4 KB
/
ICE_Norway.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
---
title: "Cross-cultural validation of the ICE: Norway"
author: "Michalina Marczak"
date: "Last compiled on `r format(Sys.time(), '%d %B, %Y')`"
output:
html_document:
toc: true
toc_depth: 3
toc_float: false
fig_width: 8
fig_height: 8
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, warning = FALSE, message = FALSE)
```
```{r, include=F}
#set the global options
options(max.print=999999) #allows printing out large outputs
options(scipen = 999) #disables scientific notation (uses decimal instead)
set.seed(9999) # set seed for replicability
####### load the libraries
library(tidyverse)
library(lavaan)
library(psych)
library(mvnormalTest)
library(astatur)
library(ggcorrplot)
# load the custom functions
condisc <- function(x){
std.loadings<- inspect(x, what="std")$lambda
#std.loadings
std.loadings[std.loadings==0] <- NA
#std.loadings
std.loadings <- std.loadings^2
#std.loadings
ave <- colMeans(std.loadings, na.rm=TRUE)
#ave
#factor correlation matrix
fcor <- lavInspect(x, "cor.lv")
#fcor
sqfcor <- fcor^2
#sqfcor
list(Squared_Factor_Correlation=round(sqfcor, digits=3),
Average_Variance_Extracted=round(ave, digits=3))
}
### I'm using the custom correlation_matrix and save_correlation_matrix functions from Paul van der Laken
### https://paulvanderlaken.com/2020/07/28/publication-ready-correlation-matrix-significance-r/#correlation_matrix
#' correlation_matrix
#' Creates a publication-ready / formatted correlation matrix, using `Hmisc::rcorr` in the backend.
#'
#' @param df dataframe; containing numeric and/or logical columns to calculate correlations for
#' @param type character; specifies the type of correlations to compute; gets passed to `Hmisc::rcorr`; options are `"pearson"` or `"spearman"`; defaults to `"pearson"`
#' @param digits integer/double; number of decimals to show in the correlation matrix; gets passed to `formatC`; defaults to `3`
#' @param decimal.mark character; which decimal.mark to use; gets passed to `formatC`; defaults to `.`
#' @param use character; which part of the correlation matrix to display; options are `"all"`, `"upper"`, `"lower"`; defaults to `"all"`
#' @param show_significance boolean; whether to add `*` to represent the significance levels for the correlations; defaults to `TRUE`
#' @param replace_diagonal boolean; whether to replace the correlations on the diagonal; defaults to `FALSE`
#' @param replacement character; what to replace the diagonal and/or upper/lower triangles with; defaults to `""` (empty string)
#'
#' @return a correlation matrix
#' @export
#'
#' @examples
#' `correlation_matrix(iris)`
#' `correlation_matrix(mtcars)`
correlation_matrix <- function(df,
type = "pearson",
digits = 3,
decimal.mark = ".",
use = "all",
show_significance = TRUE,
replace_diagonal = FALSE,
replacement = ""){
# check arguments
stopifnot({
is.numeric(digits)
digits >= 0
use %in% c("all", "upper", "lower")
is.logical(replace_diagonal)
is.logical(show_significance)
is.character(replacement)
})
# we need the Hmisc package for this
require(Hmisc)
# retain only numeric and boolean columns
isNumericOrBoolean = vapply(df, function(x) is.numeric(x) | is.logical(x), logical(1))
if (sum(!isNumericOrBoolean) > 0) {
cat('Dropping non-numeric/-boolean column(s):', paste(names(isNumericOrBoolean)[!isNumericOrBoolean], collapse = ', '), '\n\n')
}
df = df[isNumericOrBoolean]
# transform input data frame to matrix
x <- as.matrix(df)
# run correlation analysis using Hmisc package
correlation_matrix <- Hmisc::rcorr(x, type = type)
R <- correlation_matrix$r # Matrix of correlation coeficients
p <- correlation_matrix$P # Matrix of p-value
# transform correlations to specific character format
Rformatted = formatC(R, format = 'f', digits = digits, decimal.mark = decimal.mark)
# if there are any negative numbers, we want to put a space before the positives to align all
if (sum(!is.na(R) & R < 0) > 0) {
Rformatted = ifelse(!is.na(R) & R > 0, paste0(" ", Rformatted), Rformatted)
}
# add significance levels if desired
if (show_significance) {
# define notions for significance levels; spacing is important.
stars <- ifelse(is.na(p), "", ifelse(p < .001, "***", ifelse(p < .01, "**", ifelse(p < .05, "*", ""))))
Rformatted = paste0(Rformatted, stars)
}
# make all character strings equally long
max_length = max(nchar(Rformatted))
Rformatted = vapply(Rformatted, function(x) {
current_length = nchar(x)
difference = max_length - current_length
return(paste0(x, paste(rep(" ", difference), collapse = ''), sep = ''))
}, FUN.VALUE = character(1))
# build a new matrix that includes the formatted correlations and their significance stars
Rnew <- matrix(Rformatted, ncol = ncol(x))
rownames(Rnew) <- colnames(Rnew) <- colnames(x)
# replace undesired values
if (use == 'upper') {
Rnew[lower.tri(Rnew, diag = replace_diagonal)] <- replacement
} else if (use == 'lower') {
Rnew[upper.tri(Rnew, diag = replace_diagonal)] <- replacement
} else if (replace_diagonal) {
diag(Rnew) <- replacement
}
return(Rnew)
}
#' save_correlation_matrix
#' Creates and save to file a fully formatted correlation matrix, using `correlation_matrix` and `Hmisc::rcorr` in the backend
#' @param df dataframe; passed to `correlation_matrix`
#' @param filename either a character string naming a file or a connection open for writing. "" indicates output to the console; passed to `write.csv`
#' @param ... any other arguments passed to `correlation_matrix`
#'
#' @return NULL
#'
#' @examples
#' `save_correlation_matrix(df = iris, filename = 'iris-correlation-matrix.csv')`
#' `save_correlation_matrix(df = mtcars, filename = 'mtcars-correlation-matrix.csv', digits = 3, use = 'lower')`
save_correlation_matrix = function(df, filename, ...) {
return(write.csv2(correlation_matrix(df, ...), file = filename))
}
condisc <- function(x){
std.loadings<- inspect(x, what="std")$lambda
#std.loadings
std.loadings[std.loadings==0] <- NA
#std.loadings
std.loadings <- std.loadings^2
#std.loadings
ave <- colMeans(std.loadings, na.rm=TRUE)
#ave
#factor correlation matrix
fcor <- lavInspect(x, "cor.lv")
#fcor
sqfcor <- fcor^2
#sqfcor
list(Squared_Factor_Correlation=round(sqfcor, digits=3),
Average_Variance_Extracted=round(ave, digits=3))
}
```
```{r, include=F}
### Load the data
load(Sys.readlink("./NO/dataset-Norway.RData"))
```
## Inspection of the climate emotions data
```{r, include=F}
##### subset the data for the CFA
#subset the data frame to work with for now
data.for.CFA <- dplyr::select(qdata, starts_with("ICE-60-no"))
ICE_data <- as.data.frame(data.for.CFA)
#change the variables type from character to numeric (keeping them in the data frame format)
ICE_data <- as.data.frame(lapply(ICE_data, as.numeric))
####explore & inspect the ICE data for consistency
#is there any missing data?
sum(colSums(is.na(ICE_data))) # no missing data
#a categorical representation of the ICE data to check for inconsistent values
lapply(ICE_data, table)
# For the descriptives, the response format should be 1-5 not 0-4, hence we add 1 to each value in the data frame
ICE_data <- ICE_data + 1
# overview of the data
psych::describe(ICE_data)
```
### Multi- & uni-variate normality check
In the first step, let's check whether the data meets the assumptions of multi- and univariate normality using Mardia’s test for multivariate skewness and kurtosis and Shapiro-Wilk test for univariate normality
```{r, include=T}
mvnormalTest::mardia(ICE_data, std = TRUE)
# the values imply that we should reject the null hypothesis of uni & multivariate normality
```
```{r, include=F}
##### Visual inspection
theme_set(
theme_minimal() +
theme(legend.position = "top")
)
ICE.gathered <- ICE_data %>%
as_tibble() %>%
select_if(is.numeric) %>%
gather(key = "variable", value = "value")
ggplot(ICE.gathered, aes(value)) +
geom_density(fill = "lightgrey") +
facet_wrap(~variable)
```
## Confirmatory Factor Analysis
We conduct the CFA with the Satorra-Bentler MLM because the data deviates significantly from normal distribution. Yet, there is no need to use MLR because we have complete data.
### Model specification
First, we specify the model based on the results from Marczak et al., 2022
```{r, include=T, echo = T}
model <- 'climate_anger =~ ICE.60.no.ANG14 + ICE.60.no.ANG13 + ICE.60.no.ANG10 + ICE.60.no.ANG3
climate_contempt =~ ICE.60.no.DIS5 + ICE.60.no.DIS7 + ICE.60.no.IND2 + ICE.60.no.IND13
climate_enthusiasm =~ ICE.60.no.EMP12 + ICE.60.no.HOPF9 + ICE.60.no.HOPF8 + ICE.60.no.EMP7
climate_powerlessness =~ ICE.60.no.POWL11 + ICE.60.no.POWL7 + ICE.60.no.POWL2 + ICE.60.no.POWL13
climate_guilt =~ ICE.60.no.GUI11 + ICE.60.no.GUI6 + ICE.60.no.GUI8 + ICE.60.no.GUI12
climate_isolation =~ ICE.60.no.ISO4 + ICE.60.no.ISO5 + ICE.60.no.ISO8 + ICE.60.no.ISO12
climate_anxiety =~ ICE.60.no.APP7 + ICE.60.no.HOPL5 + ICE.60.no.HOPL11 + ICE.60.no.APP14
climate_sorrow =~ ICE.60.no.SOR13 + ICE.60.no.SOR6 + ICE.60.no.SOR4 + ICE.60.no.SOR14'
```
In the next step, we fit the model with the MLM estimator
```{r, include=T, echo = T}
model.fit <- cfa(model, data = ICE_data, estimator = "MLM")
```
### Fit indices
We inspect the standard indices for model fit
```{r, include=T}
fitmeasures(model.fit, fit.measures = c("chisq.scaled", "pvalue.scaled", "df.scaled", "cfi.scaled", "tli.scaled", "rmsea.scaled", "rmsea.ci.lower.scaled", "rmsea.ci.upper.scaled", "srmr"))
```
Reasonably good fit is established by a model when the (in our case scaled) CFI and TLI values are close to .95 or greater, RMSEA values are close to .06 or below, and SRMR values are close to or below .08 (Hu & Bentler, 1999).
We can see that our model presents reasonably good fit.
### Model characteristics {.tabset}
#### Facor loadings, variances etc
```{r, include=T}
lavaan::summary(model.fit, fit.measures = T, standardized = T)
```
We observe good values here too. Importantly, all factor loadings are > .4.
#### CFA: convergent validity
Convergent validity is established when the average variance extracted (AVE) by the latent variables is greater than .5
```{r, include=T}
knitr::kable(condisc(model.fit)$Average_Variance_Extracted, col.names = "AVE", "simple")
```
Climate powerlessness has AVE < the standard cutoff .5
#### CFA: discriminant validity
```{r, include=F}
#to keep it clean, create a new data frame for the selected indicators
ICE_select <- c(
"ICE.60.no.ANG14", "ICE.60.no.ANG13", "ICE.60.no.ANG10", "ICE.60.no.ANG3",
"ICE.60.no.DIS5", "ICE.60.no.DIS7", "ICE.60.no.IND2", "ICE.60.no.IND13",
"ICE.60.no.EMP12", "ICE.60.no.HOPF9", "ICE.60.no.HOPF8", "ICE.60.no.EMP7",
"ICE.60.no.POWL11", "ICE.60.no.POWL7", "ICE.60.no.POWL2", "ICE.60.no.POWL13",
"ICE.60.no.GUI11", "ICE.60.no.GUI6", "ICE.60.no.GUI8", "ICE.60.no.GUI12",
"ICE.60.no.ISO4", "ICE.60.no.ISO5", "ICE.60.no.ISO8", "ICE.60.no.ISO12",
"ICE.60.no.APP7", "ICE.60.no.HOPL5", "ICE.60.no.HOPL11", "ICE.60.no.APP14",
"ICE.60.no.SOR13", "ICE.60.no.SOR6", "ICE.60.no.SOR4", "ICE.60.no.SOR14"
)
ICE_data_short <- ICE_data[ICE_select]
# add the values for latent factors
ICE_data_short <- ICE_data_short %>%
mutate(climate.anger = rowSums(.[1:4]),
climate.contempt = rowSums(.[5:8]),
climate.enthusiasm = rowSums(.[9:12]),
climate.powerlessness = rowSums(.[13:16]),
climate.guilt = rowSums(.[17:20]),
climate.isolation = rowSums(.[21:24]),
climate.anxiety = rowSums(.[25:28]),
climate.sorrow = rowSums(.[29:32]))
#compute mean correlations between latent variables and their indicators (Mehmet's recommendation for discriminant validity)
ang.m <- mean(cor(ICE_data_short[1:4], ICE_data_short$climate.anger))
cont.m <- mean(cor(ICE_data_short[5:8], ICE_data_short$climate.contempt))
enth.m <- mean(cor(ICE_data_short[9:12], ICE_data_short$climate.enthusiasm))
powl.m <- mean(cor(ICE_data_short[13:16], ICE_data_short$climate.powerlessness))
gui.m <- mean(cor(ICE_data_short[17:20], ICE_data_short$climate.guilt))
iso.m <- mean(cor(ICE_data_short[21:24], ICE_data_short$climate.isolation))
anx.m <- mean(cor(ICE_data_short[25:28], ICE_data_short$climate.anxiety))
sor.m <- mean(cor(ICE_data_short[29:32], ICE_data_short$climate.sorrow))
```
Discriminant validity is established when the average correlation between a latent variable and its indicators is higher than the squared correlation between the latent variables (Fornell & Larcker, 1981).
Here are the average correlations between latent variables and their indicators:
```{r, include=T}
data.frame(ang.m, cont.m, enth.m, powl.m, gui.m, iso.m, anx.m, sor.m)
```
And here is a table with squared factor correlations:
```{r, include=T}
knitr::kable(condisc(model.fit)$Squared_Factor_Correlation, "simple")
```
For climate sorrow the the squared correlation between it and anger is equal to the average correlation between a latent variable and its indicators. There are no problems with other variables.
### Factor internal consistencies {.tabset}
#### Raykov's rho
```{r, include=T}
raykovrho <- astatur::relicoef(model.fit)
raykov.coefficient <- round(raykovrho$RRC, 2) #rounded
clim.emotion <- c("climate_anger", "climate_contempt", "climate_enthusiasm", "climate_powerlessness", "climate_guilt", "climate_isolation", "climate_anxiety", "climate_sorrow")
knitr::kable(cbind(clim.emotion, raykov.coefficient), "simple")
```
#### Cronbach's alpha
```{r, include=T}
knitr::kable(round(semTools::reliability(model.fit, what = "alpha"), 2)[1,], col.names = "alpha", "simple")
```
Both coefficients indicate very good internal consistency across scales.
## Nomological span
```{r, include=F}
#subset the data frame to work with for now
others <- dplyr::select(qdata, starts_with(c("CCPS", "MPS", "ULS", "WTS")))
others <- as.data.frame(others)
#change the variables type from character to numeric (keeping them in the data frame format)
others <- as.data.frame(lapply(others, as.numeric))
####explore & inspect the ICE data for consistency
#is there any missing data?
sum(colSums(is.na(others)))
#a categorical representation of the data to check for inconsistent values
lapply(others, table)
# For the descriptives, the response format should be 1-5 not 0-4, hence we add 1 to each value in the data frame
others <- others + 1
#but not for climate change beliefs scale as 0 on that scale means that somebody doesn't believe in climate change
others[,c(1:5)] <- others[,c(1:5)] - 1
# overview of the data
#psych::describe(s2.general)
```
### Recoding the reverse scored items
Some items from the scales relevant for establishing concurrent & predictive validity are reversely scored. We need to recode them.
```{r, include=T, echo = TRUE}
#### CPS: 5
others$CCPS.no.4 <- 8 - others$CCPS.no.4
### ULS: 3 & 6 (2 & 5 in the numeration of this dataset)
others$ULS.no.2 <- 5 - others$ULS.no.2
others$ULS.no.5 <- 5 - others$ULS.no.5
```
### Internal consistencies of other scales
Here, let's compute Cronbach's alpha coefficient for all the relevant scales.
```{r, include=F}
Climate_perceptions <- dplyr::select(others, c(1:5))
Mit_policy <- dplyr::select(others, c(6:10))
Loneliness <- dplyr::select(others, c(11:18))
WillingnessToSacrifice <- dplyr::select(others, c(19:23))
s_reliabilities_list <- list(Climate_perceptions,
Mit_policy,
Loneliness,
WillingnessToSacrifice)
compute.alpha.each.scale <- (lapply(s_reliabilities_list, psych::alpha, check.keys=TRUE))
s_reliabilities <- sapply(compute.alpha.each.scale, "[[", 1)[1:2,]
colnames(s_reliabilities) <- c("Climate_perceptions",
"Mit_policy",
"Loneliness",
"WillingnessToSacrifice")
```
```{r, include=T}
knitr::kable(s_reliabilities, "simple")
```
### Descriptives for all the scales
```{r, include=F}
###create a data frame with global and dimensional results for each scale
## add the final ICE scales to it
glob_dim <- data.frame(climate_perceptions = rowSums(others[1:5])/5,
Mit_policy = rowSums(others[, c(6:10)])/5,
Loneliness = rowSums(others[, c(11:18)])/8,
WillingnessToSacrifice = rowSums(others[, c(19:23)])/5
)
#add ICE scales to this data frame
#but first, change total score to mean
ICE_scales_means <- ICE_data_short[,33:40]/4
all <- cbind(glob_dim, ICE_scales_means)
```
```{r, include=T}
#### descriptives for all the data
colnames(all) <- c("pro-climate perceptions", "mitigation policy support", "loneliness", " willingness to sacrifice", "climate anger", "climate contempt", "climate enthusiasm", "climate powerlessness", "climate guilt", "climate isolation", "climate anxiety", "climate sorrow")
knitr::kable(psych::describe(all), "simple")
```
```{r, include=F}
## save the descriptives to copy it easily to the paper
#descriptivez <- psych::describe(all)
#write.table(descriptivez, file = "Descriptives_NOR.csv", sep = ";")
```
### Distribution of the variables
We will investigate the distribution using the Shapiro-Wilk test.
```{r, include=T}
#formal inspection with shapiro-wilk test
lapply(all, shapiro.test)
```
For all variables p < .05 so we can say that most of our variables deviate from normal distribution
```{r, include=F}
#### Visual inspection
#scale the data so that the graphs can be displayed together
data.scaled <- scale(all)
data.gathered <- data.scaled %>%
as_tibble() %>%
select_if(is.numeric) %>%
gather(key = "variable", value = "value")
ggplot(data.gathered, aes(value)) +
geom_density(fill = "lightgrey") +
facet_wrap(~variable)
```
### Correlational analysis
As the data deviates from the normal distribution and because it is ordinal anyways, let's use Spearman correlation coefficients.
```{r, include=T}
###### Add demographic variables to the dataframe for additional correlations
dems_cor <- dplyr::select(qdata, starts_with("demo"))
dems_cor <- as.data.frame(dems_cor)
#rename the variables so that it's easier to navigate
colnames(dems_cor) <- c("cc_concern", "gender", "yearOfbirth", "country", "language1", "area", "education", "any_views", "any_l_r", "perceived_SES", "second_lang", "edu_other_specify", "politicalViews", "gender_other_specify")
age <- 2022 - as.numeric(dems_cor$yearOfbirth)
dems_cor <- as.data.frame(lapply(dems_cor, as.numeric))
#add dems_cor to all for the analysis
all2 <- cbind(dems_cor$cc_concern, dems_cor$gender, age, dems_cor$area, dems_cor$education, rev(dems_cor$perceived_SES), all)
colnames(all2) <- c("climate concern", "gender", "age", "residence area", "education", "perceived SES", "pro-climate perceptions", "mitigation policy support", "loneliness", " willingness to sacrifice", "climate anger", "climate contempt", "climate enthusiasm", "climate powerlessness", "climate guilt", "climate isolation", "climate anxiety", "climate sorrow")
#table(all2$gender)
# filter out one case of gender = 2 (other)
#which(all2$gender==2) #246
all2 <- all2[-c(246), ]
#table(all2$gender)
# filter out one case of education = 4 (other)
#which(all2$education==4) #2
all2 <- all2[-c(2), ]
#table(all2$education)
#merge "secondary education" and "vocational training" into one level
all2$education <- as.factor(all2$education)
levels(all2$education)[levels(all2$education)=="1"] <-"2"
#change the numbering of factors in education so that it starts from 1
all2$education <- dplyr::recode(all2$education, '0' = '1', '2' = '2', '3' = '3')
all2$education <- as.numeric(all2$education)
```
```{r, include=T}
knitr::kable(correlation_matrix(all2, type = "spearman", digits = 2, use = 'lower', replace_diagonal = T), "simple")
#save_correlation_matrix(all, filename = "correlations_NOR.csv", type = "spearman", digits = 2, use = 'lower', replace_diagonal = T)
```
Note: N = 489; Climate concern: 0 - "Not at all concerned", 1 - "Not very concerned", 2 - "Somewhat concerned", 3 - "Very concerned", 4 - "Extremely concerned"; Gender: 0 - Female, 1 - Male (the option "other" (n = 1) was not included in this correlational analysis); Residence area: 0 - "A big city", 1 - "The suburbs or outskirts of a big city", 2 - "A town or a small city", 3 - "A country village", 4 - "A farm or home in the countryside"; Education: 0 - "Primary education", 1 - "Secondary education or vocational training", 3 - "University/college degree" (the option "other" (n = 1) was not included in this correlational analysis); Perceived SES: 0 - "Finding it very difficult on present income", 1 - ""Finding it difficult on present income", 2 - "Coping on present income", 3 - "Living comfortably on present income".
#### Heatmap
A hierarchically clustered heatmap summarising the correlational analysis; the clustering was performed based on the complete-linkage method.
```{r, include=T}
###correlation heatmap 2 - clustered (the version used in the manuscript)
library(ggcorrplot)
corr <- round(cor(all2), 2)
# Compute a matrix of correlation p-values
p.mat <- cor_pmat(all2)
# Get the upper triangle clustered heatmap
ggcorrplot(corr, hc.order = TRUE, type = "upper",
outline.col = "white", legend.title = "Spearman's ρ", p.mat = p.mat, lab = F) +
theme(legend.position="bottom")
```
```{r, include=F}
###### Analyse the demographics for reporting in the manuscript
dems <- dplyr::select(qdata, starts_with("demo"))
dems <- as.data.frame(dems)
lapply(dems, table)
#rename the variables so that it's easier to navigate
colnames(dems) <- c("cc_concern", "gender", "yearOfbirth", "country", "language1", "area", "education", "any_views", "any_l_r", "perceived_SES", "second_lang", "edu_other_specify", "politicalViews", "gender_other_specify")
#add dems to s2.all for later analysis
all <- cbind(all, dems)
###decribe the demographics more for the paper - means etc
#Gender
table(dems$gender)
#50% women
#Age
age <- 2022 - as.numeric(dems$yearOfbirth)
psych::describe(age)
all <- cbind(all, age)
#all["age_group"] <- cut(all$age, c(0, 23, 35, 55, Inf), c("genZ", "millennial", "genX", "boomer"), include.lowest=TRUE)
prop.table(table(all$age_group))*100
# urban vs rural
round(prop.table(table(dems$area))*100, 0)
#0 - "A big city"
# 1 - The suburbs or outskirts of a big city"
# 2 - A town or a small city"
# 3 - "A country village"
# 4 - A farm or home in the countryside
# urban: big city, suburbs of a big city, small city or town; sum up
# educational attainment
round(prop.table(table(as.numeric(dems$education)))*100, 0)
# 0 - "Primary education"
# 1 -"Secondary education"
# 2 - "Vocational training"
# 3 - "University/College degree"
# 4 - ("Other" :subq ((:te "Please specify:")))))
# climate change concern
round(prop.table(table(dems$cc_concern))*100, 0)
#0 "Not at all concerned"
#1 "Not very concerned"
#2 "Somewhat concerned"
#3 "Very concerned"
#4 "Extremely concerned"
# perceived SES
round(prop.table(table(dems$perceived_SES))*100, 2)
# 0 "Living comfortably on present income"
# 1 "Coping on present income"
# 2 "Finding it difficult on present income"
# 3 "Finding it very difficult on present income"
```
## Note
This html output presents the general logic of the analysis along with some results not outlined in the main body of the manuscript. Please note that the full R code for the data cleaning and data analysis is available in the supplementary materials on the accompanying OSF website.