4
4
# #
5
5
# # Usage:
6
6
# #
7
- # # Rscript generate-codebook.R path/to/qsf path/to/codebook
7
+ # # Rscript generate-codebook.R [UMD/CMU] path/to/qsf path/to/codebook
8
8
9
9
suppressPackageStartupMessages({
10
10
library(tidyverse )
@@ -17,81 +17,32 @@ suppressPackageStartupMessages({
17
17
18
18
19
19
process_qsf <- function (path_to_qsf ,
20
+ survey_version = c(" CMU" , " UMD" ),
20
21
path_to_shortname_map = " ./static/item_shortquestion_map.csv" ,
21
22
path_to_replacement_map = " ./static/item_replacement_map.csv" ) {
23
+ survey_version <- match.arg(survey_version )
22
24
q <- read_json(path_to_qsf )
23
25
wave <- get_wave(path_to_qsf )
24
26
25
- # get the survey elements with flow logic (should be one per block randomization branch)
26
- ii_flow <- q $ SurveyElements %> %
27
- map_chr(" Element" ) %> %
28
- {. == " FL" } %> %
29
- which()
30
- ii_block_randomizer <- q $ SurveyElements [ii_flow ] %> %
31
- map(~ .x $ Payload $ Flow ) %> %
32
- map(~ map(.x ,~ .x $ Type == " BlockRandomizer" )) %> %
33
- unlist() %> %
34
- which()
35
- random_block_ids <- q $ SurveyElements [ii_flow ] %> %
36
- map(~ .x $ Payload $ Flow ) %> %
37
- map(~ .x [ii_block_randomizer ]) %> %
38
- map(~ map(.x ,~ .x $ Flow )) %> %
39
- map(~ map(.x ,~ map(.x ,~ .x $ ID ))) %> %
40
- unlist()
41
-
42
- block_id_item_map <- get_block_item_map(q )
43
- block_id_item_map <- block_id_item_map %> % filter(BlockID %in% random_block_ids ) %> %
44
- select(- BlockID )
45
-
46
- # get the survey elements that are questions:
47
- ii_questions <- q $ SurveyElements %> %
48
- map_chr(" Element" ) %> %
49
- {. == " SQ" } %> %
50
- which()
51
-
52
- # get the questions that were shown to respondents
53
- shown_items <- get_shown_items(q )
54
- ii_shown <- q $ SurveyElements [ii_questions ] %> %
55
- map_chr(~ .x $ Payload $ QuestionID ) %> %
56
- {. %in% shown_items } %> %
57
- which()
27
+ displayed_questions <- subset_qsf_to_displayed(q )
58
28
59
- # subset qsf to valid elements
60
- displayed_questions <- q $ SurveyElements [ii_questions ][ii_shown ]
61
-
62
- # Qualtrics auto-assigned question IDs
29
+ # get Qualtrics auto-assigned question IDs
63
30
qids <- displayed_questions %> %
64
31
map_chr(~ .x $ Payload $ QuestionID )
65
32
66
- # the items are how we will match these to the survey data:
67
- items <- displayed_questions %> %
68
- map_chr(~ .x $ Payload $ DataExportTag )
69
-
70
- # B13 was originally named incorrectly. Rename manually as needed
71
- items [items == " B13 " ] <- " B13"
72
- # V2a in Wave 13 was originally named incorrectly. Rename manually as needed
73
- if (wave == 13 ) {
74
- items [items == " V2a" ] <- " V2d"
75
- }
33
+ # get item names
34
+ item_names <- displayed_questions %> %
35
+ map_chr(~ .x $ Payload $ DataExportTag ) %> %
36
+ patch_item_names(survey_version , wave )
76
37
77
- # get the text of the question :
38
+ # get question text:
78
39
questions <- displayed_questions %> %
79
40
map_chr(~ .x $ Payload $ QuestionText )
80
41
81
- # get the type of question:
82
- type_map <- c(MC = " Multiple choice" , TE = " Text" , Matrix = " Matrix" )
83
- qtype <- displayed_questions %> %
84
- map_chr(~ .x $ Payload $ QuestionType ) %> %
85
- {type_map [. ]}
86
-
87
- ii_multiselect <- displayed_questions %> %
88
- map_chr(~ .x $ Payload $ Selector ) %> %
89
- {. == " MAVR" } %> %
90
- which()
91
- qtype [ii_multiselect ] <- " Multiselect"
92
- qtype [items == " A5" ] <- " Matrix" # this will be treated like C10
93
-
94
- # get the choices (for MC and Matrix):
42
+ # get question types
43
+ qtype <- get_question_formats(displayed_questions , item_names , survey_version )
44
+
45
+ # get choices for multiple choice (MC) and Matrix items:
95
46
choices <- displayed_questions %> %
96
47
map(~ .x $ Payload $ Choices ) %> %
97
48
map(~ map(.x , " Display" ))
@@ -122,8 +73,8 @@ process_qsf <- function(path_to_qsf,
122
73
map(which ) %> %
123
74
map(names ) %> %
124
75
unlist()
125
- other_text_items <- paste(items [ii_other_text_option ], text_elem , " TEXT" , sep = " _" ) %> %
126
- setNames(items [ii_other_text_option ])
76
+ other_text_items <- paste(item_names [ii_other_text_option ], text_elem , " TEXT" , sep = " _" ) %> %
77
+ setNames(item_names [ii_other_text_option ])
127
78
128
79
# some questions port the choices from other questions
129
80
ii_carryforward <- displayed_questions %> %
@@ -189,7 +140,7 @@ process_qsf <- function(path_to_qsf,
189
140
paste(c(qid , selectable_text , option_code ), collapse = " " )
190
141
}, .x )) %> %
191
142
# Replace QID with question number (A2, etc)
192
- map(~ gsubfn(" (QID[0-9]+)" , function (qid ) {items [qids == qid ]}, .x )) %> %
143
+ map(~ gsubfn(" (QID[0-9]+)" , function (qid ) {item_names [qids == qid ]}, .x )) %> %
193
144
# Collapse logic into a single string.
194
145
map(~ paste(.x , collapse = " " ))
195
146
@@ -220,7 +171,7 @@ process_qsf <- function(path_to_qsf,
220
171
unlist()
221
172
222
173
# format all qsf content lists into a single tibble
223
- qdf <- tibble(variable = items ,
174
+ qdf <- tibble(variable = item_names ,
224
175
question = questions ,
225
176
type = qtype ,
226
177
choices = choices ,
@@ -229,8 +180,9 @@ process_qsf <- function(path_to_qsf,
229
180
response_option_randomization = response_option_randomization )
230
181
231
182
# Add on module randomization
183
+ block_id_item_map <- map_qids_to_module(q )
232
184
block_id_item_map <- block_id_item_map %> %
233
- left_join(data.frame (qid = qids , item = items ), by = c(" Questions" = " qid" ))
185
+ left_join(data.frame (qid = qids , item = item_names ), by = c(" Questions" = " qid" ))
234
186
qdf <- qdf %> % left_join(block_id_item_map , by = c(variable = " item" )) %> %
235
187
rename(group_of_respondents_item_was_shown_to = BlockName )
236
188
@@ -289,16 +241,21 @@ process_qsf <- function(path_to_qsf,
289
241
select(new ) %> %
290
242
unnest(new )
291
243
292
- # A5 and C10 are special cases b/c of they are matrix of text entry questions:
293
- # also C10 needs an extra _1.
294
- matrix_items <- matrix_items %> %
295
- mutate(variable = if_else(str_starts(variable , " C10" ), paste0(variable , " _1" ), variable ),
296
- type = if_else(str_starts(variable , " A5|C10" ), " Text" , type ),
297
- choices = if_else(str_starts(variable , " A5|C10" ), list (list ()), choices ))
244
+ # Custom matrix formatting
245
+ if (survey_version == " CMU" ) {
246
+ # A5 and C10 are special cases b/c they are matrices of text entry questions:
247
+ # also C10 needs an extra _1.
248
+ matrix_items <- matrix_items %> %
249
+ mutate(variable = if_else(str_starts(variable , " C10" ), paste0(variable , " _1" ), variable ),
250
+ type = if_else(str_starts(variable , " A5|C10" ), " Text" , type ),
251
+ choices = if_else(str_starts(variable , " A5|C10" ), list (list ()), choices ))
252
+ } else if (survey_version == " UMD" ) {
253
+ # pass
254
+ }
298
255
299
256
qdf <- bind_rows(nonmatrix_items , matrix_items )
300
257
301
- # indicate which items have replaced old items.
258
+ # indicate which new items have replaced old items.
302
259
replaces_map <- read_csv(path_to_replacement_map ,
303
260
col_types = cols(new_item = col_character(),
304
261
old_item = col_character()
@@ -465,11 +422,12 @@ add_qsf_to_codebook <- function(path_to_qsf, path_to_codebook) {
465
422
466
423
args <- commandArgs(TRUE )
467
424
468
- if (length(args ) != 2 ) {
469
- stop(" Usage: Rscript generate-codebook.R path/to/qsf path/to/codebook" )
425
+ if (length(args ) != 3 ) {
426
+ stop(" Usage: Rscript generate-codebook.R [UMD/CMU] path/to/qsf path/to/codebook" )
470
427
}
471
428
472
- path_to_qsf <- args [1 ]
473
- path_to_codebook <- args [2 ]
429
+ survey_version <- args [1 ]
430
+ path_to_qsf <- args [2 ]
431
+ path_to_codebook <- args [3 ]
474
432
475
433
invisible (add_qsf_to_codebook(path_to_qsf , path_to_codebook ))
0 commit comments