複数の.csvファイル(じゃなくてもいいけど)を一気に結合する
本記事について
Online Psychological Experiment Advent Calendar 2020 第17日目の記事です。
最初は気軽にポエムでも書こうかと思っていたものの、他の記事がどれも真面目だったので、「だから、オレだってなんかしなくっちゃあな…カッコ悪くて2021年に行けねーぜ…」ということで急きょtipsを書くことにしました。
オンライン実験のデータがどのように保存されるか
もちろん、どんな実験をするかや、どのサービスを利用するかによって、話は変わります。しかし一般的には、「協力してくださった実験参加者の数だけ、ファイルが蓄積される」と思います。オフラインの(実験室で行うような)実験ならなおさらですね。
例えば僕自身は、こちらの記事を参考にして、lab.jsで作成した.jsonファイルを、Open Labにアップロードし、単語記憶課題のオンライン実験を行いました。その結果、実験参加者の数だけ個別の.csvファイルがサーバ上に蓄積されました。
複数の.csvファイル(じゃなくてもいいけど)を一気に結合したい
もちろん.csvファイルに限らず、全てのファイルが.xlsxでも良いのですが、ともかく拡張子が同じ複数のファイルを、1つのファイルに結合しなければ、前処理も分析もできないわけです。
実験参加者数が少なければ(例えば10人など)、1つのファイルを開いてデータをコピーして、別のファイルにペーストするのを繰り返す...という手作業でも、さほど手間にはならないでしょう(※言うまでもなく、これはヒューマンエラーが混入する恐れがあるので、避けるべきですが)。
しかしオンライン実験となると、一般的にサンプルサイズが大きくなりやすいと思うので、手作業は労力の観点から現実的ではありません(※くどいようですが、労力以外の観点からも、データをコピペでまとめるのは避けるべきです)。
purrrパッケージを使おう
R環境限定の話になりますが、purrr
パッケージを用いれば、同じディレクトリ内に存在する、拡張子が同じ全てのファイルを、1つのデータフレームに結合することが、容易にできます。
その方法は...これだっ!(他の方が作成された資料を共有していくツェペリ魂)
上の画像のコードは、tidyverse
パッケージをロードする前提で書かれているので、最低限必要なpurrr
パッケージとreadr
パッケージだけをロードした場合には、以下の書き方になります。
(tidyverse
パッケージをロードしたら、これら2つのパッケージも自動的にロードされますが)
library(purrr) library(readr) target_files = list.files("data/", pattern = ".csv$", full.names = TRUE) dat = purrr::map_df(target_files, readr::read_csv)
まず、 特定のディレクトリ内に存在する、拡張子が.csvのファイル名を全て、target_files
という名前のリストにまとめています。この場合は、現在の作業ディレクトリの中に、「data」という名前のフォルダがあり、その中に全ファイルが存在する想定です。
次に、 readr::read_csv()
関数で個々の.csvファイルを読み込むたび、purrr::map_df()
で1つのデータフレームとして結合していきます。結合されたデータフレームは、dat
という名前のオブジェクトに格納されます。
自分用にカスタマイズも可能
データによっては、
- ファイルを読み込む際に、空欄のセルを
NA
にしたい - ファイル名も、データフレーム内の変数として保存したい
などの、細かいカスタムが必要となることもあるでしょう。そのような場合には、データを読み込む関数(上のコードではreadr::read_csv()
)をカスタムした自作関数を定義すればよいです。
ここで新たにdplyr
パッケージをロードしているので、パイプ演算子%>%
を使用しています(それだったらtidyverse
パッケージを1つロードすればよい気もしなくもない)。
library(purrr) library(readr) library(dplyr) # 自作関数 read_func = function(x){readr::read_csv(file = x, na = "") %>% dplyr::mutate(filename = x)} target_files = list.files("data/", pattern = ".csv$", full.names = TRUE) dat = purrr::map_df(target_files, read_func)
このコードでは、read_func()
という関数を自作しています。
まずreadr::read_csv()
でファイルを読み込む際に、空白のセルをNA
にするよう、引数を指定しています。さらに、1つのファイルをそのようにして読み込んだあとで、dplyr::mutate()
によって、ファイル名をfilename
という名前の列に追記しています。
あとはpurrr::map_df()
のなかで、自作した関数read_func()
を使用することを明記するだけです。
おわり
全てのデータが、1つのデータフレームにまとめられれば、第15日目の記事のように前処理を行うことも、分析することもできます。
Enjoy !!