使用 dplyr 将列表重组为数据框
Reorganize list into dataframe using dplyr
我会使用 dplyr 包的速度将结构化列表转换为整洁的数据帧。
我想知道我现在发布的解决方案是 "state-of-art" 还是有更快的解决方案。
这是我的起始列表示例:
l = list()
l[[1]] = list(member1=c(a=rnorm(1)),member2=matrix(rnorm(3),nrow=3,ncol=1,dimnames=list(c(letters[2:4]),c("sample"))))
l[[2]] = list(member1=c(a=rnorm(1)),member2=matrix(rnorm(3),nrow=3,ncol=1,dimnames=list(c(letters[2:4]),c("sample"))))
l[[3]] = list(member1=c(a=rnorm(1)),member2=matrix(rnorm(3),nrow=3,ncol=1,dimnames=list(c(letters[2:4]),c("sample"))))
有了这个结果(给你看玩具结构):
l
[[1]]
[[1]]$member1
a
0.3340196
[[1]]$member2
sample
b 1.0098830
c 0.6413375
d 0.9080675
[[2]]
[[2]]$member1
a
0.0590878
[[2]]$member2
sample
b 0.5585736
c -0.5936157
d -0.3985687
[[3]]
[[3]]$member1
a
0.06242458
[[3]]$member2
sample
b -0.2873391
c 0.5326067
d -1.1635551
现在我将使用一个便利的函数来重新排列数据和 lapply
以在列表中导航:
organizeSamples = function(x){
member = x$member2
output = data.frame(key=rownames(member),value=member[,1])
return(output)
}
l_new = lapply(l, organizeSamples)
现在 dplyr 发挥了作用:
samples = dplyr::bind_rows(l_new)
samples :
key value
1 b 1.0098830
2 c 0.6413375
3 d 0.9080675
4 b 0.5585736
5 c -0.5936157
6 d -0.3985687
7 b -0.2873391
8 c 0.5326067
9 d -1.1635551
有没有一种方法可以使用 dplyr 更快、更优雅、更紧凑?
这是另一种方法,具有更多 dplyr/tidyr 功能和管道,但是我没有针对问题中的原始方法测试其性能,是否更优雅取决于个人喜好。
library(dplyr); library(tidyr)
lapply(l, `[[`, 2) %>%
data.frame %>%
add_rownames("key") %>%
gather(x, value, -key) %>%
select(-x)
# key value
#1 b -1.1476570
#2 c -0.2894616
#3 d -0.2992151
#4 b 0.2522234
#5 c -0.8919211
#6 d 0.4356833
#7 b -0.2242679
#8 c 0.3773956
#9 d 0.1333364
同样来自 Hadleyverse,但不使用 "dplyr" 将考虑使用 "reshape2" 中的 melt
:
library(reshape2)
melt(l)
# value Var1 Var2 L2 L1
# 1 -0.6264538 <NA> <NA> member1 1
# 2 0.1836433 b sample member2 1
# 3 -0.8356286 c sample member2 1
# 4 1.5952808 d sample member2 1
# 5 0.3295078 <NA> <NA> member1 2
# 6 -0.8204684 b sample member2 2
# 7 0.4874291 c sample member2 2
# 8 0.7383247 d sample member2 2
# 9 0.5757814 <NA> <NA> member1 3
# 10 -0.3053884 b sample member2 3
# 11 1.5117812 c sample member2 3
# 12 0.3898432 d sample member2 3
从那里开始,您可以考虑使用"dplyr"进行一些清理。例如,要获得您描述的两列结果,您可以执行以下操作:
library(reshape2)
library(dplyr)
melt(l) %>%
filter(L2 != "member1") %>%
select(value, Var1)
(使用 set.seed(1)
创建的示例数据)。
另一个纯粹的 tidyverse 解决方案:
ll <- l %>% map_df(enframe) %>%
mutate(key1=map(value, rownames),
key2=map(value, names),
key=map2(key1, key2, ~c(.x, .y))) %>%
select(-key1, -key2) %>%
unnest()
ll
# A tibble: 12 × 3
name value key
<chr> <dbl> <chr>
1 member1 2.12962812 a
2 member2 -0.87049458 b
3 member2 0.96190007 c
4 member2 0.56403433 d
5 member1 -0.41447472 a
6 member2 0.27270458 b
7 member2 -0.01384829 c
8 member2 -0.71561501 d
9 member1 -0.81835698 a
10 member2 -2.12746977 b
11 member2 0.66185843 c
12 member2 0.07878841 d
更新
我还以为你要合并member1和member2的信息,如果只需要member2就更简单了:
ll <- l %>% map_df(enframe) %>%
filter(name=="member2") %>%
mutate(key=map(value, rownames)) %>%
unnest()
ll
# A tibble: 9 × 3
name value key
<chr> <dbl> <chr>
1 member2 -0.87049458 b
2 member2 0.96190007 c
3 member2 0.56403433 d
4 member2 0.27270458 b
5 member2 -0.01384829 c
6 member2 -0.71561501 d
7 member2 -2.12746977 b
8 member2 0.66185843 c
9 member2 0.07878841 d
我会使用 dplyr 包的速度将结构化列表转换为整洁的数据帧。 我想知道我现在发布的解决方案是 "state-of-art" 还是有更快的解决方案。
这是我的起始列表示例:
l = list()
l[[1]] = list(member1=c(a=rnorm(1)),member2=matrix(rnorm(3),nrow=3,ncol=1,dimnames=list(c(letters[2:4]),c("sample"))))
l[[2]] = list(member1=c(a=rnorm(1)),member2=matrix(rnorm(3),nrow=3,ncol=1,dimnames=list(c(letters[2:4]),c("sample"))))
l[[3]] = list(member1=c(a=rnorm(1)),member2=matrix(rnorm(3),nrow=3,ncol=1,dimnames=list(c(letters[2:4]),c("sample"))))
有了这个结果(给你看玩具结构):
l
[[1]]
[[1]]$member1
a
0.3340196
[[1]]$member2
sample
b 1.0098830
c 0.6413375
d 0.9080675
[[2]]
[[2]]$member1
a
0.0590878
[[2]]$member2
sample
b 0.5585736
c -0.5936157
d -0.3985687
[[3]]
[[3]]$member1
a
0.06242458
[[3]]$member2
sample
b -0.2873391
c 0.5326067
d -1.1635551
现在我将使用一个便利的函数来重新排列数据和 lapply
以在列表中导航:
organizeSamples = function(x){
member = x$member2
output = data.frame(key=rownames(member),value=member[,1])
return(output)
}
l_new = lapply(l, organizeSamples)
现在 dplyr 发挥了作用:
samples = dplyr::bind_rows(l_new)
samples :
key value
1 b 1.0098830
2 c 0.6413375
3 d 0.9080675
4 b 0.5585736
5 c -0.5936157
6 d -0.3985687
7 b -0.2873391
8 c 0.5326067
9 d -1.1635551
有没有一种方法可以使用 dplyr 更快、更优雅、更紧凑?
这是另一种方法,具有更多 dplyr/tidyr 功能和管道,但是我没有针对问题中的原始方法测试其性能,是否更优雅取决于个人喜好。
library(dplyr); library(tidyr)
lapply(l, `[[`, 2) %>%
data.frame %>%
add_rownames("key") %>%
gather(x, value, -key) %>%
select(-x)
# key value
#1 b -1.1476570
#2 c -0.2894616
#3 d -0.2992151
#4 b 0.2522234
#5 c -0.8919211
#6 d 0.4356833
#7 b -0.2242679
#8 c 0.3773956
#9 d 0.1333364
同样来自 Hadleyverse,但不使用 "dplyr" 将考虑使用 "reshape2" 中的 melt
:
library(reshape2)
melt(l)
# value Var1 Var2 L2 L1
# 1 -0.6264538 <NA> <NA> member1 1
# 2 0.1836433 b sample member2 1
# 3 -0.8356286 c sample member2 1
# 4 1.5952808 d sample member2 1
# 5 0.3295078 <NA> <NA> member1 2
# 6 -0.8204684 b sample member2 2
# 7 0.4874291 c sample member2 2
# 8 0.7383247 d sample member2 2
# 9 0.5757814 <NA> <NA> member1 3
# 10 -0.3053884 b sample member2 3
# 11 1.5117812 c sample member2 3
# 12 0.3898432 d sample member2 3
从那里开始,您可以考虑使用"dplyr"进行一些清理。例如,要获得您描述的两列结果,您可以执行以下操作:
library(reshape2)
library(dplyr)
melt(l) %>%
filter(L2 != "member1") %>%
select(value, Var1)
(使用 set.seed(1)
创建的示例数据)。
另一个纯粹的 tidyverse 解决方案:
ll <- l %>% map_df(enframe) %>%
mutate(key1=map(value, rownames),
key2=map(value, names),
key=map2(key1, key2, ~c(.x, .y))) %>%
select(-key1, -key2) %>%
unnest()
ll
# A tibble: 12 × 3
name value key
<chr> <dbl> <chr>
1 member1 2.12962812 a
2 member2 -0.87049458 b
3 member2 0.96190007 c
4 member2 0.56403433 d
5 member1 -0.41447472 a
6 member2 0.27270458 b
7 member2 -0.01384829 c
8 member2 -0.71561501 d
9 member1 -0.81835698 a
10 member2 -2.12746977 b
11 member2 0.66185843 c
12 member2 0.07878841 d
更新 我还以为你要合并member1和member2的信息,如果只需要member2就更简单了:
ll <- l %>% map_df(enframe) %>%
filter(name=="member2") %>%
mutate(key=map(value, rownames)) %>%
unnest()
ll
# A tibble: 9 × 3
name value key
<chr> <dbl> <chr>
1 member2 -0.87049458 b
2 member2 0.96190007 c
3 member2 0.56403433 d
4 member2 0.27270458 b
5 member2 -0.01384829 c
6 member2 -0.71561501 d
7 member2 -2.12746977 b
8 member2 0.66185843 c
9 member2 0.07878841 d