在 R 中使用 data.table 创建多行组标识符的最快方法是什么?

dhe*_*rsz 5 grouping nested r data.table

我有一个数据框,它用 id 标识一组值:

library(data.table)

dt <- data.table(
  id = rep(c("a", "b", "c"), each = 2),
  value1 = c(1, 1, 1, 2, 1, 1),
  value2 = c(0, 3, 0, 3, 0, 3)
)
dt
#>    id value1 value2
#> 1:  a      1      0
#> 2:  a      1      3
#> 3:  b      1      0
#> 4:  b      2      3
#> 5:  c      1      0
#> 6:  c      1      3
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,idacidentify 都是同一组值。a因此,我想创建一个“模式 id”,它标识与ids 关联的值集c(obs:一个 id 可能标识多于两行,为了简单起见,我只是将它们限制为两行)。

我确实设法使用嵌套 data.tables 提出了一个解决方案match()

dt <- dt[, .(data = list(.SD)), by = id]

unique_groups <- unique(dt$data)
dt[, pattern_id := match(data, unique_groups)]
dt[, data := NULL]

dt
#>    id pattern_id
#> 1:  a          1
#> 2:  b          2
#> 3:  c          1
Run Code Online (Sandbox Code Playgroud)

确实有效,但它没有我希望的那么快。match()文档对于列表的效率非常清楚:

列表匹配可能非常慢,最好避免,除非是简单的情况。

正如您所看到的,我不需要最终结果中的实际模式数据,只需要一个将 id 与模式 id 相关联的表。我觉得嵌套数据,用它来匹配然后删除它有点浪费,但不确定是否有更好的方法。我正在考虑将每个数据帧转换为字符串的方法,或者更好的是,完全避免嵌套的方法,但我想不出比现在更好的方法。

我创建了一个更大的数据集来尝试和测试不同的解决方案:

dt <- dt[, .(data = list(.SD)), by = id]

unique_groups <- unique(dt$data)
dt[, pattern_id := match(data, unique_groups)]
dt[, data := NULL]

dt
#>    id pattern_id
#> 1:  a          1
#> 2:  b          2
#> 3:  c          1
Run Code Online (Sandbox Code Playgroud)

lan*_*ang 1

更新(删除连接):

这复制了您的方法(即它要求顺序和值相同)

unique(
  dt[, pattern:=.(paste0(c(value1,value2), collapse=",")), by=id][,.(id,pattern)]
)[,grp:=.GRP, by=pattern][,pattern:=NULL]

       id   grp
   <char> <int>
1:      a     1
2:      b     2
3:      c     1
Run Code Online (Sandbox Code Playgroud)

之前的解决方案:

dt[dt[, .(paste0(sort(c(value1,value2)), collapse=",")), by=id] %>% 
     .[,pattern:=.GRP, by=V1] %>% 
     .[,V1:=NULL], on=.(id)]
Run Code Online (Sandbox Code Playgroud)

输出:

       id value1 value2 pattern
   <char>  <num>  <num>   <int>
1:      a      1      0       1
2:      a      1      3       1
3:      b      1      0       2
4:      b      2      3       2
5:      c      1      0       1
6:      c      1      3       1
Run Code Online (Sandbox Code Playgroud)