オンライン実験をがんばった話

December 15, 2020
R labjs jsPsych

オンライン実験・調査に関するアドベントカレンダー15日目の記事です。

今年はいろいろありましたね。

私の所属する研究室は、実験心理学の研究室です。「我々は実験がアイデンティティ」というのがいつもボスとしゃべっていることで、今年は実験ができず、自分のアイデンティティが揺らぐ一年でした。

実験をしないと研究が進まないので、何かしらやろうと思って、今年の春はずっとオンライン実験の作り方を勉強していました。lab.jsやjsPsychというものがあるのを知って、小林先生のこのチュートリアルlab.js公式ドキュメントjsPsychの公式チュートリアルを見ていました。両方とも結構使いやすいツールなので(違いについてはこの記事を参照)結構すぐに実験が作れるようになりました。

結構lab.jsについては詳しくなった自信があります。JavaScriptも結構できるようになりました。1

でも結局のところ、私自身はこれまで一度もオンライン実験をしていないんですよね。自分がやりたい実験をオンラインでやるのは難しかったからです。

ただ勉強したことが何の役にも立たなかったわけではありません。オンライン実験をすることになった卒論生が多かったからです。私が所属する学科では学部3年のときにPsychoPy Builderの使い方を勉強するので、卒論生ならPsychoPyは一通り使えるのですが、lab.jsを使うことは想定していなかったはずで、とても大変だったと思います。lab.jsやjsPsychを使える人が研究室には私以外にいなかったので、オンライン実験を使った卒論については私がほぼすべての面倒を見ました。卒論生のがんばりには本当に頭が下がる思いです。

特に多かった質問2つと、それについての対処法をご紹介しようと思います。

Q1. オンライン実験はどうやって公開したらいいですか?

オンライン実験の作成じたいはlab.js, jsPsychなどでいいのですが、作ったものをどこで公開するのか?は結構難しい問題です。当初はQualtricsにlab.jsやjsPsychで作った実験を貼り込む方法 (jsPsychの実験を貼る方法についてはこちら; 柏原くんの記事も参照してください。こっちのほうが自分のより分かりやすい気が…) を推奨していたのですが、途中から推奨しなくなりました。なぜなら、Qualtricsから出てくるデータがめちゃめちゃuntidyだからです。Rに強い人なら気にならないかもしれませんが、そうでない人・Excelでなんとかしたい人にはつらいです。

そこで、Open Labを使い始めました。Open Labのいいところは、lab.jsとの連携が簡単なところです。こちらの公式ドキュメントページにも、連携の方法が載っています。細かいやり方はいつか時間のある時にまとめますが、基本的にはlab.jsのビルダーで保存ボタンの隣の矢印 (赤丸で示す) をクリックして、「Upload to Open Lab」を選ぶだけです。

300人までなら無料で実験できるので、卒論の実験には十分でしょう。ただ無料版だと2つ以上の実験を同時に実施することができないので、実験群を3つ設けて同じ数だけ参加者を取る、みたいなのは少し難しかったです。

Q2. Qualtricsにlab.jsの実験を貼り込んで実施したところ、lab.jsからのデータがJSON形式で出力されて、Excelでは内容がよくわかりません。

上で書いた「Qualtricsから出てくるデータがめちゃめちゃuntidy」ってやつですね。lab.jsの公式ドキュメントでQualtricsのデータ整理方法が紹介されていて、基本的にはこのRコードで解読できます。ただ、このRコードが結構難解なんですよね。一応簡単に解説します。

まず必要パッケージ (tidyverse, readr) を読み込みます。

Qualtricsからはcsv, tsv, xlsxなど様々な形式でデータを書き出すことが可能ですが、できればcsv形式で出力してください。tsvやxlsxだとRで扱うときにエラーを吐くことがあります。

library(tidyverse)
library(readr)

data_raw <- read_csv('data.csv')

次に、lab.jsのデータが入っている列の名前をlabjs_columnというオブジェクトに入れます。

labjs_column <- 'labjs-data'

次が、その列に入っているJSON形式のデータを、RやExcelで扱いやすい形のデータに変形させるためのコードです。難解ですが…。

data_raw %>%
  mutate(
    !!labjs_column := recode(.[[labjs_column]], .missing='[{}]')
  ) %>%
  group_by_all() %>%
  do(
    fromJSON(.[[labjs_column]], flatten=T)
  ) %>%
  ungroup() %>%
  select(-matches(labjs_column)) -> data

tidyverseを使っている人だったらmutate()などは見覚えがあると思いますが、recode()とか、あまり使わないですよね。switch()のベクトル版で、データを置き換えることができます。

vector <- c("a", "b", "c")
dplyr::recode(vector, a = "Apple")
## [1] "Apple" "b"     "c"

group_by_all()group_by()の兄弟みたいな関数です。

dplyr::group_by_all(mtcars) %>%
  head(10)
## # A tibble: 10 x 11
## # Groups:   mpg, cyl, disp, hp, drat, wt, qsec, vs, am, gear, carb [10]
##      mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
##    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1  21       6  160    110  3.9   2.62  16.5     0     1     4     4
##  2  21       6  160    110  3.9   2.88  17.0     0     1     4     4
##  3  22.8     4  108     93  3.85  2.32  18.6     1     1     4     1
##  4  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
##  5  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
##  6  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
##  7  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
##  8  24.4     4  147.    62  3.69  3.19  20       1     0     4     2
##  9  22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2
## 10  19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4

一応これでいけると思いますが、もし何かトラブったら教えてください。研究室内でもしょっちゅうトラブったのですが、トラブルシューティングも行き当たりばったりでやっていたので、あまりきちんと記録していなかったのです。


  1. 私はPythonとRの人なので、JavaScript書かなきゃいけないのか…と結構渋りました。が、やっておいてよかったとは思います。