[英]Is there an R function to get the unique edges in an undirected (not directed) network?
我想计算无向网络中唯一边的数量,例如 net
x y
1 A B
2 B A
3 A B
这个矩阵应该只有一个唯一的边,因为边 AB 和 BA 对于无向网络是相同的。
对于有向网络,我可以通过以下方式获得唯一边的数量:
nrow(唯一的(net[,c("x","y"]))
但这不适用于无向网络。
尝试这个,
df <- data.frame(x=c("A", "B", "A"), y = c("B", "A", "B"))
unique(apply(df, 1, function(x) paste(sort(unlist(strsplit(x, " "))),collapse = " ")))
[1] "A B"
那么这是如何工作的呢?
我们正在对数据框的每一行应用一个函数,因此我们可以一次获取每一行。 取df的第二行,
df[2,] xy 1 BA
然后我们拆分( strsplit
)这个,并unlist
每个字母的向量,(我们使用as.matrix
来隔离元素)
unlist(strsplit(as.matrix(df[2,]), " ")) [1] "B" "A"
使用 sort 功能按字母顺序排列,然后将它们粘贴在一起,
paste(sort(unlist(strsplit(as.matrix(df[2,]), " "))), collapse = " ") [1] "AB"
然后apply
函数对所有行执行此操作,因为我们将索引设置为 1,然后使用unique
函数来识别唯一的边。
延期
这可以扩展到 n 个变量,例如 n=3,
df <- data.frame(x=c("A", "B", "A"), y = c("B", "A", "B"), z = c("C", "D", "D"))
unique(apply(df, 1, function(x) paste(sort(unlist(strsplit(x, " "))),collapse = " ")))
[1] "A B C" "A B D"
如果需要更多字母,只需将两个字母组合如下,
df <- data.frame(x=c("A", "BC", "A"), y = c("B", "A", "BC"))
df
x y
1 A B
2 BC A
3 A BC
unique(apply(df, 1, function(x) paste(sort(unlist(strsplit(x, " "))),collapse = " ")))
[1] "A B" "A BC"
旧版本
使用tidyverse
包,创建一个名为rev
的函数,它可以对我们的边进行排序,然后使用mutate
创建一个结合 x 和 y 列的新列,这样它就可以很好地与rev
函数配合使用,然后通过函数并找到唯一的对。
library(tidyverse)
rev <- function(x){
unname(sapply(x, function(x) {
paste(sort(trimws(strsplit(x[1], ',')[[1]])), collapse=',')} ))
}
df <- data.frame(x=c("A", "B", "A"), y = c("B", "A", "B"))
rows <- df %>%
mutate(both = c(paste(x, y, sep = ", ")))
unique(rev(rows$both))
鉴于您正在使用网络, igraph
解决方案:
library(igraph)
as_data_frame(simplify(graph_from_data_frame(dat, directed=FALSE)))
然后使用nrow
说明
dat %>%
graph_from_data_frame(., directed=FALSE) %>% # convert to undirected graph
simplify %>% # remove loops / multiple edges
as_data_frame # return remaining edges
这是一个没有igraph
干预的解决方案,全部在一个管道内:
df = tibble(x=c("A", "B", "A"), y = c("B", "A", "B"))
可以使用group_by()
然后sort()
值的组合并通过mutate()
将它们paste()
到新列中。 如果您有“真正的”重复项(AB,AB 将进入一组),则使用unique()
)。
df %>%
group_by(x, y) %>%
mutate(edge_id = paste(sort(unique(c(x,y))), collapse=" "))
当您在新列中正确排序边缘名称时,计算唯一值或从数据框中过滤重复项非常简单。
如果你有额外的边变量,只需将它们添加到分组中。
如果您不使用{igraph}
或者只是想知道如何在没有任何依赖的情况下干净地使用它...
这是你的数据...
your_edge_list <- data.frame(x = c("A", "B", "A"),
y = c("B", "A", "B"),
stringsAsFactors = FALSE)
your_edge_list
#> x y
#> 1 A B
#> 2 B A
#> 3 A B
这是一个分步分解...
`%>%` <- magrittr::`%>%`
your_edge_list %>%
apply(1L, sort) %>% # sort dyads
t() %>% # transpose resulting matrix to get the original shape back
unique() %>% # get the unique rows
as.data.frame() %>% # back to data frame
setNames(names(your_edge_list)) # reset column names
#> x y
#> 1 A B
如果我们放下管道,它的核心看起来像这样......
unique(t(apply(your_edge_list, 1, sort)))
#> [,1] [,2]
#> [1,] "A" "B"
我们可以将它包装在一个函数中:1) 处理有向和无向,2) 处理数据帧和(更常见的)矩阵,以及 3)可以丢弃循环......
simplify_edgelist <- function(el, directed = TRUE, drop_loops = TRUE) {
stopifnot(ncol(el) == 2)
if (drop_loops) {
el <- el[el[, 1] != el[, 2], ]
}
if (directed) {
out <- unique(el)
} else {
out <- unique(t(apply(el, 1, sort)))
}
colnames(out) <- colnames(el)
if (is.data.frame(el)) {
as.data.frame(out, stringsAsFactors = FALSE)
} else {
out
}
}
el2 <- rbind(your_edge_list,
data.frame(x = c("C", "C"), y = c("C", "A"), stringsAsFactors = FALSE))
el2
#> x y
#> 1 A B
#> 2 B A
#> 3 A B
#> 4 C C
#> 5 C A
simplify_edgelist(el2, directed = FALSE)
#> x y
#> 1 A B
#> 5 A C
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.