Tidyverse方法通过row-do.call(rbind,x)等价物绑定未命名向量的未命名列表
我经常发现这样的问题:人们不知何故得到了一个未命名字符向量的未命名列表,他们希望将它们按行绑定到Tidyverse方法通过row-do.call(rbind,x)等价物绑定未命名向量的未命名列表,r,dplyr,data.table,tidyverse,purrr,R,Dplyr,Data.table,Tidyverse,Purrr,我经常发现这样的问题:人们不知何故得到了一个未命名字符向量的未命名列表,他们希望将它们按行绑定到data.frame。以下是一个例子: library(magrittr) data <- cbind(LETTERS[1:3],1:3,4:6,7:9,c(12,15,18)) %>% split(1:3) %>% unname data #[[1]] #[1] "A" "1" "4" "7" "12" # #[[2]] #[1] "B" "2" "5" "8"
data.frame
。以下是一个例子:
library(magrittr)
data <- cbind(LETTERS[1:3],1:3,4:6,7:9,c(12,15,18)) %>%
split(1:3) %>% unname
data
#[[1]]
#[1] "A" "1" "4" "7" "12"
#
#[[2]]
#[1] "B" "2" "5" "8" "15"
#
#[[3]]
#[1] "C" "3" "6" "9" "18"
也许一种效率较低的方法是从基R开始使用Reduce
do.call(rbind, data) %>% as.data.frame
# V1 V2 V3 V4 V5
#1 A 1 4 7 12
#2 B 2 5 8 15
#3 C 3 6 9 18
Reduce(rbind,data, init = NULL) %>% as.data.frame
# V1 V2 V3 V4 V5
#1 A 1 4 7 12
#2 B 2 5 8 15
#3 C 3 6 9 18
然而,当我们考虑更多的现代包,如<代码> DPLYR 或<代码>数据>表< /代码>时,可能会立即想到的一些方法不起作用,因为向量是未命名的或不是列表。p>
library(dplyr)
bind_rows(data)
#Error: Argument 1 must have names
一种方法可能是在向量上设置名称
library(purrr)
map_df(data, ~set_names(.x, seq_along(.x)))
# A tibble: 3 x 5
# `1` `2` `3` `4` `5`
# <chr> <chr> <chr> <chr> <chr>
#1 A 1 4 7 12
#2 B 2 5 8 15
#3 C 3 6 9 18
库(purrr)
映射(数据,~设置名称(.x,顺(.x)))
#一个tibble:3x5
# `1` `2` `3` `4` `5`
#
#1A 14 7 12
#2B25815
#3C36918
然而,这似乎比需要的步骤更多
因此,我的问题是什么是有效的
tidyverse
或data.table
方法来将未命名字符向量的未命名列表绑定到data.frame
行?不完全确定效率,但使用purr
和tible
的紧凑选项可以是:
map_dfc(purrr::transpose(data), ~ unlist(tibble(.)))
V1 V2 V3 V4 V5
<chr> <chr> <chr> <chr> <chr>
1 A 1 4 7 12
2 B 2 5 8 15
3 C 3 6 9 18
map\u-dfc(purrr::transpose(数据),~unlist(tible(.))
V1 V2 V3 V4 V5
1A 14 7 12
2B25815
3C36918
编辑
使用的方法:
使用
data.table
的方式,类似于@tmfmnk显示的方式
library(data.table)
as.data.table(transpose(data))
# V1 V2 V3 V4 V5
#1: A 1 4 7 12
#2: B 2 5 8 15
#3: C 3 6 9 18
带有
unnest\u加宽的选项
library(tibble)
library(tidyr)
library(stringr)
tibble(col = data) %>%
unnest_wider(c(col), names_repair = ~ str_c('value', seq_along(.)))
# A tibble: 3 x 5
# value1 value2 value3 value4 value5
# <chr> <chr> <chr> <chr> <chr>
#1 A 1 4 7 12
#2 B 2 5 8 15
#3 C 3 6 9 18
库(TIBLE)
图书馆(tidyr)
图书馆(stringr)
TIBLE(列=数据)%>%
unnest_wide(c(col),name_repair=~str_c('value',seq_along(.))
#一个tibble:3x5
#值1值2值3值4值5
#
#1A 14 7 12
#2B25815
#3C36918
我的方法是将这些列表条目转换为预期类型
rbindlist(lappy(数据,as.list))
#V1 V2 V3 V4 V5
#
#1:A 14 7 12
#2:B25815
#3:C36918
如果您希望将数据类型从字符向量调整为适当的类型,那么lappy
也可以在这里提供帮助。第一个lappy
为每一行调用,第二个lappy
为每一列调用
rbindlist(lappy(数据,as.list))[,lappy(.SD,type.convert)]
V1 V2 V3 V4 V5
1:A 14 7 12
2:B25815
3:C36918
这里是tmfmnk建议使用as_tible_row()
将向量转换为单行tible的方法的一个细微变化。还需要使用.name\u repair
参数:
library(purrr)
library(tibble)
map_df(data, as_tibble_row, .name_repair = ~paste0("value", seq(.x)))
# A tibble: 3 x 5
value1 value2 value3 value4 value5
<chr> <chr> <chr> <chr> <chr>
1 A 1 4 7 12
2 B 2 5 8 15
3 C 3 6 9 18
库(purrr)
图书馆(tibble)
map_df(数据,作为_tible_行,.name_repair=~paste0(“值”,seq(.x)))
#一个tibble:3x5
值1值2值3值4值5
1A 14 7 12
2B25815
3C36918
这看起来相当紧凑。我相信这就是bind_rows()
来自dplyr
的力量,因此map_df()
在purr
中的力量,因此应该是相当有效的
库(vctrs)
vec_rbind(!!!数据)
这给出了一个数据帧
…1…2…3…4…5
1A 14 7 12
2B25815
3C36918
一些基准
似乎tidyverse
方法中的.name\u repair
是一个严重的瓶颈。我选择了一些相当简单的选项,这些选项似乎也是其他帖子中运行最快的(感谢H1和sindri_baldur)
microbenchmark(vctrs=vec\u rbind(!!!数据),
dt=rbindlist(lappy(数据,as.list)),
map=map_-df(数据,作为可存储行,.name_repair=“unique”),
base=as.data.frame(do.call(rbind,data)))
但是如果你先命名向量(但不一定是列表元素),你会得到一个不同的故事
data2我认为这可以添加到这个问题的一整套非常好的答案中:
library(rlang) # Or purrr
data %>%
exec(rbind, !!!.) %>%
as_tibble() %>%
set_names(~ letters[seq_along(.)])
# A tibble: 3 x 5
a b c d e
<chr> <chr> <chr> <chr> <chr>
1 A 1 4 7 12
2 B 2 5 8 15
3 C 3 6 9 18
library(rlang)#或purrr
数据%>%
执行者(rbind,!!!)%>%
as_tible()%>%
设置名称(~字母[顺序(.))
#一个tibble:3x5
a、b、c、d、e
1A 14 7 12
2B25815
3C36918
作为旁注,Reduce(rbind,
不能比do.call(rbind,
更有效,因为do.call
构造分配内存并复制数据一次,而Reduce
构造重复分配新内存并重新复制所有以前的“rbind
ed”元素。你说得很对。我没想到性能会像现在这样糟糕,在100000行上慢了6000倍。我编辑了这个问题,将其称为“效率较低的方法”。我只是用一些其他方法运行了一个基准测试。这在速度方面压倒了所有其他方法,并且是第一个真正超过base::rbind()的方法
solution@dww是的,但是setDF()
不同于as.data.table()
/as.data.frame()
@Adam,你认为你可以用新的解决方案更新你的基准吗?对于那些不知道如何setDF()
/setDT()
work then here is good post:您可以通过将名称设置为不需要粘贴的整数来进一步提高性能。可能类似于vctrs::vec\u rbind(!!!lappy(数据,函数(x){attr(x,“名称”)是的,这比我刚才做的要快一点。但我同意。我很想在
library(data.table)
setDF(transpose(data))
V1 V2 V3 V4 V5
1 A 1 4 7 12
2 B 2 5 8 15
3 C 3 6 9 18
library(rlang) # Or purrr
data %>%
exec(rbind, !!!.) %>%
as_tibble() %>%
set_names(~ letters[seq_along(.)])
# A tibble: 3 x 5
a b c d e
<chr> <chr> <chr> <chr> <chr>
1 A 1 4 7 12
2 B 2 5 8 15
3 C 3 6 9 18