我正在try 通过ID列表对同一数据帧进行子集.我有一个大约50,000行的数据帧和大约1,000个数据帧的列表.列表中的每个数据框具有100到1000行,并且具有相同的 struct .

请考虑以下示例:

df1 <- data.frame(id = sample(sample(1000:3000, 1000), 50000, TRUE), info = runif(50000, 200, 300))
set.seed(1)
l <- replicate(1000,
               data.frame(id = sample(1000:3000, sample(400:700, 1), replace = TRUE)),
               simplify = FALSE)

我想根据l中的ID来子集df1.我可以通过执行半连接或使用%in%设置子集来完成此操作:

library(dplyr)
semi_join(df1, l[[1]], "id")
df1[df1$id %in% l[[1]]$id, ]

我正在寻找一种快速的解决方案,可以扩展到数千个数据帧的列表.到目前为止,我只用了lapply个(但可能会有更快的、矢量化的解决方案).

lapply(l, \(x) semi_join(df1, x, "id"))

以下是解决方案的起始基准:

bc <- 
  bench::mark(dplyr = lapply(l, \(x) semi_join(df1, x, "id")),
              baseR = lapply(l, \(x) df1[df1$id %in% x$id, ]),
              unique = lapply(l, \(x) df1[df1$id %in% unique(x$id), ]),
              data.table = {df2 <- setDT(df1); lapply(l, \(x) df2[df2$id %in% unique(x$id), ])},
              iterations = 10, check = FALSE)

#> bc
# A tibble: 4 × 13
#  expression      min   median `itr/sec` mem_alloc gc/se…¹ n_itr  n_gc
#  <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>   <dbl> <int> <dbl>
#1 dplyr         2.25s    2.43s    0.416     1.64GB   4.03     10    97
#2 baseR         9.04s    9.55s    0.105     1.56GB   0.536    10    51
#3 unique        10.3s   10.95s    0.0912    1.57GB   0.420    10    46
#4 data.table   10.21s    10.9s    0.0916   979.5MB   0.458    10    50

任何程序包都可以使用.

推荐答案

rbindlist上一次data.table次接球将是很快的.

library(data.table)
library(dplyr)

microbenchmark::microbenchmark(
  dplyr = lapply(l, \(x) semi_join(df1, x, "id")),
  baseR = lapply(l, \(x) df1[df1$id %in% x$id, ]),
  unique = lapply(l, \(x) df1[df1$id %in% unique(x$id), ]),
  data.table = {setDT(df2); lapply(l, \(x) df2[id %in% unique(x$id)])},
  bindJoinSplit = split(setDT(df2, key = "id")[unique(rbindlist(l, idcol = "df")), on = "id", allow.cartesian = TRUE, nomatch = 0], by = "df", keep.by = FALSE),
  times = 10,
  setup = df2 <- copy(df1)
)
#> Unit: milliseconds
#>           expr       min        lq     mean    median        uq       max neval
#>          dplyr 1555.2198 1569.4590 1630.778 1619.9118 1626.8791 1857.1259    10
#>          baseR 1079.4916 1087.2524 1131.043 1126.8084 1179.5400 1196.9150    10
#>         unique 1171.3705 1214.4915 1253.490 1234.3908 1274.9278 1398.2908    10
#>     data.table 1925.1388 1950.9440 1978.538 1982.5494 1995.3917 2038.3573    10
#>  bindJoinSplit  368.8109  380.4029  412.595  401.4089  437.4869  503.8478    10

如果可以避免绑定和分裂,这将更快和更容易.从?data.table::split人起:

请注意,处理数据列表.表通常会很多 比在单个数据中进行操作要慢.按组使用BY 论辩

假设数据被构建到一个data.table中,而不是data.frame的列表中.我们还可以将结果保存在单个data.table中,而不是data.frame的列表中.这样做速度更快.

dt <- rbindlist(l, idcol = "df")

microbenchmark::microbenchmark(
  bindJoinSplit = split(setDT(df2, key = "id")[unique(rbindlist(l, idcol = "df")), on = "id", allow.cartesian = TRUE, nomatch = 0], by = "df", keep.by = FALSE),
  join = setDT(df2, key = "id")[unique(dt), on = "id", allow.cartesian = TRUE, nomatch = 0],
  times = 10,
  setup = df2 <- copy(df1)
)
#> Unit: milliseconds
#>           expr      min       lq     mean   median       uq      max neval
#>  bindJoinSplit 317.1514 326.3613 343.2588 333.3914 364.1945 398.5467    10
#>           join 188.5818 191.4344 198.7380 194.4094 208.7339 219.9847    10

生效日期:

set.seed(1)
df1 <- data.frame(id = sample(sample(1000:3000, 1000), 50000, TRUE), info = runif(50000, 200, 300))
l <- replicate(1000,
               data.frame(id = sample(1000:3000, sample(400:700, 1), replace = TRUE)),
               simplify = FALSE)

R相关问答推荐

是否有任何解决方案可以优化VSCode中RScript的图形绘制?

如何在弹性表中为类别值的背景上色

如何创建构成多个独立列条目列表的收件箱框列?

如何替换R中数据集列中的各种字符串

判断字符串中数字的连续性

将数据集中的值增加到当前包含的最大值

R根据条件进行累积更改

在R中使用download. file().奇怪的URL?

在数组索引上复制矩阵时出错

多个模拟序列间的一种预测回归关系

在使用bslb和bootstrap5时,有没有办法更改特定dt行的 colored颜色 ?

给定开始日期和月份(数字),如何根据R中的开始日期和月数创建日期列

如何将网站图像添加到带有极坐标的面包裹条形图?

有没有一种方法可以同时对rhandsontable进行排序和从rhandsontable中删除?

如何根据R中其他变量的类别汇总值?

在R中创建连续的期间

从R中发出的咕噜声中的BUG?

如何在使用箭头R包(箭头::OPEN_DATASSET)和dplyr谓词时编写具有整齐计算的函数?

如何根据每个子框架中分类因子的唯一计数来过滤子框架列表?

如何修复geom_rect中的层错误?