将常量列添加到嵌套 data.table

add constant column to nested data.table

我正在使用 jsonlite 加载一些 JSON 数据,这导致一些嵌套数据(在结构上)类似于下面构造的玩具 data.table dt。

设置:

dt <- data.table(a=c("abc", "def", "ghi"), b=runif(3))
dt[, c:=list(list(data.table(d=runif(4), e=runif(4))))]
dt
     a         b            c
1: abc 0.2623218 <data.table>
2: def 0.7092507 <data.table>
3: ghi 0.2795103 <data.table>

在我的数据中存在 key/identifier 列(例如,上面 data.table 中的列 a),但嵌套数据没有此类标识符。我需要处理嵌套数据(参见我的 related question),但在使用 rbindlist 之前,我想将列 a 的值作为嵌套数据的常量列。

例如第一行c的值为:

dt[1, c]
[[1]]
            d         e
1: 0.27951027 0.6350479
2: 0.45996594 0.6148956
3: 0.29377315 0.8432641
4: 0.01850265 0.1346082

我的 objective 是在将嵌套表绑定在一起之前将其修改为如下所示,以便我知道哪些行与哪些记录相关:

dt[1, c]
[[1]]
            d         e   a
1: 0.27951027 0.6350479 abc
2: 0.45996594 0.6148956 abc
3: 0.29377315 0.8432641 abc
4: 0.01850265 0.1346082 abc

我可以使用在 J 表达式中调用的自定义函数来实现这一点,并为该行采用嵌套的 data.table 以及常量列(本例中为 a)名称和值。大致如下:

add_nested_column <- function(dfl, name, value) {
  df <- dfl[[1]] # data.frame wrapped in list per row, pull it out
  df[, c(name):=value]  
  return(list(list(df)))
}

像这样使用:

dt[, key:=1:.N]
dt[, c:=add_nested_column(c, "a", a), by=key]
rbindlist(dt[, c])
             d         e   a
 1: 0.27951027 0.6350479 abc
 2: 0.45996594 0.6148956 abc
 3: 0.29377315 0.8432641 abc
 4: 0.01850265 0.1346082 abc
 5: 0.27951027 0.6350479 def
 6: 0.45996594 0.6148956 def
 7: 0.29377315 0.8432641 def
 8: 0.01850265 0.1346082 def
 9: 0.27951027 0.6350479 ghi
10: 0.45996594 0.6148956 ghi
11: 0.29377315 0.8432641 ghi
12: 0.01850265 0.1346082 ghi

这个解决方案对我来说似乎并没有那么糟糕,但我想知道它是否真的是最佳实践,或者是否有内置于 data.table 或其他我不知道的技术的功能让它更多 efficient/concise.

要达到最终效果,最直接的方法就是

dt[,c[[1]],by=a]

这给出了

      a         d          e
 1: abc 0.9082078 0.66079779
 2: abc 0.2016819 0.62911404
 3: abc 0.8983897 0.06178627
 4: abc 0.9446753 0.20597457
 5: def 0.9082078 0.66079779
 6: def 0.2016819 0.62911404
 7: def 0.8983897 0.06178627
 8: def 0.9446753 0.20597457
 9: ghi 0.9082078 0.66079779
10: ghi 0.2016819 0.62911404
11: ghi 0.8983897 0.06178627
12: ghi 0.9446753 0.20597457

您可以交替进行

rbindlist( setNames(dt[["c"]], dt[["a"]]), idcol = TRUE )

数据

set.seed(1)
dt <- data.table(a=c("abc", "def", "ghi"), b=runif(3))
dt[, c:=list(list(data.table(d=runif(4), e=runif(4))))]