タグ別アーカイブ: データハンドリング

[R] 1列だけの選択ならselect関数よりpull関数を使う

はじめに

dplyr使いの方で,select関数を使って特定の1列に対して何かしらの処理をするということをしたいときにエラーが出る人はpull関数を使いましょうという話です。ちなみに,$使えば問題は解決です。今回は,それ以外の方法で,というお話。

具体的になにをしようとしたか

私がどんな処理をしようとしたかについて少し触れておきます。ここはスキップしてもらっても構いません。

ある列の単語(1単語または2単語の英単語が入っている)の文字数をカウントするということをやろうとしていました。ピリオドが含まれていたり(e.g., “dogs.”),2語の場合は間に空白もあるので(e.g., “beautiful lake”,それらを除去して文字数を数える必要があります。そのためには,str_extract,str_replace, str_lengthなどの文字列処理関数を使う必要があります。しかし,これらの関数はベクトルを受け取って処理をするので,データフレームを渡してもエラーが出てしまうという問題に直面しました。

select関数の挙動

データフレームからある特定の列を引っ張ってくるというとき,もちろん$を使って,dat$wordのようにするのが一番簡単なのでそれでもいいのですけども,dplyr使いの方はselect関数を使っている方も多いのではと思います。ただし,select関数はデータフレームの中から特定の列を引っ張ってくると,それがたとえ1列であってもdata.frame型になります。

よって,処理に使う関数がベクトル型を要求するものだとエラーが発生することになるわけです。しかもやっかいなのは,「じゃあas.vector()関数」を噛ませればいいやんとやってみてもそれでは解決しないからです。理由はよくわかりません。

  dat %>% 
  select(word) %>% #wordという列に文字数カウントしたい文字列があるとする
  as.vector() %>%
  is.vector() #このコードではFALSEとなります

pull関数がすること

pull関数は,要するにdat$x1のように$を使って,またはdat[, x1]のように[,]を使ってデータフレームの中の特定の列を指定するのと同じ挙動をするということです(参考)。よって,pull関数の出力はベクトル型になります。

  dat %>% 
  pull(word) %>%
  is.vector() #このコードではTRUEとなります

というわけで,1列だけ持ってくるときに関数を使う場合はpull()関数を使いましょうというのが結論です。私は結局こういう感じで文字数カウントをしました。

  dat %>% 
  pull(word) %>%
  str_extract(.,"[^\\.]+") %>% #ピリオドを除去
  str_replace(.,pattern = "\\s",replacement = "") %>% #半角スペースを除去
  str_length()->rt_dat$length #文字数をカウント

$を使うと次のようになります。

  str_extract(dat$word,"[^\\.]+") %>% #ピリオドを除去
  str_replace(.,pattern = "\\s",replacement = "") %>% #半角スペースを除去
  str_length()-> dat$length #文字数をカウントしてlengthという列に入れる

$を使ったほうが行数が少なくなるので,そっちのほうがいいような気もしますが,工程の見やすさでいうとpull関数を使うほうが上かなという感じがします。

おわりに

もともと文字数はカウントしてあったのですが,ちょっと査読者の指摘でフィラー項目も入れて分析をやり直さないといけなくなってこういった処理が必要になりました。データ型って基本といえば基本なのですが,以外に気づかずにエラーで困ることもあるので,select関数の挙動について勉強になるいい機会でした。

ということで,pull関数とselect関数,場合によって使い分けましょう。

なにをゆう たむらゆう。

おしまい。

[R] mutateとacrossでデータの下処理を少しだけエレガントに

まえおき

私はdplyrは5年前くらいから使っていて,自分が扱うようなデータについて自分がやりたいことを(その表現方法のエレガントさは別として)表現することはできていました。ただ,近年dplyrはアップデートを重ねていました。昔覚えたやり方でやろうとしても,その関数は使えませんとか,その表記方法は違いますとか言われることが増えました。分析の下処理でやりたいことは基本的に研究が変わらないので同じです。よって,過去に自分が書いたスクリプトのコピペをすることが多いわけです。それができなくなっていたと。

特に,最近の更新でacross()という関数が導入されたことが変更として大きいなと思います。まだまだこのacross()に関する記事も少なかったので,自分が使うにあたって覚えたことをメモ代わりに書いておきます。ここでは,mutate関数と一緒に使うケースです。つまり,ある特定の列について,ある処理を施して,その処理を施した列をデータフレームに追加するという作業です。単純に列に対して処理を施すだけというのは結構記事があったんですが,列を追加することについては全部列挙するみたいな方法しか見つかりませんでした。そこでacross関数の出番というわけですね。

やりたいこと

例えば,今やってる研究のデータでは,データフレームの中に頻度のデータが入っています。これをログ変換したいとします。すると,これまでは以下のように書いていました。

log(dat$ColFreq)->dat$ColFreq_log #コロケーション頻度
log(dat$AdjFreq)->dat$AdjFreq_log #コロケーション内の形容詞の頻度
log(dat$NounFreq)->dat$NounFreq_log #コロケーション内の名詞の頻度
log(dat$MIScore)->dat$MIScore_log #Mutual Information Score

別にコピペ&書き換えみたいなことをしながらやればいいし,これでだめだってことはないんですけど,複数の列について

  1. 同じ関数を適用
  2. 列を追加する

という同じ動作をしているわけなので,これは一気にできたほうが応用可能性があがります。私は手作業でやるの無理みたいな列数のデータを扱うことはないんですが,もし仮にそういうデータを扱う場合には何十行も使うのは好ましくないし無駄な作業だといえます。そこで列に対して処理を施して追加するという機能があるmutate関数と,それを複数列に適用する際に便利なacross関数を組み合わせます。

やりかた

ちなみに,なんだかんだでdplyrのパッケージのPDFが一番わかりやすかったです(pp. 3-6のacross関数のセクションとpp. 43-46のmutate関数のセクション)。across関数の引数は,列(.cols),関数(.fns),追加する列の名前(.names)という3つの引数があります。よって,今回のケースで言えば列のところで頻度情報が入ってる列を選択し,関数はlogを選べばOKです。ただ,.namesがないと情報を上書きしてしまいます。.namesのところは手書きで全部列名指定してやらなかんのかと思いましたが,そんなことはありません。”{.col}”を使えば,もとの列名を使えます。これにあとは自分で好きなタグのようなものをつけてあげればいいですね。”{.fn}”というのも使えて,これは使った関数名が入ります。

ということで,以下のようにすれば頻度情報にログ変換して列追加という作業ができます。

dat%>%
  mutate(across(c(ColFreq, AdjFreq, NounFreq, MIScore),log,.names = "{.col}_log"))->dat

.namesの部分は”{.col}_log”としていますが,”{.col}_{.fn}”でも同じです。dat$ColFreq_log, dat$AdjFreq_log,dat$NounFreq_log,dat$MIScore_logという4つの列が追加されます。ちなみに,列指定の部分は列の数値(e.g., 1, 2)でも可能です。頻度の情報が5~8列目にあるなら,次のように書くこともできます。ある特定の文字列が含まれる列を選ぶcontains()関数starts_with()関数とかも使えるはずです(こういうのは調べれば結構例があります)。

dat%>%
  mutate(across(5:8,log,.names = "{.col}_log"))->dat

ちょっと応用

さて,mutate関数とacross関数でたいぶすっきりしたコードを書くことができました。そこでふと,私がもう一ついつも下処理で複数列に適用する作業を思い出しました。それは,変数の標準化です。いつもなら次のようにしてました。

dat$z.oqpt <-scale(dat$oqpt)[,1] #Oxford Placement Testの点数の中心化
dat$z.rating <-scale(dat$rating)[,1] #評定値の中心化

これも別に2行だけなので大したことないんですが,やってることは先ほどのログ変換と同じですので,これもmutate関数を使って書き直してみましょう。次のようになります。

dat%>%
  mutate(across(c(oqpt,rating),scale,.names = "z.{.col}"))->dat

これでうまくいっているようにも見えますが,実はscale関数って出力された結果がベクトルではありません(データ型を調べるとmatrix型なのがわかります)。よって,大抵の場合は分析に問題はありませんが,あとで(私の場合だと分析結果の図示とか)ベクトル形式が求められる関数に渡した際に問題が発生することがよくあります。データフレームをただ眺めるだけではそのことはわからないので,次のように工夫してあげる必要があります。

dat%>%
  mutate(across(c(oqpt,rating),~scale(.x)[,1],.names = "z.{.col}"))->dat

さきほどと関数部分の書き方が変わっているのがわかると思います。このように”~”をつける書記法はpurrr-styleと呼ばれるそうですが,これは一般的には関数内の引数を指定する場合によく用いられます。例えば,~mean(.x, na.rm=T) のように使います。”na.rm=T”は欠損値は外して関数を適用するという設定のようなものです。今回は引数の設定ではなく,~scale(.x)[,1]としています。”[,1]”とすることで,行列の1つ目の要素(つまりこれは標準化された数値のベクトル)だけを出力してくれます。ちなみに,この方法で.namesに{.fn}をつかって次のようにすると,出力される列名はoqpt_1, rating_1のようになりました(理由は不明)。

dat%>%
  mutate(across(c(oqpt,rating),~scale(.x)[,1],.names = "{.col}_{.fn}"))->dat

おわりに

というわけで,改良されているんだろうけれども前のやり方に慣れてるこっちからしたらアップデートたびにコードを書き換えるのまじで面倒…って思っていたのですが,調べてみるとやっぱり便利でしたというお話でした。

またこういう系のことで新しく覚えたことがあれば記事に書こうと思います。

なにをゆう たむらゆう。

おしまい。

【R】JSON形式で刺激リスト作成

はじめに

この記事では,よくある刺激のリストをJSON形式で保持するということをRを使ってやってみます。ただのデータフレームをJSON形式に変換するのはそれほど難しいことではありません。むしろ,Rを使わなくてもウェブ上で変換してくれるサービスがあります。
https://tableconvert.com/

こういうのを使うと,下記のようなテーブル形式のデータをcsvで持っていたとしたら,それをJSON形式に変換するのは一瞬です。

id name age gender
1 Roberta 39 M
2 Oliver 25 M
3 Shayna 18 F
4 Fechin 18 M
#JSON形式
[
    {"id":1,"name":"Roberta","age":39,"gender":"M"},
    {"id":2,"name":"Oliver","age":25,"gender":"M"},
    {"id":3,"name":"Shayna","age":18,"gender":"F"},
    {"id":4,"name":"Fechin","age":18,"gender":"M"}
]

問題の所在

じゃあ別にそのウェブサービスでいいじゃんということになるんですが,問題は少しこれより複雑です。というのも,私は今 jsPsychを使って実験ができるようにと勉強しています。jsPsychではJSON形式で刺激を読み込むのですが,その際に,データに階層性が必要になってくるようです。別に,反応の取得だけを目的とするなら必要ないのですが,のちのデータ分析を楽にすることを考えると,これは実験の前の段階でやっておきたいです1jsPsychのページでは以下のように例が示されています。

var test_stimuli = [
  { stimulus: "img/blue.png", data: {test_part: 'test', correct_response: 'f'}},
  { stimulus: "img/orange.png", data: {test_part: 'test', correct_response: 'j'}}
];

この例では,刺激として画像を提示するので,“stimulus”として画像ファイルが指定されています。そして,その後ろにdataという変数があって,要するに,実際に表示される刺激と,その刺激に付随する情報(正誤,刺激の種類等)が分かれていて,付随する情報は一つ階層が下のレベルに入っているということです。リストの中にリストがあるということですね。こうなると,ただのデータフレームからの変換というわけにはいかないので,先ほど紹介したようなウェブブラウザで変換というわけにもいきません。というわけで,Rを使って,できるだけ簡単にデータフレームから階層性のあるリストをゲットしましょう。というのが今回の目標です。実は,リスト->データフレームという話は,rlistパッケージ周りでやってる方が結構いらっしゃるようです(Googleで「rlist データフレーム 」と検索してみてください)。ところが,今回のようにデータフレーム->リストはあまり例が見つかりませんでした。ということでやってみましょう。結論から先にいうと,めちゃくちゃ単純でした。

1. データの準備

まずは,わかりやすい刺激リストの例として自分が最近実験で使った刺激リストを読み込みます。

dat<-read.csv("stimuli.csv")
head(dat)

一応,各列に何が入っているかを簡単にまとめると,以下のようになります。

  1. itemID: 刺激のID(かぶりがありますが,nonwordは分析から最初に外すのでとりあえずOK。ほんとは連番のがいいですけど)
  2. type: 刺激の種類
  3. word: ターゲットとなる英単語
  4. kana: 対応するカタカナ語
  5. pic: 提示する画像
  6. lang: 提示する言語
  7. prime: プライミング条件
  8. answer: 正答
  9. form: フォーム
  10. freq_J: カタカナ語の頻度
  11. freq_E: 英単語の頻度

この実験では,まずはじめに画像を提示して,参加者はその画像を見ます。画像を理解したら次に注視点が表示されます。その後に提示された文字列が実在語かどうかを判断する語彙性判断課題です。プライミングの条件がshare, spec, baseと3条件あります。さて,プログラム上では,

  1. 画像(pic)を提示
  2. 語(word)を提示

ということで,上で紹介した例と異なって,提示する刺激が2種類あります(ここでは,提示刺激は英単語のみとして進めます。カタカナ語の場合は英単語の部分をカタカナ語の列に置き換えれば良いと考えます)。つまり,

{ pic: "img/2_C_sh.jpg", word: "interview", data: {itemID: '2', kana: 'インタビュー', lang: 'eng', prime: 'share',answer: 'TRUE',form: 'A',freq_J: '29.5098', freq_E: '17.5744'}}

というのを読み込んだデータフレームのすべての行において作ることができれば成功となります。

2. パッケージの準備

とりあえず,これ入れとけばいいかなということでtidyverseパッケージと,最後にJSON形式に変換する際に使うjsonliteパッケージ。

install.packages("tidyverse")
install.packages("jsonlite")
library(tidyverse)
library(jsonlite)

3. データハンドリング

tibbleという比較的新しいデータ形式を使います。tidyrとかdplyrとか使うようになって,数年前からこのtibble形式がよく出てきてたんですが,私もいまいちよくわかってませんでした。というか,データフレームを扱うことがほとんどなので,データフレーム形式しか受け付けない関数にtibbleで出力された結果をうっかり渡してエラー吐くみたいなことが頻発したのでいちいちas.data.frame()でデータフレーム型に強制的に直すみたいなことをしてました。

ところが,今回みたいな階層性のある形については,tibble型が便利なようですね。tibbleでは,リスト型の列を持つことができるので,“data”の列に刺激の情報をまとめたリストを入れていけばいいということになります。そう考えて,次のようにやってみました。

tibble::tibble(
  pic=dat$pic,
  word=dat$word,
  data=list(dat[,c(1,2,4,6,7,8,9,10,11)])
)->dat2

ところが,これで中身を見てみると…

head(dat2)
## # A tibble: 6 x 3
##   pic         word        data             
##   <fct>       <fct>       <list>           
## 1 2_C_sh.jpg  interview   <df[,9] [48 × 9]>
## 2 3_C_sp.jpg  court       <df[,9] [48 × 9]>
## 3 6_C_sh.jpg  alien       <df[,9] [48 × 9]>
## 4 7_C_sp.jpg  appointment <df[,9] [48 × 9]>
## 5 10_C_sh.jpg stamp       <df[,9] [48 × 9]>
## 6 14_C_sh.jpg channel     <df[,9] [48 × 9]>
head(dat2$data,3)
## [[1]]
##    itemID    type               kana lang prime answer form   freq_J
## 1       2  target       インタビュー  eng share   TRUE    A  29.5098
## 2       3  target             コート  eng  spec   TRUE    A 100.7255
## 3       6  target         エイリアン  eng share   TRUE    A  17.4314
## 4       7  target   アポイントメント  eng  spec   TRUE    A  30.5686
## 5      10  target           スタンプ  eng share   TRUE    A   5.9216
## 6      14  target         チャンネル  eng share   TRUE    A  24.4118
## 7      15  target           クロール  eng  spec   TRUE    A  12.0392
## 8      18  target             センス  eng share   TRUE    A 131.8039
## 9      19  target             ベンチ  eng  spec   TRUE    A   9.6667
## 10     22  target     プロモーション  eng share   TRUE    A  10.9216
## 11     23  target               ツナ  eng  spec   TRUE    A   8.0000
## 12      1  target           アイロン  eng  base   TRUE    A  17.9412
## 13      4  target         グラウンド  eng  base   TRUE    A  72.4706
## 14      5  target           アドレス  eng  base   TRUE    A  52.2745
## 15      8  target       プレッシャー  eng  base   TRUE    A  53.1176
## 16      9  target         プロポーズ  eng  base   TRUE    A  13.0000
## 17     12  target         ボリューム  eng  base   TRUE    A   6.9412
## 18     13  target             ベース  eng  base   TRUE    A  35.3725
## 19     16  target       エクスプレス  eng  base   TRUE    A  17.9216
## 20     17  target           ストーブ  eng  base   TRUE    A   7.5882
## 21     20  target           リコール  eng  base   TRUE    A  19.6667
## 22     21  target             レター  eng  base   TRUE    A  82.6078
## 23     24  target             ガッツ  eng  base   TRUE    A  23.7451
## 24     25  target             バイク  eng  base   TRUE    A  25.8824
## 25     17 nonword     ドートレギング  eng  <NA>  FALSE <NA>       NA
## 26     18 nonword     フィスティレド  eng  <NA>  FALSE <NA>       NA
## 27     19 nonword       ストネヘンデ  eng  <NA>  FALSE <NA>       NA
## 28     20 nonword   ポリディフィエス  eng  <NA>  FALSE <NA>       NA
## 29     21 nonword   メストレイヤーズ  eng  <NA>  FALSE <NA>       NA
## 30     22 nonword         ドンスーン  eng  <NA>  FALSE <NA>       NA
## 31     23 nonword           スプラム  eng  <NA>  FALSE <NA>       NA
## 32     24 nonword ティソベディエント  eng  <NA>  FALSE <NA>       NA
## 33     25 nonword             ムイン  eng  <NA>  FALSE <NA>       NA
## 34     26 nonword           ドソーム  eng  <NA>  FALSE <NA>       NA
## 35     27 nonword             ヘイド  eng  <NA>  FALSE <NA>       NA
## 36     28 nonword         オンテナー  eng  <NA>  FALSE <NA>       NA
## 37     29 nonword         タンサック  eng  <NA>  FALSE <NA>       NA
## 38     30 nonword           フロール  eng  <NA>  FALSE <NA>       NA
## 39     31 nonword アンチヒスタモーネ  eng  <NA>  FALSE <NA>       NA
## 40     32 nonword         パラックス  eng  <NA>  FALSE <NA>       NA
## 41     33 nonword     ハイプノジスト  eng  <NA>  FALSE <NA>       NA
## 42     34 nonword       クロリエイジ  eng  <NA>  FALSE <NA>       NA
## 43     35 nonword         コラプソス  eng  <NA>  FALSE <NA>       NA
## 44     36 nonword             ビキナ  eng  <NA>  FALSE <NA>       NA
## 45     37 nonword スティメレーション  eng  <NA>  FALSE <NA>       NA
## 46     38 nonword         スキマッド  eng  <NA>  FALSE <NA>       NA
## 47     39 nonword     ディロクトネス  eng  <NA>  FALSE <NA>       NA
## 48     40 nonword         ケグファグ  eng  <NA>  FALSE <NA>       NA
##     freq_E
## 1  17.5744
## 2  21.4056
## 3   0.5272
## 4   0.5272
## 5   3.3743
## 6  20.8784
## 7   0.3163
## 8  11.7045
## 9  13.9541
## 10  2.4253
## 11  5.2020
## 12  3.6555
## 13  9.2793
## 14 31.5284
## 15  5.7292
## 16  2.2847
## 17 14.9382
## 18 40.7726
## 19  2.5307
## 20  3.5852
## 21  0.7030
## 22  3.5500
## 23  3.6906
## 24 13.8135
## 25      NA
## 26      NA
## 27      NA
## 28      NA
## 29      NA
## 30      NA
## 31      NA
## 32      NA
## 33      NA
## 34      NA
## 35      NA
## 36      NA
## 37      NA
## 38      NA
## 39      NA
## 40      NA
## 41      NA
## 42      NA
## 43      NA
## 44      NA
## 45      NA
## 46      NA
## 47      NA
## 48      NA
## 
## [[2]]
##    itemID    type               kana lang prime answer form   freq_J
## 1       2  target       インタビュー  eng share   TRUE    A  29.5098
## 2       3  target             コート  eng  spec   TRUE    A 100.7255
## 3       6  target         エイリアン  eng share   TRUE    A  17.4314
## 4       7  target   アポイントメント  eng  spec   TRUE    A  30.5686
## 5      10  target           スタンプ  eng share   TRUE    A   5.9216
## 6      14  target         チャンネル  eng share   TRUE    A  24.4118
## 7      15  target           クロール  eng  spec   TRUE    A  12.0392
## 8      18  target             センス  eng share   TRUE    A 131.8039
## 9      19  target             ベンチ  eng  spec   TRUE    A   9.6667
## 10     22  target     プロモーション  eng share   TRUE    A  10.9216
## 11     23  target               ツナ  eng  spec   TRUE    A   8.0000
## 12      1  target           アイロン  eng  base   TRUE    A  17.9412
## 13      4  target         グラウンド  eng  base   TRUE    A  72.4706
## 14      5  target           アドレス  eng  base   TRUE    A  52.2745
## 15      8  target       プレッシャー  eng  base   TRUE    A  53.1176
## 16      9  target         プロポーズ  eng  base   TRUE    A  13.0000
## 17     12  target         ボリューム  eng  base   TRUE    A   6.9412
## 18     13  target             ベース  eng  base   TRUE    A  35.3725
## 19     16  target       エクスプレス  eng  base   TRUE    A  17.9216
## 20     17  target           ストーブ  eng  base   TRUE    A   7.5882
## 21     20  target           リコール  eng  base   TRUE    A  19.6667
## 22     21  target             レター  eng  base   TRUE    A  82.6078
## 23     24  target             ガッツ  eng  base   TRUE    A  23.7451
## 24     25  target             バイク  eng  base   TRUE    A  25.8824
## 25     17 nonword     ドートレギング  eng  <NA>  FALSE <NA>       NA
## 26     18 nonword     フィスティレド  eng  <NA>  FALSE <NA>       NA
## 27     19 nonword       ストネヘンデ  eng  <NA>  FALSE <NA>       NA
## 28     20 nonword   ポリディフィエス  eng  <NA>  FALSE <NA>       NA
## 29     21 nonword   メストレイヤーズ  eng  <NA>  FALSE <NA>       NA
## 30     22 nonword         ドンスーン  eng  <NA>  FALSE <NA>       NA
## 31     23 nonword           スプラム  eng  <NA>  FALSE <NA>       NA
## 32     24 nonword ティソベディエント  eng  <NA>  FALSE <NA>       NA
## 33     25 nonword             ムイン  eng  <NA>  FALSE <NA>       NA
## 34     26 nonword           ドソーム  eng  <NA>  FALSE <NA>       NA
## 35     27 nonword             ヘイド  eng  <NA>  FALSE <NA>       NA
## 36     28 nonword         オンテナー  eng  <NA>  FALSE <NA>       NA
## 37     29 nonword         タンサック  eng  <NA>  FALSE <NA>       NA
## 38     30 nonword           フロール  eng  <NA>  FALSE <NA>       NA
## 39     31 nonword アンチヒスタモーネ  eng  <NA>  FALSE <NA>       NA
## 40     32 nonword         パラックス  eng  <NA>  FALSE <NA>       NA
## 41     33 nonword     ハイプノジスト  eng  <NA>  FALSE <NA>       NA
## 42     34 nonword       クロリエイジ  eng  <NA>  FALSE <NA>       NA
## 43     35 nonword         コラプソス  eng  <NA>  FALSE <NA>       NA
## 44     36 nonword             ビキナ  eng  <NA>  FALSE <NA>       NA
## 45     37 nonword スティメレーション  eng  <NA>  FALSE <NA>       NA
## 46     38 nonword         スキマッド  eng  <NA>  FALSE <NA>       NA
## 47     39 nonword     ディロクトネス  eng  <NA>  FALSE <NA>       NA
## 48     40 nonword         ケグファグ  eng  <NA>  FALSE <NA>       NA
##     freq_E
## 1  17.5744
## 2  21.4056
## 3   0.5272
## 4   0.5272
## 5   3.3743
## 6  20.8784
## 7   0.3163
## 8  11.7045
## 9  13.9541
## 10  2.4253
## 11  5.2020
## 12  3.6555
## 13  9.2793
## 14 31.5284
## 15  5.7292
## 16  2.2847
## 17 14.9382
## 18 40.7726
## 19  2.5307
## 20  3.5852
## 21  0.7030
## 22  3.5500
## 23  3.6906
## 24 13.8135
## 25      NA
## 26      NA
## 27      NA
## 28      NA
## 29      NA
## 30      NA
## 31      NA
## 32      NA
## 33      NA
## 34      NA
## 35      NA
## 36      NA
## 37      NA
## 38      NA
## 39      NA
## 40      NA
## 41      NA
## 42      NA
## 43      NA
## 44      NA
## 45      NA
## 46      NA
## 47      NA
## 48      NA
## 
## [[3]]
##    itemID    type               kana lang prime answer form   freq_J
## 1       2  target       インタビュー  eng share   TRUE    A  29.5098
## 2       3  target             コート  eng  spec   TRUE    A 100.7255
## 3       6  target         エイリアン  eng share   TRUE    A  17.4314
## 4       7  target   アポイントメント  eng  spec   TRUE    A  30.5686
## 5      10  target           スタンプ  eng share   TRUE    A   5.9216
## 6      14  target         チャンネル  eng share   TRUE    A  24.4118
## 7      15  target           クロール  eng  spec   TRUE    A  12.0392
## 8      18  target             センス  eng share   TRUE    A 131.8039
## 9      19  target             ベンチ  eng  spec   TRUE    A   9.6667
## 10     22  target     プロモーション  eng share   TRUE    A  10.9216
## 11     23  target               ツナ  eng  spec   TRUE    A   8.0000
## 12      1  target           アイロン  eng  base   TRUE    A  17.9412
## 13      4  target         グラウンド  eng  base   TRUE    A  72.4706
## 14      5  target           アドレス  eng  base   TRUE    A  52.2745
## 15      8  target       プレッシャー  eng  base   TRUE    A  53.1176
## 16      9  target         プロポーズ  eng  base   TRUE    A  13.0000
## 17     12  target         ボリューム  eng  base   TRUE    A   6.9412
## 18     13  target             ベース  eng  base   TRUE    A  35.3725
## 19     16  target       エクスプレス  eng  base   TRUE    A  17.9216
## 20     17  target           ストーブ  eng  base   TRUE    A   7.5882
## 21     20  target           リコール  eng  base   TRUE    A  19.6667
## 22     21  target             レター  eng  base   TRUE    A  82.6078
## 23     24  target             ガッツ  eng  base   TRUE    A  23.7451
## 24     25  target             バイク  eng  base   TRUE    A  25.8824
## 25     17 nonword     ドートレギング  eng  <NA>  FALSE <NA>       NA
## 26     18 nonword     フィスティレド  eng  <NA>  FALSE <NA>       NA
## 27     19 nonword       ストネヘンデ  eng  <NA>  FALSE <NA>       NA
## 28     20 nonword   ポリディフィエス  eng  <NA>  FALSE <NA>       NA
## 29     21 nonword   メストレイヤーズ  eng  <NA>  FALSE <NA>       NA
## 30     22 nonword         ドンスーン  eng  <NA>  FALSE <NA>       NA
## 31     23 nonword           スプラム  eng  <NA>  FALSE <NA>       NA
## 32     24 nonword ティソベディエント  eng  <NA>  FALSE <NA>       NA
## 33     25 nonword             ムイン  eng  <NA>  FALSE <NA>       NA
## 34     26 nonword           ドソーム  eng  <NA>  FALSE <NA>       NA
## 35     27 nonword             ヘイド  eng  <NA>  FALSE <NA>       NA
## 36     28 nonword         オンテナー  eng  <NA>  FALSE <NA>       NA
## 37     29 nonword         タンサック  eng  <NA>  FALSE <NA>       NA
## 38     30 nonword           フロール  eng  <NA>  FALSE <NA>       NA
## 39     31 nonword アンチヒスタモーネ  eng  <NA>  FALSE <NA>       NA
## 40     32 nonword         パラックス  eng  <NA>  FALSE <NA>       NA
## 41     33 nonword     ハイプノジスト  eng  <NA>  FALSE <NA>       NA
## 42     34 nonword       クロリエイジ  eng  <NA>  FALSE <NA>       NA
## 43     35 nonword         コラプソス  eng  <NA>  FALSE <NA>       NA
## 44     36 nonword             ビキナ  eng  <NA>  FALSE <NA>       NA
## 45     37 nonword スティメレーション  eng  <NA>  FALSE <NA>       NA
## 46     38 nonword         スキマッド  eng  <NA>  FALSE <NA>       NA
## 47     39 nonword     ディロクトネス  eng  <NA>  FALSE <NA>       NA
## 48     40 nonword         ケグファグ  eng  <NA>  FALSE <NA>       NA
##     freq_E
## 1  17.5744
## 2  21.4056
## 3   0.5272
## 4   0.5272
## 5   3.3743
## 6  20.8784
## 7   0.3163
## 8  11.7045
## 9  13.9541
## 10  2.4253
## 11  5.2020
## 12  3.6555
## 13  9.2793
## 14 31.5284
## 15  5.7292
## 16  2.2847
## 17 14.9382
## 18 40.7726
## 19  2.5307
## 20  3.5852
## 21  0.7030
## 22  3.5500
## 23  3.6906
## 24 13.8135
## 25      NA
## 26      NA
## 27      NA
## 28      NA
## 29      NA
## 30      NA
## 31      NA
## 32      NA
## 33      NA
## 34      NA
## 35      NA
## 36      NA
## 37      NA
## 38      NA
## 39      NA
## 40      NA
## 41      NA
## 42      NA
## 43      NA
## 44      NA
## 45      NA
## 46      NA
## 47      NA
## 48      NA

このように,各行にすべての情報が入ってしまいます。よって,行ごとに入れることを考えないといけません。これを一発できれいにできたらかっこいいんですが,思いつかなかったので,とりあえずfor関数でi行目を取り出してtibbleに入れる,を繰り返すことにしました。まずは,dataのところがリスト型になるようにtibbleを作ります。

tibble::tibble(
  pic=dat$pic,
  word=dat$word,
  data=list()
)->dat3
head(dat3)

しかしここでもまた失敗。dataの列の長さがあってないと怒られてしまいます。これを解決するためにlistの中に空のリストを入れます(正直ここで入れる要素はなんでもOK)。

tibble::tibble(
  pic=dat$pic,
  word=dat$word,
  data=list(list())
)->dat3
dat3
## # A tibble: 48 x 3
##    pic         word        data      
##    <fct>       <fct>       <list>    
##  1 2_C_sh.jpg  interview   <list [0]>
##  2 3_C_sp.jpg  court       <list [0]>
##  3 6_C_sh.jpg  alien       <list [0]>
##  4 7_C_sp.jpg  appointment <list [0]>
##  5 10_C_sh.jpg stamp       <list [0]>
##  6 14_C_sh.jpg channel     <list [0]>
##  7 15_C_sp.jpg crawl       <list [0]>
##  8 18_C_sh.jpg sense       <list [0]>
##  9 19_C_sp.jpg bench       <list [0]>
## 10 22_C_sh.jpg promotion   <list [0]>
## # … with 38 more rows

できあがった dat3 という変数の“data”列に,pic( dat の5列目)とword( dat の3列目)を除いたものを1行目から順にとってきてlistにして,それを dat3 の“data”列に順番にいれていきます。

for (i in 1:length(dat3$pic)){
  dat3[i,3][[1]]<-list(dat[i,c(1,2,4,6,7,8,9,10,11)])
}
head(dat3)
## # A tibble: 6 x 3
##   pic         word        data            
##   <fct>       <fct>       <list>          
## 1 2_C_sh.jpg  interview   <df[,9] [1 × 9]>
## 2 3_C_sp.jpg  court       <df[,9] [1 × 9]>
## 3 6_C_sh.jpg  alien       <df[,9] [1 × 9]>
## 4 7_C_sp.jpg  appointment <df[,9] [1 × 9]>
## 5 10_C_sh.jpg stamp       <df[,9] [1 × 9]>
## 6 14_C_sh.jpg channel     <df[,9] [1 × 9]>

こうすると,できあがったtibbleのdata列には1行目から順に,interview, court,…の刺激の情報が入ることになります。確認のために見てみましょう。

dat3$data[[1]];dat3$data[[2]]
##   itemID   type         kana lang prime answer form  freq_J  freq_E
## 1      2 target インタビュー  eng share   TRUE    A 29.5098 17.5744
##   itemID   type   kana lang prime answer form   freq_J  freq_E
## 2      3 target コート  eng  spec   TRUE    A 100.7255 21.4056

ちゃんと入ってますね。最後に,このtibbleをJSON形式に変換すれば完成です。

toJSON(dat3)
## [{"pic":"2_C_sh.jpg","word":"interview","data":[{"itemID":2,"type":"target","kana":"インタビュー","lang":"eng","prime":"share","answer":true,"form":"A","freq_J":29.5098,"freq_E":17.5744}]},{"pic":"3_C_sp.jpg","word":"court","data":[{"itemID":3,"type":"target","kana":"コート","lang":"eng","prime":"spec","answer":true,"form":"A","freq_J":100.7255,"freq_E":21.4056}]},{"pic":"6_C_sh.jpg","word":"alien","data":[{"itemID":6,"type":"target","kana":"エイリアン","lang":"eng","prime":"share","answer":true,"form":"A","freq_J":17.4314,"freq_E":0.5272}]},{"pic":"7_C_sp.jpg","word":"appointment","data":[{"itemID":7,"type":"target","kana":"アポイントメント","lang":"eng","prime":"spec","answer":true,"form":"A","freq_J":30.5686,"freq_E":0.5272}]},{"pic":"10_C_sh.jpg","word":"stamp","data":[{"itemID":10,"type":"target","kana":"スタンプ","lang":"eng","prime":"share","answer":true,"form":"A","freq_J":5.9216,"freq_E":3.3743}]},{"pic":"14_C_sh.jpg","word":"channel","data":[{"itemID":14,"type":"target","kana":"チャンネル","lang":"eng","prime":"share","answer":true,"form":"A","freq_J":24.4118,"freq_E":20.8784}]},{"pic":"15_C_sp.jpg","word":"crawl","data":[{"itemID":15,"type":"target","kana":"クロール","lang":"eng","prime":"spec","answer":true,"form":"A","freq_J":12.0392,"freq_E":0.3163}]},{"pic":"18_C_sh.jpg","word":"sense","data":[{"itemID":18,"type":"target","kana":"センス","lang":"eng","prime":"share","answer":true,"form":"A","freq_J":131.8039,"freq_E":11.7045}]},{"pic":"19_C_sp.jpg","word":"bench","data":[{"itemID":19,"type":"target","kana":"ベンチ","lang":"eng","prime":"spec","answer":true,"form":"A","freq_J":9.6667,"freq_E":13.9541}]},{"pic":"22_C_sh.jpg","word":"promotion","data":[{"itemID":22,"type":"target","kana":"プロモーション","lang":"eng","prime":"share","answer":true,"form":"A","freq_J":10.9216,"freq_E":2.4253}]},{"pic":"23_C_sp.jpg","word":"tuna","data":[{"itemID":23,"type":"target","kana":"ツナ","lang":"eng","prime":"spec","answer":true,"form":"A","freq_J":8,"freq_E":5.202}]},{"pic":"1_C_b.jpg","word":"iron","data":[{"itemID":1,"type":"target","kana":"アイロン","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":17.9412,"freq_E":3.6555}]},{"pic":"4_C_b.jpg","word":"ground","data":[{"itemID":4,"type":"target","kana":"グラウンド","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":72.4706,"freq_E":9.2793}]},{"pic":"5_C_b.jpg","word":"address","data":[{"itemID":5,"type":"target","kana":"アドレス","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":52.2745,"freq_E":31.5284}]},{"pic":"8_C_b.jpg","word":"pressure","data":[{"itemID":8,"type":"target","kana":"プレッシャー","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":53.1176,"freq_E":5.7292}]},{"pic":"9_C_b.jpg","word":"propose","data":[{"itemID":9,"type":"target","kana":"プロポーズ","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":13,"freq_E":2.2847}]},{"pic":"12_C_b.jpg","word":"volume","data":[{"itemID":12,"type":"target","kana":"ボリューム","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":6.9412,"freq_E":14.9382}]},{"pic":"13_C_b.jpg","word":"base","data":[{"itemID":13,"type":"target","kana":"ベース","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":35.3725,"freq_E":40.7726}]},{"pic":"16_C_b.jpg","word":"express","data":[{"itemID":16,"type":"target","kana":"エクスプレス","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":17.9216,"freq_E":2.5307}]},{"pic":"17_C_b.jpg","word":"stove","data":[{"itemID":17,"type":"target","kana":"ストーブ","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":7.5882,"freq_E":3.5852}]},{"pic":"20_C_b.jpg","word":"recall","data":[{"itemID":20,"type":"target","kana":"リコール","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":19.6667,"freq_E":0.703}]},{"pic":"21_C_b.jpg","word":"letter","data":[{"itemID":21,"type":"target","kana":"レター","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":82.6078,"freq_E":3.55}]},{"pic":"24_C_b.jpg","word":"guts","data":[{"itemID":24,"type":"target","kana":"ガッツ","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":23.7451,"freq_E":3.6906}]},{"pic":"25_C_b.jpg","word":"bike","data":[{"itemID":25,"type":"target","kana":"バイク","lang":"eng","prime":"base","answer":true,"form":"A","freq_J":25.8824,"freq_E":13.8135}]},{"pic":"17_n.jpg","word":"dootlegging","data":[{"itemID":17,"type":"nonword","kana":"ドートレギング","lang":"eng","answer":false}]},{"pic":"18_n.jpg","word":"fistilled","data":[{"itemID":18,"type":"nonword","kana":"フィスティレド","lang":"eng","answer":false}]},{"pic":"19_n.jpg","word":"stonehende","data":[{"itemID":19,"type":"nonword","kana":"ストネヘンデ","lang":"eng","answer":false}]},{"pic":"20_n.jpg","word":"polidifies","data":[{"itemID":20,"type":"nonword","kana":"ポリディフィエス","lang":"eng","answer":false}]},{"pic":"21_n.jpg","word":"mestroyers","data":[{"itemID":21,"type":"nonword","kana":"メストレイヤーズ","lang":"eng","answer":false}]},{"pic":"22_n.jpg","word":"donsoon","data":[{"itemID":22,"type":"nonword","kana":"ドンスーン","lang":"eng","answer":false}]},{"pic":"23_n.jpg","word":"splum","data":[{"itemID":23,"type":"nonword","kana":"スプラム","lang":"eng","answer":false}]},{"pic":"24_n.jpg","word":"tisobedient","data":[{"itemID":24,"type":"nonword","kana":"ティソベディエント","lang":"eng","answer":false}]},{"pic":"25_n.jpg","word":"muin","data":[{"itemID":25,"type":"nonword","kana":"ムイン","lang":"eng","answer":false}]},{"pic":"26_n.jpg","word":"dothorme","data":[{"itemID":26,"type":"nonword","kana":"ドソーム","lang":"eng","answer":false}]},{"pic":"27_n.jpg","word":"hade","data":[{"itemID":27,"type":"nonword","kana":"ヘイド","lang":"eng","answer":false}]},{"pic":"28_n.jpg","word":"ontener","data":[{"itemID":28,"type":"nonword","kana":"オンテナー","lang":"eng","answer":false}]},{"pic":"29_n.jpg","word":"tansack","data":[{"itemID":29,"type":"nonword","kana":"タンサック","lang":"eng","answer":false}]},{"pic":"30_n.jpg","word":"frool","data":[{"itemID":30,"type":"nonword","kana":"フロール","lang":"eng","answer":false}]},{"pic":"31_n.jpg","word":"antihistamone","data":[{"itemID":31,"type":"nonword","kana":"アンチヒスタモーネ","lang":"eng","answer":false}]},{"pic":"32_n.jpg","word":"parracks","data":[{"itemID":32,"type":"nonword","kana":"パラックス","lang":"eng","answer":false}]},{"pic":"33_n.jpg","word":"hypnojist","data":[{"itemID":33,"type":"nonword","kana":"ハイプノジスト","lang":"eng","answer":false}]},{"pic":"34_n.jpg","word":"croilage","data":[{"itemID":34,"type":"nonword","kana":"クロリエイジ","lang":"eng","answer":false}]},{"pic":"35_n.jpg","word":"collapsos","data":[{"itemID":35,"type":"nonword","kana":"コラプソス","lang":"eng","answer":false}]},{"pic":"36_n.jpg","word":"bikina","data":[{"itemID":36,"type":"nonword","kana":"ビキナ","lang":"eng","answer":false}]},{"pic":"37_n.jpg","word":"stimelation","data":[{"itemID":37,"type":"nonword","kana":"スティメレーション","lang":"eng","answer":false}]},{"pic":"38_n.jpg","word":"skimmud","data":[{"itemID":38,"type":"nonword","kana":"スキマッド","lang":"eng","answer":false}]},{"pic":"39_n.jpg","word":"diroctness","data":[{"itemID":39,"type":"nonword","kana":"ディロクトネス","lang":"eng","answer":false}]},{"pic":"40_n.jpg","word":"kegfug","data":[{"itemID":40,"type":"nonword","kana":"ケグファグ","lang":"eng","answer":false}]}]

テキストファイルとして保存する場合は,以下のようにします。

toJSON(dat3) %>%
write(.,file = "json.txt")

おわりに

この記事では,データフレーム形式のものを階層性をもった形でJSON形式に変換するということをやってみました。tibbleという形式ができたことで,データフレームの中にリスト型変数を持つということができます。これができれば,あとは toJSON関数 で一発で変換ができました。もしかしたらもっとエレガントな方法もあるかもしれませんが,とりあえず現状の課題は解決できました。

なにをゆう たむらゆう。

おしまい。


  1. 注: 私はこれまで,大学院で習ったHot Soup Processorというゲームを作る目的で使われることが多いプログラミング言語を使って実験プログラムを作っていました。その際にも,特にRでのデータハンドリングに習熟するようになってからは,刺激を読み込む際に,その刺激の情報も一緒に読み込んで,実験結果の出力時にロング型で表示されるようにしていました。