检索两个分层组织的列表之间的共同元素
Retrieving elements in common between two lists hierarchically organized
这是之前 post 在此处提出的问题的变体。
我认为这个问题可能会对其解决方案形式进行足够的更改,因此需要一个新的 post.
我想在比较两个层次结构的列表时检索共同元素的列表(站点包含组,组包含元素)
这是一些虚拟数据:
site<-c('A','A','A','A','A','A','A','A','A','B','B','B','B','B','B')
group<-c('A1','A1','A2','A2','A2','A3','A3','A3','A3',
'B1','B1','B2','B2','B2','B2')
element<-c("red","orange","blue","black","white", "black","cream","yellow","purple","red","orange","blue","white","gray","salmon")
d<-cbind(site,group,element)
问题是我不想在组之间进行所有可能的比较,而只是在站点之间进行比较。因此,我以这种方式组织数据。
#first level list - by site
sitelist<-split(d, list(d$site),drop = TRUE)
#list by group
nestedlist <- lapply(sitelist, function(x) split(x, x[['group']], drop = TRUE))
我的目的是创建一个列表,其中包含来自两个站点的组之间的共同元素(我的原始数据有其他站点)。因此,如果数据结构如下:
A1 A2 A3
B1 2 0 0
B2 0 2 0
我需要出现在 A1/B1 和 A2/B2 交集的元素列表。
因此输出为:
output
$A1-B1
[1] "red" "orange"
$A2-B2
[2] "blue" "white"
我的尝试与 post 在上一个相关问题中所做的类似,只是对我认为可行的内容进行了调整。
t <- outer(1:length(d$A),
1:length(d$B),
FUN=function(i,j){
sapply(1:length(i),
FUN=function(x)
intersect(d$A[[i]]$element, d$B[[j]]$element) )
})
再次感谢您的帮助,如果问题过于相似,我们深表歉意。我尝试调整所有建议都失败了。
您的代码 (outer
) 的前提是正确的。这里有几个想法。 (请注意,我将您的数据更改为使用 cbind.data.frame(..., stringsAsFactors=FALSE)
。)
首先,重组对我有点帮助:
dl <- list(
A = with(subset(d, site=="A"), split(element, group)),
B = with(subset(d, site=="B"), split(element, group))
)
str(dl)
# List of 2
# $ A:List of 3
# ..$ A1: chr [1:2] "red" "orange"
# ..$ A2: chr [1:3] "blue" "black" "white"
# ..$ A3: chr [1:4] "black" "cream" "yellow" "purple"
# $ B:List of 2
# ..$ B1: chr [1:2] "red" "orange"
# ..$ B2: chr [1:4] "blue" "white" "gray" "salmon"
您更喜欢哪个选项取决于您打算如何检索结果。如果您以编程方式执行此操作,那么我认为我更喜欢选项 1,它完全明确地随机访问配对;使用选项 2 进行随机访问配对,您需要将所需的索引组合成一个新字符串并假设它在列表中。
如果您想要的结果主要用于报告,那么选项 2 可能会起作用,因为默认情况下它是用人类可读的名称展开的。 YMMV.
选项 1:
func <- function(a,b) Map(intersect, a, b)
o1 <- outer(dl[[1]], dl[[2]], func)
o1
# B1 B2
# A1 Character,2 Character,0
# A2 Character,0 Character,2
# A3 Character,0 Character,0
这看起来像是胡言乱语,但每个单元格都是 list
:
o1["A1","B1"]
# [[1]]
# [1] "red" "orange"
o1[["A2","B2"]] # only difference: double-bracket, returns vector not list
# [1] "blue" "white"
apply(o1, 1, lengths)
# A1 A2 A3
# B1 2 0 0
# B2 0 2 0
选项 2:
eg2 <- do.call(expand.grid, dl)
o2 <- setNames(Map(intersect, eg2$A, eg2$B),
apply(sapply(eg2, names), 1, paste, collapse = "-"))
o2
# $`A1-B1`
# [1] "red" "orange"
# $`A2-B1`
# character(0)
# $`A3-B1`
# character(0)
# $`A1-B2`
# character(0)
# $`A2-B2`
# [1] "blue" "white"
# $`A3-B2`
# character(0)
如果空元素是个问题,你可以
Filter(length, o2)
# $`A1-B1`
# [1] "red" "orange"
# $`A2-B2`
# [1] "blue" "white"
这是之前 post 在此处提出的问题的变体。
我想在比较两个层次结构的列表时检索共同元素的列表(站点包含组,组包含元素)
这是一些虚拟数据:
site<-c('A','A','A','A','A','A','A','A','A','B','B','B','B','B','B')
group<-c('A1','A1','A2','A2','A2','A3','A3','A3','A3',
'B1','B1','B2','B2','B2','B2')
element<-c("red","orange","blue","black","white", "black","cream","yellow","purple","red","orange","blue","white","gray","salmon")
d<-cbind(site,group,element)
问题是我不想在组之间进行所有可能的比较,而只是在站点之间进行比较。因此,我以这种方式组织数据。
#first level list - by site
sitelist<-split(d, list(d$site),drop = TRUE)
#list by group
nestedlist <- lapply(sitelist, function(x) split(x, x[['group']], drop = TRUE))
我的目的是创建一个列表,其中包含来自两个站点的组之间的共同元素(我的原始数据有其他站点)。因此,如果数据结构如下:
A1 A2 A3
B1 2 0 0
B2 0 2 0
我需要出现在 A1/B1 和 A2/B2 交集的元素列表。 因此输出为:
output
$A1-B1
[1] "red" "orange"
$A2-B2
[2] "blue" "white"
我的尝试与 post 在上一个相关问题中所做的类似,只是对我认为可行的内容进行了调整。
t <- outer(1:length(d$A),
1:length(d$B),
FUN=function(i,j){
sapply(1:length(i),
FUN=function(x)
intersect(d$A[[i]]$element, d$B[[j]]$element) )
})
再次感谢您的帮助,如果问题过于相似,我们深表歉意。我尝试调整所有建议都失败了。
您的代码 (outer
) 的前提是正确的。这里有几个想法。 (请注意,我将您的数据更改为使用 cbind.data.frame(..., stringsAsFactors=FALSE)
。)
首先,重组对我有点帮助:
dl <- list(
A = with(subset(d, site=="A"), split(element, group)),
B = with(subset(d, site=="B"), split(element, group))
)
str(dl)
# List of 2
# $ A:List of 3
# ..$ A1: chr [1:2] "red" "orange"
# ..$ A2: chr [1:3] "blue" "black" "white"
# ..$ A3: chr [1:4] "black" "cream" "yellow" "purple"
# $ B:List of 2
# ..$ B1: chr [1:2] "red" "orange"
# ..$ B2: chr [1:4] "blue" "white" "gray" "salmon"
您更喜欢哪个选项取决于您打算如何检索结果。如果您以编程方式执行此操作,那么我认为我更喜欢选项 1,它完全明确地随机访问配对;使用选项 2 进行随机访问配对,您需要将所需的索引组合成一个新字符串并假设它在列表中。
如果您想要的结果主要用于报告,那么选项 2 可能会起作用,因为默认情况下它是用人类可读的名称展开的。 YMMV.
选项 1:
func <- function(a,b) Map(intersect, a, b)
o1 <- outer(dl[[1]], dl[[2]], func)
o1
# B1 B2
# A1 Character,2 Character,0
# A2 Character,0 Character,2
# A3 Character,0 Character,0
这看起来像是胡言乱语,但每个单元格都是 list
:
o1["A1","B1"]
# [[1]]
# [1] "red" "orange"
o1[["A2","B2"]] # only difference: double-bracket, returns vector not list
# [1] "blue" "white"
apply(o1, 1, lengths)
# A1 A2 A3
# B1 2 0 0
# B2 0 2 0
选项 2:
eg2 <- do.call(expand.grid, dl)
o2 <- setNames(Map(intersect, eg2$A, eg2$B),
apply(sapply(eg2, names), 1, paste, collapse = "-"))
o2
# $`A1-B1`
# [1] "red" "orange"
# $`A2-B1`
# character(0)
# $`A3-B1`
# character(0)
# $`A1-B2`
# character(0)
# $`A2-B2`
# [1] "blue" "white"
# $`A3-B2`
# character(0)
如果空元素是个问题,你可以
Filter(length, o2)
# $`A1-B1`
# [1] "red" "orange"
# $`A2-B2`
# [1] "blue" "white"