"combine" 来自 R 中多个列表的多元素索引的所有组合的更好方法?
Better way to "combine" all combinations of multi-element indices from multiple lists in R?
假设我有两个列表,每个列表在多个索引中包含可变数量的多个子元素:
list.a <- list(c("a","b","c"), c("x", "y", "z"))
list.b <- list(c("d", "e", "f","g"), c("m", "n"))
这导致:
> list.a
[[1]]
[1] "a" "b" "c"
[[2]]
[1] "x" "y" "z"
和
> list.b
[[1]]
[1] "d" "e" "f" "g" "h"
[[2]]
[1] "m" "n"
如何从每个列表的相应索引中递归访问每个 combo 子元素?
例如,我想访问第一个索引和 x-m、x-n、y-m、y-n 的 a-d、a-e、a-f、a-g、b-d、b-e、... 等的组合, z-m 和 z-n 来自每个列表的第二个索引。
[[1]]
[1] "a d" "a e" "a f" "a g" "b d" "b e" "b f" "b g" "c d" "c e" "c f" "c g"
[[2]]
[1] "x m" "x n" "y m" "y n" "z m" "z n"
mapply
当我从每个列表中有多个子元素时似乎不起作用(特别是如果两个列表中的元素数量不相等):
> mapply(paste,list.a,list.b)
[[1]]
[1] "a d" "b e" "c f" "a g"
[[2]]
[1] "x m" "y n" "z m"
- 它跳过了一半的组合,而是只循环使用两个列表中较短的一个。我希望它在两个列表的共享索引中合并 all 组合。
我知道我也可以使用 for
循环...:[=29=]
list.d <- list()
for(i in 1:length(list.a)) {
list.c <- list()
list.d[[i]] <- {
for(j in list.a[[i]]) {
for(k in list.b[[i]]) {
list.c <- c(list.c, paste(j, k))
}
}
unlist(list.c)
}
}
产生所需结果:
> list.d
[[1]]
[1] "a d" "a e" "a f" "a g" "b d" "b e" "b f" "b g" "c d" "c e" "c f" "c g"
[[2]]
[1] "x m" "x n" "y m" "y n" "z m" "z n"
...但是循环充其量是混乱的,并且对于巨大的列表变得相当慢。
有更好的方法吗?
- 具体来说,是否有一种特殊的函数或某种方法可以使用
apply
函数来更有效地完成这项任务?
<申请>
(这部分不需要回答问题,但提供context/extension它的使用):
对于那些好奇的人,我想将其扩展到 paste()
之外,而是想在 data.frame 上使用它。
例如:
假设我有两个列表,每个列表包含多个索引和多个子元素:
l1 <- list(c(1933:1935),c(1950:1954), c(2012:2013)) #groups of years
l2 <- list(c(19:21),c(19:24),c(22:26)) #groups of plot numbers
我们还假设我有以下 data.frame:
dat <- data.frame(plot = rep(1:30,81), year = rep(1933:2013, each = 30), area = sample(270))
> head(dat)
plot year area
1 1 1933 137
2 2 1933 72
3 3 1933 136
4 4 1933 187
5 5 1933 206
6 6 1933 74
我想创建一个新列表(我们称之为 l3
),其中包含 l1
(年)和 l2
(地块)的所有组合的总面积对于每个一致的列表索引。
例如,结果列表中 [[1]]
的结果将是地块 19、20 & 21 的面积总和1933 年、1934 年 & 1935 年。
[[2]]
的结果将是 1950 年到 1954 年每年的地块 19 到 24 的总面积。
你需要expand.grid
,它用来:
Create a data frame from all combinations of the supplied vectors or
factors.
使用do.call(paste, ...)
是将数据框的所有列粘贴在一起。
Map(function(a,b) do.call(paste, expand.grid(a,b)), list.a, list.b)
#[[1]]
# [1] "a d" "b d" "c d" "a e" "b e" "c e" "a f" "b f" "c f" "a g" "b g" "c g"
#[[2]]
#[1] "x m" "y m" "z m" "x n" "y n" "z n"
对于问题的第二部分,我们可以先按年份对数据框进行子集化并绘制,然后按年聚合面积使用 rowsum:
Map(function(years, plots) {
with(subset(dat, plot %in% plots & year %in% years), rowsum(area, year))
}, l1, l2)
[[1]]
[,1]
1933 257
1934 398
1935 640
[[2]]
[,1]
1950 950
1951 457
1952 601
1953 1202
1954 1148
[[3]]
[,1]
2012 736
2013 497
假设我有两个列表,每个列表在多个索引中包含可变数量的多个子元素:
list.a <- list(c("a","b","c"), c("x", "y", "z"))
list.b <- list(c("d", "e", "f","g"), c("m", "n"))
这导致:
> list.a [[1]] [1] "a" "b" "c" [[2]] [1] "x" "y" "z"
和
> list.b [[1]] [1] "d" "e" "f" "g" "h" [[2]] [1] "m" "n"
如何从每个列表的相应索引中递归访问每个 combo 子元素?
例如,我想访问第一个索引和 x-m、x-n、y-m、y-n 的 a-d、a-e、a-f、a-g、b-d、b-e、... 等的组合, z-m 和 z-n 来自每个列表的第二个索引。
[[1]] [1] "a d" "a e" "a f" "a g" "b d" "b e" "b f" "b g" "c d" "c e" "c f" "c g" [[2]] [1] "x m" "x n" "y m" "y n" "z m" "z n"
mapply
当我从每个列表中有多个子元素时似乎不起作用(特别是如果两个列表中的元素数量不相等):
> mapply(paste,list.a,list.b)
[[1]]
[1] "a d" "b e" "c f" "a g"
[[2]]
[1] "x m" "y n" "z m"
- 它跳过了一半的组合,而是只循环使用两个列表中较短的一个。我希望它在两个列表的共享索引中合并 all 组合。
我知道我也可以使用 for
循环...:[=29=]
list.d <- list()
for(i in 1:length(list.a)) {
list.c <- list()
list.d[[i]] <- {
for(j in list.a[[i]]) {
for(k in list.b[[i]]) {
list.c <- c(list.c, paste(j, k))
}
}
unlist(list.c)
}
}
产生所需结果:
> list.d
[[1]]
[1] "a d" "a e" "a f" "a g" "b d" "b e" "b f" "b g" "c d" "c e" "c f" "c g"
[[2]]
[1] "x m" "x n" "y m" "y n" "z m" "z n"
...但是循环充其量是混乱的,并且对于巨大的列表变得相当慢。
有更好的方法吗?
- 具体来说,是否有一种特殊的函数或某种方法可以使用
apply
函数来更有效地完成这项任务?
<申请>
(这部分不需要回答问题,但提供context/extension它的使用):
对于那些好奇的人,我想将其扩展到 paste()
之外,而是想在 data.frame 上使用它。
例如:
假设我有两个列表,每个列表包含多个索引和多个子元素:
l1 <- list(c(1933:1935),c(1950:1954), c(2012:2013)) #groups of years l2 <- list(c(19:21),c(19:24),c(22:26)) #groups of plot numbers
我们还假设我有以下 data.frame:
dat <- data.frame(plot = rep(1:30,81), year = rep(1933:2013, each = 30), area = sample(270)) > head(dat) plot year area 1 1 1933 137 2 2 1933 72 3 3 1933 136 4 4 1933 187 5 5 1933 206 6 6 1933 74
我想创建一个新列表(我们称之为
l3
),其中包含l1
(年)和l2
(地块)的所有组合的总面积对于每个一致的列表索引。例如,结果列表中
[[1]]
的结果将是地块 19、20 & 21 的面积总和1933 年、1934 年 & 1935 年。[[2]]
的结果将是 1950 年到 1954 年每年的地块 19 到 24 的总面积。
你需要expand.grid
,它用来:
Create a data frame from all combinations of the supplied vectors or factors.
使用do.call(paste, ...)
是将数据框的所有列粘贴在一起。
Map(function(a,b) do.call(paste, expand.grid(a,b)), list.a, list.b)
#[[1]]
# [1] "a d" "b d" "c d" "a e" "b e" "c e" "a f" "b f" "c f" "a g" "b g" "c g"
#[[2]]
#[1] "x m" "y m" "z m" "x n" "y n" "z n"
对于问题的第二部分,我们可以先按年份对数据框进行子集化并绘制,然后按年聚合面积使用 rowsum:
Map(function(years, plots) {
with(subset(dat, plot %in% plots & year %in% years), rowsum(area, year))
}, l1, l2)
[[1]]
[,1]
1933 257
1934 398
1935 640
[[2]]
[,1]
1950 950
1951 457
1952 601
1953 1202
1954 1148
[[3]]
[,1]
2012 736
2013 497