メモ:data.frameはdata.frameの列として使えるけどtibbleの列には使えない

こんな感じのJSONfromJSON()で読み込むと、ちょっと特殊なdata.frameができることに気付いた(オプションをつければ挙動は変わるけど)。

df_from_json <- jsonlite::fromJSON('[
  {"x": 1, "y": 1, "df": {"a": 10, "b": 10}},
  {"x": 2, "y": 2, "df": {"a": 20, "b": 20}},
  {"x": 3, "y": 3, "df": {"a": 30, "b": 30}}
]')

これはこんな感じでやれば作れる気がするし、実際、表示は同じものができる。

df_flattened <- data.frame(
  x = 1:3,
  y = 1:3,
  df = data.frame(a = 1:3 * 10,
                  b = 1:3 * 10)
)

df_from_json
#>   x y df.a df.b
#> 1 1 1   10   10
#> 2 2 2   20   20
#> 3 3 3   30   30

df_flattened
#>   x y df.a df.b
#> 1 1 1   10   10
#> 2 2 2   20   20
#> 3 3 3   30   30

でも、構造を見ると違っている。

str(df_from_json)
#> 'data.frame':    3 obs. of  3 variables:
#>  $ x : int  1 2 3
#>  $ y : int  1 2 3
#>  $ df:'data.frame':  3 obs. of  2 variables:
#>   ..$ a: int  10 20 30
#>   ..$ b: int  10 20 30

str(df_flattened)
#> 'data.frame':    3 obs. of  4 variables:
#>  $ x   : int  1 2 3
#>  $ y   : int  1 2 3
#>  $ df.a: num  10 20 30
#>  $ df.b: num  10 20 30

同じ構造のをつくるには、こんな感じであとから列を追加しないといけないみたい。

df_step_by_step <- data.frame(
  x = 1:3,
  y = 1:3
)

df_step_by_step$df <- data.frame(a = 1:3 * 10,
                                 b = 1:3 * 10)

str(df_step_by_step)
#> 'data.frame':    3 obs. of  3 variables:
#>  $ x : int  1 2 3
#>  $ y : int  1 2 3
#>  $ df:'data.frame':  3 obs. of  2 variables:
#>   ..$ a: num  10 20 30
#>   ..$ b: num  10 20 30

でもこれはtibbleとしてはvalidではない。変換しようとしてもエラーになるし、

tibble::as_tibble(df_from_json)
#> Error: Column `df` must be a 1d atomic vector or a list

さっきと同じであとから列を追加するやり方でやれば作れるけど、ちゃんと動作しない。

tbl_step_by_step <- tibble::tibble(
  x = 1:3,
  y = 1:3
)

tbl_step_by_step$df <- data.frame(a = 1:3 * 10,
                                  b = 1:3 * 10)

tbl_step_by_step
#> Error in `[.data.frame`(X[[i]], ...): undefined columns selected

たまーにfromJSON()したdata.frameがdplyrでうまく扱えなくて、どうするのがいいんだろう、と思いつつ深追いしてなかったけどこういうことか...

お手軽な対処法としては、flatten = TRUEなのかな。