Emm*_*man 4 performance r data.table tidyr
我有一个大型数据集,其中有一个包含嵌套命名向量的列表列。我想将这些向量取消嵌套到两个新列中:
目前,我发现的唯一直接的方法是使用tidyr::unnest_longer(). 虽然它对于小数据对象非常有用,但我发现在处理非常大的数据时它太慢了。因此,我正在寻找更快的替代方案。
我看到一个答案让我很接近,但并不完全是我需要的:一个基本的 R 替代品,unnest_wider()但速度更快。但是,我正在寻找一种模仿 unnest_ long所做的快速解决方案。
无论是基于base R、data.table、rrapply、 或collapse- 的解决方案,只要能减少处理时间,都受欢迎。
数据
library(stringi)
library(tidyr)
library(magrittr, warn.conflicts = FALSE)
# simulate data
set.seed(123)
vec_n <- 1e6
vec_vals <- 1:vec_n
vec_names <- stringi::stri_rand_strings(vec_n, 5)
my_named_vec <- setNames(vec_vals, vec_names)
split_func <- function(x, n) {
unname(split(x, rep_len(1:n, length(x))))
}
my_tbl <-
tibble(col_1 = sample(split_func(my_named_vec, n = vec_n / 5)))
Run Code Online (Sandbox Code Playgroud)
我需要“解除嵌套”的给定my_tbl数据对象也是如此。数据结构的简要预览揭示了每行列中的嵌套命名向量。col_1
# preview my_tbl
my_tbl
#> # A tibble: 200,000 x 1
#> col_1
#> <list>
#> 1 <int [5]>
#> 2 <int [5]>
#> 3 <int [5]>
#> 4 <int [5]>
#> 5 <int [5]>
#> 6 <int [5]>
#> 7 <int [5]>
#> 8 <int [5]>
#> 9 <int [5]>
#> 10 <int [5]>
#> # ... with 199,990 more rows
head(my_tbl$col_1)
#> [[1]]
#> 9YAGC hTjlr vgxjQ y4qG2 R1fUE
#> 56356 256356 456356 656356 856356
#>
#> [[2]]
#> nz5rk ZvEe6 ustHv 2TdA8 Rreqn
#> 119257 319257 519257 719257 919257
#>
#> [[3]]
#> ubbWp aw6zR ab0Ax N747j GY1xU
#> 4663 204663 404663 604663 804663
#>
#> [[4]]
#> JHo4w otk4s BTZ3h zlAKU svSgH
#> 75297 275297 475297 675297 875297
#>
#> [[5]]
#> A1pxZ T7y0l 0ixE2 DRBxP IBqxe
#> 19495 219495 419495 619495 819495
#>
#> [[6]]
#> fDkau Z7tmy TIzgx nKANU Bqwo1
#> 184074 384074 584074 784074 984074
Run Code Online (Sandbox Code Playgroud)
如果我们只有 10 行
my_tbl[1:10, ] %>%
tidyr::unnest_longer(col_1)
#> # A tibble: 50 x 2
#> col_1 col_1_id
#> <int> <chr>
#> 1 56356 9YAGC
#> 2 256356 hTjlr
#> 3 456356 vgxjQ
#> 4 656356 y4qG2
#> 5 856356 R1fUE
#> 6 119257 nz5rk
#> 7 319257 ZvEe6
#> 8 519257 ustHv
#> 9 719257 2TdA8
#> 10 919257 Rreqn
#> # ... with 40 more rows
Run Code Online (Sandbox Code Playgroud)
但其中my_tbl有 200,000 行,因此这tidyr::unnest_longer()需要很多时间:
my_benchmark <-
bench::mark(tidyrunnestlonger =
my_tbl %>%
tidyr::unnest_longer(col_1)
)
#> Warning: Some expressions had a GC in every iteration; so filtering is disabled.
my_benchmark
#> # A tibble: 1 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 tidyrunnestlonger 2.47m 2.47m 0.00674 309MB 1.50
Run Code Online (Sandbox Code Playgroud)
由 reprex 包 (v2.0.0) 于 2021-08-23 创建
虽然my_tbl有 200,000 行,但我的真实数据有超过 100 万行这种格式。所以我正在寻找尽可能最快的解决方案。
谢谢!
你可以只是unlist你的专栏:
x<-unlist(my_tbl[[1]])\nres<-tibble(col_1=unname(x),col_1_id=names(x))\nres\n## A tibble: 1,000,000 x 2\n# col_1 col_1_id\n# <int> <chr> \n# 1 56356 9YAGC \n# 2 256356 hTjlr \n# 3 456356 vgxjQ \n# 4 656356 y4qG2 \n# 5 856356 R1fUE \n# 6 119257 nz5rk \n# 7 319257 ZvEe6 \n# 8 519257 ustHv \n# 9 719257 2TdA8 \n#10 919257 Rreqn \n## \xe2\x80\xa6 with 999,990 more rows\nRun Code Online (Sandbox Code Playgroud)\n