如何比较两个列表并将 "hits" 输出到数据框中
How can I compare two lists and output "hits" into a dataframe
我试图在这里和 google 上找到答案,但没有成功,我已经为这个问题苦苦挣扎了几天,所以非常感谢帮助。我正在分析一个网络,看看周期是否倾向于在谨慎的社区内或它们之间,或者没有模式。我的数据是一个循环列表(三个节点形成一个循环)和一个社区列表(可变数量的节点)。我有两个问题,1) 如何比较两个列表,以及 2) 如何以可读的方式输出比较结果:
- 问题 1
我有两个列表(都是 igraph objects),一个包含 678 个项目(每个 3 个元素,所有字符),另一个包含 11 个项目,每个项目具有不同数量的元素。示例:
x1 <- as.character(c(1,3,5))
x2 <- as.character(c(2,4,6))
x3 <- as.character(c(7,8,9))
x4 <- as.character(c(10,11,12))
x <- list(x1, x2, x3, x4)
y1 <- as.character(c(1,2,3,4,5))
y2 <- as.character(c(2,3,4,5))
y3 <- as.character(c(1,2,3,4,5,7,8,9))
y <- list(y1, y2, y3)
给予:
> x
[[1]]
[1] "1" "3" "5"
[[2]]
[1] "2" "4" "6"
[[3]]
[1] "7" "8" "9"
[[4]]
[1] "10" "11" "12"
> y
[[1]]
[1] "1" "2" "3" "4" "5"
[[2]]
[1] "2" "3" "4" "5"
[[3]]
[1] "1" "2" "3" "4" "5" "7" "8" "9"
我想将 x
中的每个组件与 y
中的每个组件进行比较并添加每个命中(即当 x[[i]]
中的所有元素也在 [=20= 中找到时]) 到一个新的数据框。我尝试使用 all()
和 %in%
进行循环,但这没有用:
for (i in 1:length(x)) {
for (j in 1:length(y)) {
hits <- all(y[[j]] %in% x[[i]]) == TRUE
print(hits)
}
}
这 returns 12 FALSE
命中。检查单个组件,它应该有效,因为:
all(x[[1]] %in% y[[1]])
Returns TRUE
应该的,并且:
all(x[[1]] %in% y[[2]])
Returns FALSE
应该的。我哪里错了?
- 问题 2
我看到了一些将循环结果输出到 df 的解决方案,但这并不是我所需要的。我想要的输出是一个数据框,它告诉我每个周期在哪个社区。由于只有 11 个社区,它可以只让我参考列表组件的索引,但我还没有找到执行此操作的方法。我也可以只使用 paste()
将社区的节点名称连接成一个标题。无论哪种方式,这是我需要的输出:
cycle community
1 1_3_5 1_2_3_4_5
2 1_3_5 1_2_3_4_5_7_8_9
3 7_8_9 1_2_3_4_5_7_8_9
我猜是某种 if 语句。我觉得这应该很容易执行,而且我应该能够自己解决。不过,感谢您抽出宝贵时间,对这篇文章感到抱歉。
你弄错了
for (i in 1:length(x)) {
for (j in 1:length(y)) {
# hits <- all(y[[j]] %in% x[[i]]) == TRUE
hits <- all(x[[i]] %in% y[[j]]) == TRUE
print(hits)
}
}
对于第二部分,您可以存储命中的索引以备后用。
a <- list()
for (i in 1:length(x)) {
for (j in 1:length(y)) {
# hits <- all(y[[j]] %in% x[[i]]) == TRUE
hits <- all(x[[i]] %in% y[[j]]) == TRUE
if(hits == TRUE){
a[[length(a)+1]] <- c(i,j)
}
}
}
问题的最后一部分,即循环和社区标签的创建,可以使用 stringi::stri_join()
(或评论中指出的 paste()
)来完成。整理 Jt Miclat 的答案中创建的列表的最后一步如下,使用列表 a
中的索引为 cycle
和 community
提取适当的字符串,生成数据帧,然后rbind()
结果到单个数据框。
# combine with cycle & community tags
cycles <- sapply(x,paste,collapse="_")
communities <- sapply(y,paste,collapse="_")
b <- lapply(a,function(x){
cycle <- cycles[x[1]]
community <- communities[x[2]]
data.frame(x=x[1],y=x[2],cycle=cycle,community=community,
stringsAsFactors=FALSE)
})
df <- do.call(rbind,b)
df
...输出:
> df <- do.call(rbind,b)
> df
x y cycle community
1 1 1 1_3_5 1_2_3_4_5
2 1 3 1_3_5 1_2_3_4_5_7_8_9
3 3 3 7_8_9 1_2_3_4_5_7_8_9
>
你可以利用 outer
:
outer(x,y,function(w,z)Map(function(i,j)all(i%in%j),w,z))->results
[,1] [,2] [,3]
[1,] TRUE FALSE TRUE
[2,] FALSE FALSE FALSE
[3,] FALSE FALSE TRUE
[4,] FALSE FALSE FALSE
x
是行,而 y
是列,所以要检查 all(x[[1]]%in%y[[2]])
,只需检查第 1 行第 2 列,即元素 [1,2] 等。
然后您可以使用 apply
和自己创建的函数:
fun<-function(i)c(paste(x[[i[1]]],collapse ="_"), paste(y[[i[2]]],collapse ="_"))
t(apply(which(result==T,T),1,fun))
[,1] [,2]
[1,] "1_3_5" "1_2_3_4_5"
[2,] "1_3_5" "1_2_3_4_5_7_8_9"
[3,] "7_8_9" "1_2_3_4_5_7_8_9"
我试图在这里和 google 上找到答案,但没有成功,我已经为这个问题苦苦挣扎了几天,所以非常感谢帮助。我正在分析一个网络,看看周期是否倾向于在谨慎的社区内或它们之间,或者没有模式。我的数据是一个循环列表(三个节点形成一个循环)和一个社区列表(可变数量的节点)。我有两个问题,1) 如何比较两个列表,以及 2) 如何以可读的方式输出比较结果:
- 问题 1
我有两个列表(都是 igraph objects),一个包含 678 个项目(每个 3 个元素,所有字符),另一个包含 11 个项目,每个项目具有不同数量的元素。示例:
x1 <- as.character(c(1,3,5))
x2 <- as.character(c(2,4,6))
x3 <- as.character(c(7,8,9))
x4 <- as.character(c(10,11,12))
x <- list(x1, x2, x3, x4)
y1 <- as.character(c(1,2,3,4,5))
y2 <- as.character(c(2,3,4,5))
y3 <- as.character(c(1,2,3,4,5,7,8,9))
y <- list(y1, y2, y3)
给予:
> x
[[1]]
[1] "1" "3" "5"
[[2]]
[1] "2" "4" "6"
[[3]]
[1] "7" "8" "9"
[[4]]
[1] "10" "11" "12"
> y
[[1]]
[1] "1" "2" "3" "4" "5"
[[2]]
[1] "2" "3" "4" "5"
[[3]]
[1] "1" "2" "3" "4" "5" "7" "8" "9"
我想将 x
中的每个组件与 y
中的每个组件进行比较并添加每个命中(即当 x[[i]]
中的所有元素也在 [=20= 中找到时]) 到一个新的数据框。我尝试使用 all()
和 %in%
进行循环,但这没有用:
for (i in 1:length(x)) {
for (j in 1:length(y)) {
hits <- all(y[[j]] %in% x[[i]]) == TRUE
print(hits)
}
}
这 returns 12 FALSE
命中。检查单个组件,它应该有效,因为:
all(x[[1]] %in% y[[1]])
Returns TRUE
应该的,并且:
all(x[[1]] %in% y[[2]])
Returns FALSE
应该的。我哪里错了?
- 问题 2
我看到了一些将循环结果输出到 df 的解决方案,但这并不是我所需要的。我想要的输出是一个数据框,它告诉我每个周期在哪个社区。由于只有 11 个社区,它可以只让我参考列表组件的索引,但我还没有找到执行此操作的方法。我也可以只使用 paste()
将社区的节点名称连接成一个标题。无论哪种方式,这是我需要的输出:
cycle community
1 1_3_5 1_2_3_4_5
2 1_3_5 1_2_3_4_5_7_8_9
3 7_8_9 1_2_3_4_5_7_8_9
我猜是某种 if 语句。我觉得这应该很容易执行,而且我应该能够自己解决。不过,感谢您抽出宝贵时间,对这篇文章感到抱歉。
你弄错了
for (i in 1:length(x)) {
for (j in 1:length(y)) {
# hits <- all(y[[j]] %in% x[[i]]) == TRUE
hits <- all(x[[i]] %in% y[[j]]) == TRUE
print(hits)
}
}
对于第二部分,您可以存储命中的索引以备后用。
a <- list()
for (i in 1:length(x)) {
for (j in 1:length(y)) {
# hits <- all(y[[j]] %in% x[[i]]) == TRUE
hits <- all(x[[i]] %in% y[[j]]) == TRUE
if(hits == TRUE){
a[[length(a)+1]] <- c(i,j)
}
}
}
问题的最后一部分,即循环和社区标签的创建,可以使用 stringi::stri_join()
(或评论中指出的 paste()
)来完成。整理 Jt Miclat 的答案中创建的列表的最后一步如下,使用列表 a
中的索引为 cycle
和 community
提取适当的字符串,生成数据帧,然后rbind()
结果到单个数据框。
# combine with cycle & community tags
cycles <- sapply(x,paste,collapse="_")
communities <- sapply(y,paste,collapse="_")
b <- lapply(a,function(x){
cycle <- cycles[x[1]]
community <- communities[x[2]]
data.frame(x=x[1],y=x[2],cycle=cycle,community=community,
stringsAsFactors=FALSE)
})
df <- do.call(rbind,b)
df
...输出:
> df <- do.call(rbind,b)
> df
x y cycle community
1 1 1 1_3_5 1_2_3_4_5
2 1 3 1_3_5 1_2_3_4_5_7_8_9
3 3 3 7_8_9 1_2_3_4_5_7_8_9
>
你可以利用 outer
:
outer(x,y,function(w,z)Map(function(i,j)all(i%in%j),w,z))->results
[,1] [,2] [,3]
[1,] TRUE FALSE TRUE
[2,] FALSE FALSE FALSE
[3,] FALSE FALSE TRUE
[4,] FALSE FALSE FALSE
x
是行,而 y
是列,所以要检查 all(x[[1]]%in%y[[2]])
,只需检查第 1 行第 2 列,即元素 [1,2] 等。
然后您可以使用 apply
和自己创建的函数:
fun<-function(i)c(paste(x[[i[1]]],collapse ="_"), paste(y[[i[2]]],collapse ="_"))
t(apply(which(result==T,T),1,fun))
[,1] [,2]
[1,] "1_3_5" "1_2_3_4_5"
[2,] "1_3_5" "1_2_3_4_5_7_8_9"
[3,] "7_8_9" "1_2_3_4_5_7_8_9"