有没有办法根据 R 中另一个数据框中的共享值构建成对数据框?
Is there a way to build a pairwise data frame based on shared values in another data frame in R?
例如 DF1 是:
Id1 Id2
1 10
2 10
3 7
4 7
5 10
并想要 DF2:
Id1 Id2
1 2
1 5
2 5
3 4
数据框 DF2 是 DF1 中 Id1 列的成对值集,它们在 DF1 的 Id2 中共享一个公共值。
我的尝试:
temp <- do.call("cbind", split(DF1, rep(c(1,2), length.out = nrow(DF1))))
(DF2 <- temp %>% select("1.Id1", "2.Id2"))
但这不会生成成对数据框:
Id1 Id2
1 2
3 4
您可以 split
Id1
基于 Id2
中的值,并使用 combn
创建所有可能的组合并绑定结果。
do.call(rbind, lapply(split(df$Id1, df$Id2), function(x) t(combn(x, 2))))
# [,1] [,2]
#[1,] 3 4
#[2,] 1 2
#[3,] 1 5
#[4,] 2 5
我们也可以使用更短的 by
:
do.call(rbind, by(df$Id1, df$Id2, function(x) t(combn(x, 2))))
我们可以使用 tidyverse 方法,其中我们按 'Id2' 分组,获取 'Id1' 的 combn
,取消嵌套为宽格式并重命名列
library(dplyr)
library(tidyr)
library(stringr)
DF1 %>%
# // group by Id2
group_by(Id2) %>%
# // get the combinations in summarise
summarise(out = combn(Id1, 2, simplify = FALSE)) %>%
ungroup %>%
# // unnest to wide format
unnest_wider(c(out)) %>%
select(-Id2) %>%
rename_all(~ str_c("V", seq_along(.)))
# A tibble: 4 x 2
# V1 V2
# <int> <int>
#1 3 4
#2 1 2
#3 1 5
#4 2 5
数据
DF1 <- structure(list(Id1 = 1:5, Id2 = c(10L, 10L, 7L, 7L, 10L)),
class = "data.frame", row.names = c(NA,
-5L))
这是另一个 tidyverse
使用 full_join
的方法。
library(dplyr)
library(purrr)
dat2 <- dat %>%
full_join(dat, by = "Id2") %>%
filter(Id1.x != Id1.y) %>%
mutate(Id_sort = map2_chr(Id1.x, Id1.y, ~paste(sort(c(.x, .y)), collapse = ", "))) %>%
distinct(Id_sort, .keep_all = TRUE) %>%
select(Id1 = Id1.x, Id2 = Id1.y)
dat2
# Id1 Id2
# 1 1 2
# 2 1 5
# 3 2 5
# 4 3 4
数据
dat <- read.table(text = "Id1 Id2
1 10
2 10
3 7
4 7
5 10",
header = TRUE)
它也可以被概念化为一个 network/graph 问题:
df1 <- data.frame(Id1 = 1:5, Id2 = c(10L, 10L, 7L, 7L, 10L))
library(igraph)
g <- graph.data.frame(df1)
g <- connect(g, 2)
g <- induced_subgraph(g, V(g) %in% df1$Id1)
as_edgelist(g)
# [,1] [,2]
#[1,] "1" "2"
#[2,] "1" "5"
#[3,] "2" "5"
#[4,] "3" "4"
例如 DF1 是:
Id1 Id2
1 10
2 10
3 7
4 7
5 10
并想要 DF2:
Id1 Id2
1 2
1 5
2 5
3 4
数据框 DF2 是 DF1 中 Id1 列的成对值集,它们在 DF1 的 Id2 中共享一个公共值。
我的尝试:
temp <- do.call("cbind", split(DF1, rep(c(1,2), length.out = nrow(DF1))))
(DF2 <- temp %>% select("1.Id1", "2.Id2"))
但这不会生成成对数据框:
Id1 Id2
1 2
3 4
您可以 split
Id1
基于 Id2
中的值,并使用 combn
创建所有可能的组合并绑定结果。
do.call(rbind, lapply(split(df$Id1, df$Id2), function(x) t(combn(x, 2))))
# [,1] [,2]
#[1,] 3 4
#[2,] 1 2
#[3,] 1 5
#[4,] 2 5
我们也可以使用更短的 by
:
do.call(rbind, by(df$Id1, df$Id2, function(x) t(combn(x, 2))))
我们可以使用 tidyverse 方法,其中我们按 'Id2' 分组,获取 'Id1' 的 combn
,取消嵌套为宽格式并重命名列
library(dplyr)
library(tidyr)
library(stringr)
DF1 %>%
# // group by Id2
group_by(Id2) %>%
# // get the combinations in summarise
summarise(out = combn(Id1, 2, simplify = FALSE)) %>%
ungroup %>%
# // unnest to wide format
unnest_wider(c(out)) %>%
select(-Id2) %>%
rename_all(~ str_c("V", seq_along(.)))
# A tibble: 4 x 2
# V1 V2
# <int> <int>
#1 3 4
#2 1 2
#3 1 5
#4 2 5
数据
DF1 <- structure(list(Id1 = 1:5, Id2 = c(10L, 10L, 7L, 7L, 10L)),
class = "data.frame", row.names = c(NA,
-5L))
这是另一个 tidyverse
使用 full_join
的方法。
library(dplyr)
library(purrr)
dat2 <- dat %>%
full_join(dat, by = "Id2") %>%
filter(Id1.x != Id1.y) %>%
mutate(Id_sort = map2_chr(Id1.x, Id1.y, ~paste(sort(c(.x, .y)), collapse = ", "))) %>%
distinct(Id_sort, .keep_all = TRUE) %>%
select(Id1 = Id1.x, Id2 = Id1.y)
dat2
# Id1 Id2
# 1 1 2
# 2 1 5
# 3 2 5
# 4 3 4
数据
dat <- read.table(text = "Id1 Id2
1 10
2 10
3 7
4 7
5 10",
header = TRUE)
它也可以被概念化为一个 network/graph 问题:
df1 <- data.frame(Id1 = 1:5, Id2 = c(10L, 10L, 7L, 7L, 10L))
library(igraph)
g <- graph.data.frame(df1)
g <- connect(g, 2)
g <- induced_subgraph(g, V(g) %in% df1$Id1)
as_edgelist(g)
# [,1] [,2]
#[1,] "1" "2"
#[2,] "1" "5"
#[3,] "2" "5"
#[4,] "3" "4"