UPDATE: 2023-06-13 11:28:24

はじめに

GoogleFormのマルチアンサーを処理する方法をここではまとめておく。

GoogleFormのマルチアンサー

GoogleFormのマルチアンサーをエクスポートすると下記のようなq2カラムの形式でエクスポートされるらしい。確かに一般的なアンケートツールからエクスポートされる値の形式とは異なる。ちなみにcという選択肢は存在しているが、だれも回答していケースを想定している。

library(tidyverse)
library(rlang)

df <- tibble(
  id = 1:5,
  q1 = c(1,2,3,4,2),
  q2 = c('a,b,d','a,b','b,d','a,d','d')
)
df
## # A tibble: 5 × 3
##      id    q1 q2   
##   <int> <dbl> <chr>
## 1     1     1 a,b,d
## 2     2     2 a,b  
## 3     3     3 b,d  
## 4     4     4 a,d  
## 5     5     2 d

すぐに思いつく方法としては、文字列を含んでいたら、TRUEなり、その選択肢をif_else関数で返す方法。

df %>% 
  mutate(
    q2_a = if_else(str_detect(q2, 'a'), 'a', NA),
    q2_b = if_else(str_detect(q2, 'b'), 'b', NA),
    q2_c = if_else(str_detect(q2, 'c'), 'c', NA),
    q2_d = if_else(str_detect(q2, 'd'), 'd', NA)
  )
## # A tibble: 5 × 7
##      id    q1 q2    q2_a  q2_b  q2_c  q2_d 
##   <int> <dbl> <chr> <chr> <chr> <chr> <chr>
## 1     1     1 a,b,d a     b     <NA>  d    
## 2     2     2 a,b   a     b     <NA>  <NA> 
## 3     3     3 b,d   <NA>  b     <NA>  d    
## 4     4     4 a,d   a     <NA>  <NA>  d    
## 5     5     2 d     <NA>  <NA>  <NA>  d

できなくはないが、これでは選択肢20個あるなら、20行必要になるし、マルチアンサー質問が5つあると、100行必要になる。上記のように機能する関数を書けば良いのでは?という話があるが、下記のよううな方法でもできそうなので、ここではその方法をまとめておく。

まずは選択肢のユニークなベクトルを作成しておく。

col_val <- separate_rows(df, q2, sep = ",") %>% 
  select(q2) %>% 
  distinct() %>% 
  pull() %>% 
  append('c') %>% 
  sort()

col_val
## [1] "a" "b" "c" "d"

この選択肢ベクトルを利用して、map2_dfc関数で、カラム内の値を選択肢ベクトルの値の長さ分、判定してリストを作成する。そして、そのリストをデータフレーム化する。あとは、mutate関数の部分で、カラム名を使って、値を置換し、再度カラム名を修正する。

df %>%
  dplyr::select(q2) %>%
  purrr::map2_dfc(.x = ., .y = col_val, .f = function(x, y) {str_detect(x, pattern = y)}) %>% 
  rlang::set_names(col_val) %>% 
  # dplyr::mutate_if(is.logical, function(x){if_else(x, quo_text(quo(x)), NA_character_)})
  dplyr::mutate(across(is.logical, ~ if_else(.x, quo_text(quo(.x)), NA_character_))) %>% 
  rlang::set_names(str_c('q2_', col_val)) %>%
  dplyr::bind_cols(df, .)
## # A tibble: 5 × 7
##      id    q1 q2    q2_a  q2_b  q2_c  q2_d 
##   <int> <dbl> <chr> <chr> <chr> <chr> <chr>
## 1     1     1 a,b,d a     b     <NA>  d    
## 2     2     2 a,b   a     b     <NA>  <NA> 
## 3     3     3 b,d   <NA>  b     <NA>  d    
## 4     4     4 a,d   a     <NA>  <NA>  d    
## 5     5     2 d     <NA>  <NA>  <NA>  d

場合にもよるが、アンケートの仕様がそこまで変わらないのであれば、めんどくさいけどif_else関数の方法のほうが可読性は高いかも。

追記

一晩寝たらそもそもこんなことしなくても下記の方法でも実現できそうなことに気がついたのでメモしておく。

df %>% 
  dplyr::select(-q1) %>% 
  tidyr::separate_rows(q2, sep = ',') %>% 
  tidyr::pivot_wider(
    names_from = q2,
    names_prefix = 'q2_',
    values_from = q2,
    values_fill = NA_character_
  ) %>% 
  mutate(q2_c = NA_character_) %>% 
  dplyr::select(-id) %>% 
  dplyr::bind_cols(df, .)
## # A tibble: 5 × 7
##      id    q1 q2    q2_a  q2_b  q2_d  q2_c 
##   <int> <dbl> <chr> <chr> <chr> <chr> <chr>
## 1     1     1 a,b,d a     b     d     <NA> 
## 2     2     2 a,b   a     b     <NA>  <NA> 
## 3     3     3 b,d   <NA>  b     d     <NA> 
## 4     4     4 a,d   a     <NA>  d     <NA> 
## 5     5     2 d     <NA>  <NA>  d     <NA>