はじめに
以前(というかかなり昔),tidyrやdplyrについての記事を書きました。
どちらの記事を書いたときからもだいぶ月日が経っていて,dplyrのアップデート等もあって色々とやり方が変わっているのですが,自分自身が研究で分析をする際にアップデートしていたことをブログ記事には反映させられていないので,上の2本の記事のアップデート版のようなことを書いておこうと思います。
まずはサンプルデータ
#事前・事後・遅延事後でCAFのデータを取ってるというデザイン
pre.fluency <-rnorm(50,mean=10,sd=2)
pre.accuracy<-rnorm(50,mean=7,sd=2)
pre.complexity<-rnorm(50,mean=4,sd=2)
post.fluency<-rnorm(50,mean=14,sd=4)
post.accuracy<-rnorm(50,mean=10,sd=3)
post.complexity<-rnorm(50,mean=7,sd=2)
delayed.fluency<-rnorm(50,mean=12,sd=2)
delayed.accuracy<-rnorm(50,mean=8,sd=1)
delayed.complexity<-rnorm(50,mean=6,sd=1)
#それぞれの列を横にくっつける
dat<-cbind(pre.fluency,pre.accuracy,pre.complexity,post.fluency,post.accuracy,post.complexity,delayed.fluency,delayed.accuracy,delayed.complexity)
dat<-as.data.frame(dat) #データフレーム型に変換
dat$subject<-rep(1:50) #実験参与者のID列をつける
とりあえずこんな感じでいまデータを持ってるとする
head(dat)
## pre.fluency pre.accuracy pre.complexity post.fluency post.accuracy
## 1 9.344978 3.921626 4.5778491 13.932376 2.241629
## 2 9.126920 7.307178 3.2309289 13.624622 12.813440
## 3 13.433524 6.048270 5.0082008 7.932601 11.832851
## 4 11.937755 5.859142 0.6414096 11.289177 7.009059
## 5 7.913083 5.748651 2.6099159 17.933721 10.765706
## 6 8.683515 4.363661 5.4608116 16.550468 16.483160
## post.complexity delayed.fluency delayed.accuracy delayed.complexity subject
## 1 9.381369 10.628923 6.929672 7.923673 1
## 2 4.485729 14.456886 9.048825 5.306266 2
## 3 7.534226 13.031400 7.144670 7.781451 3
## 4 8.076248 12.390157 9.247418 6.244443 4
## 5 8.702016 9.604130 7.530200 5.927892 5
## 6 8.973912 8.060271 8.188526 6.458383 6
縦横変換
昔の縦横変換は,gatherでやっていました。現在は,pivot_関数を使います。その名の通り,縦長(long型)にするのがpivot_longer関数で,横長にするのがpivot_wider関数です。
library(dplyr)
dat %>%
tidyr::pivot_longer(cols = 1:9)
## # A tibble: 450 × 3
## subject name value
## <int> <chr> <dbl>
## 1 1 pre.fluency 9.34
## 2 1 pre.accuracy 3.92
## 3 1 pre.complexity 4.58
## 4 1 post.fluency 13.9
## 5 1 post.accuracy 2.24
## 6 1 post.complexity 9.38
## 7 1 delayed.fluency 10.6
## 8 1 delayed.accuracy 6.93
## 9 1 delayed.complexity 7.92
## 10 2 pre.fluency 9.13
## # … with 440 more rows
colsのところでどの列をまとめるかという指定をします。ここの指定は,上のやり方だと数字で列指定(1列目から9列目)としています。この部分はc()関数を使って文字列で指定してもいいですし,列指定のときに使えるstarts_with()やcontains() なんかもできます。例えば,まあこれはあくまで偶然そうなだけですけど,ここではまとめたい1列目から9列目はすべて”y”で終わっているので,以下のようにすることもできます。
dat %>%
tidyr::pivot_longer(cols = ends_with("y"))
## # A tibble: 450 × 3
## subject name value
## <int> <chr> <dbl>
## 1 1 pre.fluency 9.34
## 2 1 pre.accuracy 3.92
## 3 1 pre.complexity 4.58
## 4 1 post.fluency 13.9
## 5 1 post.accuracy 2.24
## 6 1 post.complexity 9.38
## 7 1 delayed.fluency 10.6
## 8 1 delayed.accuracy 6.93
## 9 1 delayed.complexity 7.92
## 10 2 pre.fluency 9.13
## # … with 440 more rows
また,まとめたくない列を”!“で指定することもできるので,今回のようにまとめないでほしい列が少ないという場合については,次のようにも出来ます。
dat %>%
tidyr::pivot_longer(!subject)
## # A tibble: 450 × 3
## subject name value
## <int> <chr> <dbl>
## 1 1 pre.fluency 9.34
## 2 1 pre.accuracy 3.92
## 3 1 pre.complexity 4.58
## 4 1 post.fluency 13.9
## 5 1 post.accuracy 2.24
## 6 1 post.complexity 9.38
## 7 1 delayed.fluency 10.6
## 8 1 delayed.accuracy 6.93
## 9 1 delayed.complexity 7.92
## 10 2 pre.fluency 9.13
## # … with 440 more rows
「まとめる」という感覚がいまいちよくわからないなぁとか,どの列を「まとめ」て,どの列は「まとめ」なくていいのかというのがピンと来ない場合には,次のように考えてください。
分析の際に従属変数(応答変数)となる列をまとめる
さて,今の段階ではまとめた際の列名が”name”になっていて,数値の部分が”value”という列名になっていますよね。ここも次のように指定できます。
dat %>%
tidyr::pivot_longer(!subject, names_to = "variable", values_to = "score")
## # A tibble: 450 × 3
## subject variable score
## <int> <chr> <dbl>
## 1 1 pre.fluency 9.34
## 2 1 pre.accuracy 3.92
## 3 1 pre.complexity 4.58
## 4 1 post.fluency 13.9
## 5 1 post.accuracy 2.24
## 6 1 post.complexity 9.38
## 7 1 delayed.fluency 10.6
## 8 1 delayed.accuracy 6.93
## 9 1 delayed.complexity 7.92
## 10 2 pre.fluency 9.13
## # … with 440 more rows
ただ,今回のケースではまとめた列に”pre”, “post”, “delayed”というテスト実施時期(test)という要因と,“complexity”, “accuracy”, “fluency”という測定値の要因が混在していますね。よって,あまり”name”の列名を変えることは意味がありません。むしろ,この列を分割してそれぞれの列に名前をつける必要があります。この列分割をseparate関数で行うという点は私が以前ブログ記事を書いた際と同じです。というわけで,次のようにします。
dat %>%
tidyr::pivot_longer(!subject) %>%
tidyr::separate(name, c("test","measure"), sep = "\\.")
## # A tibble: 450 × 4
## subject test measure value
## <int> <chr> <chr> <dbl>
## 1 1 pre fluency 9.34
## 2 1 pre accuracy 3.92
## 3 1 pre complexity 4.58
## 4 1 post fluency 13.9
## 5 1 post accuracy 2.24
## 6 1 post complexity 9.38
## 7 1 delayed fluency 10.6
## 8 1 delayed accuracy 6.93
## 9 1 delayed complexity 7.92
## 10 2 pre fluency 9.13
## # … with 440 more rows
これで,完璧ですね。と思いきや…!実はpivot_関数には”name_sep”という便利な引数があります。これはどういう時に使うかと言うと,まとめた際に一つの列に複数の要因が混在してしまうときに,それを指定した区切り文字によって分割するために使います。まさに上で起こった問題ですよね。テスト実施時期と測定値が一緒の列になっていたのをseparate関数で分割したわけですが,なんとseparateを使わなくても縦型に変換する段階で分割までできてしまいます。
dat %>%
tidyr::pivot_longer(!subject, names_to = c("test", "measure"), names_sep = "\\.", values_to = "score")
## # A tibble: 450 × 4
## subject test measure score
## <int> <chr> <chr> <dbl>
## 1 1 pre fluency 9.34
## 2 1 pre accuracy 3.92
## 3 1 pre complexity 4.58
## 4 1 post fluency 13.9
## 5 1 post accuracy 2.24
## 6 1 post complexity 9.38
## 7 1 delayed fluency 10.6
## 8 1 delayed accuracy 6.93
## 9 1 delayed complexity 7.92
## 10 2 pre fluency 9.13
## # … with 440 more rows
このときのポイントは2点あります。1つは”names_to”で列名を2つ指定すること。縦型変換の際に列の分割もするので,ここでのnames_toの指定は分割後の列名とします。もう一つは,区切り文字は正規表現を受け付けるということ。区切り文字がドット(.)なので,ここでnames_sep= “.”としてしまうと,正規表現におけるドットだと認識されてしまいます。これでは任意の1文字ですので,列名がうまく分割されずに以下のようになってしまいます。
dat %>%
tidyr::pivot_longer(!subject, names_to = c("test", "measure"), names_sep = ".", values_to = "score")
## Warning: Expected 2 pieces. Additional pieces discarded in 9 rows [1, 2, 3, 4,
## 5, 6, 7, 8, 9].
## # A tibble: 450 × 4
## subject test measure score
## <int> <chr> <chr> <dbl>
## 1 1 "" "" 9.34
## 2 1 "" "" 3.92
## 3 1 "" "" 4.58
## 4 1 "" "" 13.9
## 5 1 "" "" 2.24
## 6 1 "" "" 9.38
## 7 1 "" "" 10.6
## 8 1 "" "" 6.93
## 9 1 "" "" 7.92
## 10 2 "" "" 9.13
## # … with 440 more rows
したがって,正規表現ではありませんよということを追記する必要があります。このことをエスケープするなんて言いますが,Rにおけるエスケープは “\\”です。一般的にはエスケープは”\“ですが,R上では2つ重ねないといけないことに注意が必要です。
おわりに
とりあえず,long型に変換する作業をこの記事では説明しました。少し長くなってしまったので,記述統計を出すという話はまた別の記事にしたいと思います。
なにをゆう たむらゆう。
おしまい。
追記(2022.03.16)
従属変数を3列待ちにしたい(横長にしたい)
よく考えたら,分析するときはcomplexity, accuracy, fluencyの3つの列があったほうが便利ですよね。ということで,その形に変形させましょう。ここで,横長に変換するためのpivot_wider関数を使います。“names_from”の引数で「分解」したい列を指定します。ここでは,accuracy, complexity, fluencyの入っている“measure”の列を「分解」して横長にするので,“measure”を指定します。あとは,横長にしたときに持ってくる数値がどこに入っているかを“values_from”の引数で指定します。これは“score”に入ってますから,これを指定すればいいですね。というわけで,次のようになります。
dat %>%
tidyr::pivot_longer(!subject, names_to = c("test", "measure"), names_sep = "\\.", values_to = "score") %>%
tidyr::pivot_wider(names_from = "measure", values_from="score")
## # A tibble: 150 × 5
## subject test fluency accuracy complexity
## <int> <chr> <dbl> <dbl> <dbl>
## 1 1 pre 10.1 10.0 3.97
## 2 1 post 15.8 8.50 9.81
## 3 1 delayed 15.5 8.59 4.67
## 4 2 pre 12.0 6.40 1.03
## 5 2 post 6.90 10.1 7.30
## 6 2 delayed 15.0 8.54 7.70
## 7 3 pre 9.07 8.49 2.78
## 8 3 post 7.11 10.2 8.55
## 9 3 delayed 10.7 7.97 5.54
## 10 4 pre 12.5 6.03 2.26
## # … with 140 more rows
もしも,fluency, accuracy, complexityなどの順番が気になる場合は,select関数で指定してください。
dat %>%
tidyr::pivot_longer(!subject, names_to = c("test", "measure"), names_sep = "\\.", values_to = "score") %>%
tidyr::pivot_wider(names_from = "measure", values_from="score") %>%
dplyr::select(subject, test, complexity, accuracy, fluency)
## # A tibble: 150 × 5
## subject test complexity accuracy fluency
## <int> <chr> <dbl> <dbl> <dbl>
## 1 1 pre 3.97 10.0 10.1
## 2 1 post 9.81 8.50 15.8
## 3 1 delayed 4.67 8.59 15.5
## 4 2 pre 1.03 6.40 12.0
## 5 2 post 7.30 10.1 6.90
## 6 2 delayed 7.70 8.54 15.0
## 7 3 pre 2.78 8.49 9.07
## 8 3 post 8.55 10.2 7.11
## 9 3 delayed 5.54 7.97 10.7
## 10 4 pre 2.26 6.03 12.5
## # … with 140 more rows
この変換後のデータを別の変数に保存するのを忘れずに!
dat2 <- dat %>%
tidyr::pivot_longer(!subject, names_to = c("test", "measure"), names_sep = "\\.", values_to = "score") %>%
tidyr::pivot_wider(names_from = "measure", values_from="score") %>%
dplyr::select(subject, test, complexity, accuracy, fluency)
head(dat2)
## # A tibble: 6 × 5
## subject test complexity accuracy fluency
## <int> <chr> <dbl> <dbl> <dbl>
## 1 1 pre 3.97 10.0 10.1
## 2 1 post 9.81 8.50 15.8
## 3 1 delayed 4.67 8.59 15.5
## 4 2 pre 1.03 6.40 12.0
## 5 2 post 7.30 10.1 6.90
## 6 2 delayed 7.70 8.54 15.0
