R:理解图
R: Understanding Graph
我正在使用 R 编程语言和“igraph”库。我试图更好地理解“双模式”图(有两种节点的图)的图结构。特别是,我试图了解如何“投射”两种模式(据我了解,这些通常是“二分”)图。(https://rpubs.com/pjmurphy/317838)
例如,我创建了一张“男人”和“女人”之间的关系图。虽然这个图有两种模式(男性和女性),但我不认为这个图是二分的(因为“边”可以存在于相同类型的节点之间:
library(igraph)
# I don't think this is a bipartite graph
gender_data <- data.frame(
"men" = c("john", "kevin", "mark", "kevin", "kevin", "mark", "henry", "mark", "susan", "john", "henry", "susan", "susan", "janet", "janet", "henry", "henry", "john"),
"women" = c("janet", "janet", "sarah", "lucy", "lucy", "susan", "janet", "susan", "lucy", "kevin", "lucy", "janet", "kevin", "mark", "lucy", "sarah", "mark", "mark")
)
#create directed graph
graph <- graph.data.frame(gender_data, directed=F)
graph <- simplify(graph)
V(graph)["john"]$color<-"red"
V(graph)["kevin"]$color<-"red"
V(graph)["mark"]$color<-"red"
V(graph)["janet"]$color<-"blue"
V(graph)["sarah"]$color<-"blue"
V(graph)["lucy"]$color<-"blue"
V(graph)["henry"]$color<-"red"
V(graph)["susan"]$color<-"blue"
plot(graph)
我读到,理解二分图的更好方法是通过“演员和电影”。不同的演员可以在同一部电影中,一个演员可以在不同的电影中——但演员不能与自己共享边缘,电影也不能与自己共享边缘。这是我对这样一个网络的解释:
film_data <- data.frame(
"movie" = c("movie_1", "movie_1", "movie_1", "movie_2", "movie_2", "movie_2", "movie_3", "movie_3", "movie_3", "movie_4", "movie_4", "movie_4", "movie_4", "movie_5", "movie_5", "movie_5", "movie_6", "movie_6"),
"actor" = c("actor_1", "actor_2", "actor_3", "actor_2", "actor_3", "actor_4", "actor_1", "actor_5", "actor_6", "actor_2", "actor_7", "actor_1", "actor_8", "actor_5", "actor_9", "actor_3", "actor_2", "actor_8")
)
#create directed graph
graph <- graph.data.frame(film_data, directed=F)
graph <- simplify(graph)
plot(graph)
但是,(根据这里的 Whosebug post:valued bipartite projection using R igraph),这个 actor 图仍然不是二分的(我不明白为什么):
is.bipartite(graph)
[1] FALSE
根据同一个Whosebugpost,actor graph还是可以转换成bipartite graph的(我不明白刚刚发生了什么):
V(graph)$type <- V(graph)$name %in% film_data[,1]
is.bipartite(graph)
[1] TRUE
从这里,可以进行“投射”两个独立图表的投影:
proj<-bipartite.projection(graph, V(graph)$type,multiplicity = TRUE)
proj
$proj1
IGRAPH b5bc5ca UNW- 9 16 --
+ attr: name (v/c), weight (e/n)
+ edges from b5bc5ca (vertex names):
[1] actor_1--actor_2 actor_1--actor_3 actor_1--actor_5 actor_1--actor_6 actor_1--actor_7 actor_1--actor_8 actor_2--actor_3 actor_2--actor_4
[9] actor_2--actor_7 actor_2--actor_8 actor_3--actor_4 actor_3--actor_5 actor_3--actor_9 actor_5--actor_6 actor_5--actor_9 actor_7--actor_8
$proj2
IGRAPH b5bc5ca UNW- 6 11 --
+ attr: name (v/c), weight (e/n)
+ edges from b5bc5ca (vertex names):
[1] movie_1--movie_3 movie_1--movie_4 movie_1--movie_2 movie_1--movie_6 movie_1--movie_5 movie_2--movie_4 movie_2--movie_6 movie_2--movie_5
[9] movie_3--movie_4 movie_3--movie_5 movie_4--movie_6
终于可以绘制两个投影了:
plot(proj$proj1)
plot(proj$proj2)
我的问题:
为什么原来的演员-电影图不是“二分图”?毕竟是无向循环的。
为什么 V(graph)$type <- V(graph)$name %in% film_data[,1]
行将演员-电影图转换为二分图?
有什么理由
is.bipartite(proj$proj1)
1错误
is.bipartite(proj$proj2)
1错误
这条线 proj<-bipartite.projection(graph, V(graph)$type,multiplicity = TRUE)
如何“工作”?在原来的演员-电影图中,我 特意 输入了数据,这样两部电影或两个演员之间就没有直接关系了。例如,在“proj2”中,“movie_1”和“movie_2”之间有一条边——这是怎么发生的,为什么会发生?在我的原始数据中, movie_1 和 movie_2?
之间没有这种直接关系
假设actor_1、actor_2、actor_3、actor_4是男性,actor_5、actor_6、actor_7、actor_8、actor_9为女性。现在有没有办法进行 3 次预测?男演员投影,女演员投影,电影投影?
谢谢
除了你的演员和电影类比之外,我想补充一点,一个演员可以只能连接到 0 或更多部电影,而不能连接到其他演员。而电影只能连接到 0 个或多个演员。现在,对于问题:
A1.
当某个函数的输出与您的预期不符时,查看该函数的帮助页面通常会有所帮助。此命令将解释第一个问题:
?is.bipartite
Bipartite graphs have a type vertex attribute in igraph, this is boolean and FALSE for the vertices of the first kind and TRUE for vertices of the second kind.
[...]
is_bipartite
checks whether the graph is bipartite or not. It just checks whether the graph has a vertex attribute called type
.
因此,is_bipartite
不认为原始演员-电影图是二分图,因为该图没有名为 type
的顶点属性。 graph
中根本没有信息告诉它每个顶点属于哪个集合。我们将在下一个问题中添加此信息:
A2.
这里我们将查看您已经找到的示例,我将尝试对其进行解释。我们先再看看帮助页面:
?V
Create a vertex sequence (vs) containing all vertices of a graph. [...]
此函数 V()
从图中创建一系列顶点。 V(graph)
将列出 graph
中的所有顶点。我们希望 V(graph)$type
包含基本属性 type
.
如第一个帮助页面中所述,V(graph)$type 需要为 graph
中的每个顶点包含一个 TRUE/FALSE 值,这就是此代码中所做的:
V(graph)$type <- V(graph)$name %in% film_data[,1]
V(graph)$name
是一个包含所有顶点值的向量。 film_data[,1]
是一个包含所有主顶点(第一组顶点)值的向量。查看这两个R,研究一下他们的内容,你就会明白我的意思了。
最后,%in%
运算符检查左侧的每个项目是否存在于右侧的向量中。如果是,则 return 为真。如果不是,则 return 为 FALSE。在这种情况下,它将 return 一个向量,其中每个次要顶点(例如演员)为 TRUE,对于主要组中的顶点(例如电影)为 FALSE。
完整的构造 V(graph)$name %in% film_data[,1]
因此创建了一个 TRUE 和 FALSE 向量,其中 TRUE 表示顶点属于次要组。正如帮助页面所说,我们可以通过简单地将此信息存储在 V(graph)$type
.
中来使我们的 graph
二分。
A3.
如果我们查看 V(proj$proj1)$type
,就像我们在 A1 中所做的那样,我们会看到 proj$proj1
不包含 type
属性。再次不知道它的顶点是主要还是次要组 - 此信息在 运行 bipartite.projection()
时丢失。但这一次没有必要;我们知道它不是二分图,因为它只包含一组。
您可以选择使用 bipartite.projection()
中的 remove.type = F
选项保留此信息。
A4.
二分投影显示哪些 actors
共享相同的 movies
,哪些 movies
共享相同的 actors
。
示例:在您的示例数据中,我们可以看到演员 6 仅与电影 3 相关联。电影 3 也与演员 1 和 5 相关联。二分投影将显示演员 6 仅与演员 1 和演员 5 相关联。
A5.
这里我会设计一个有两个集合(演员和电影)的图表,其中演员有一个额外的属性(男性)来指定他们的性别。
您之前构建图表的方式没有指定这些项目之间的关系。我不知道这种方法,我认为这不是指定图形的正确方法。 igraph manual pages 中提到的创建图形的方法有多种。我将演示一个接近你的方法:
items <- data.frame(
name = c("actorM1","actorM2","actorM3","actorF1","actorF2","actorF3","actorF4","movie1","movie2","movie3"),
movie = c(F,F,F,F,F,F,F,T,T,T),
male = c(T,T,T,F,F,F,F,NA,NA,NA)
)
items
relations <- data.frame(
a = c("actorM1","actorM1","actorM2","actorM3","actorM3","actorM3","actorF1","actorF2","actorF2","actorF3","actorF3","actorF3","actorF4"),
b = c("movie1", "movie2", "movie3", "movie1", "movie2", "movie3", "movie2", "movie2", "movie3", "movie1", "movie2", "movie3", "movie3")
)
relations
graph <- graph_from_data_frame(relations, directed=F, vertices=items)
graph
plot(graph)
上面我创建了两个数据框:
items
包含每个项目的条目(5 个演员和 3 部电影)及其特征(他们是电影,他们是男性),并且
relations
列出了它们的连接方式。
然后我将这两个合并成一个图表 graph_from_data_frame()
。
您会记得下一步:我根据 $movie 的值分配集合。然后我策划电影。先不剧透演员,因为我们还需要分男女。
actors_movies <- bipartite.projection(graph, types = V(graph)$movie, remove.type = F)
plot(actors_movies$proj2)
我找不到比这更好的解决方案来拆分这个组:从投影中删除所有女性以绘制所有男性,然后从投影中删除所有男性以绘制所有女性。请注意,由于 bipartite.projection()
.
中的选项 remove.type = F
,信息 $male
仍然可用
male = delete_vertices(actors_movies$proj1, V(actors_movies$proj1)$male == F)
plot(male)
female = delete_vertices(actors_movies$proj1, V(actors_movies$proj1)$male == T)
plot(female)
希望对您有所帮助。至少我喜欢学习 igraph。
卡斯帕 V. 回答得好!我只有一个评论:
假设我们通过将其中一个演员连接到另一个演员(actor_2 和 actor_3)来“破坏”演员-电影图:
film_data <- data.frame(
"movie" = c("movie_1", "movie_1", "movie_1", "movie_2", "movie_2", "movie_2", "movie_3", "movie_3", "movie_3", "movie_4", "movie_4", "movie_4", "movie_4", "movie_5", "movie_5", "movie_5", "movie_6", "movie_6", "actor_2"),
"actor" = c("actor_1", "actor_2", "actor_3", "actor_2", "actor_3", "actor_4", "actor_1", "actor_5", "actor_6", "actor_2", "actor_7", "actor_1", "actor_8", "actor_5", "actor_9", "actor_3", "actor_2", "actor_8", "actor_3")
)
#create directed graph
graph <- graph.data.frame(film_data, directed=F)
graph <- simplify(graph)
plot(graph)
据我了解,现在这张图不是二分图。
但是,如果我们使用您提供的代码:
V(graph)$type <- V(graph)$name %in% film_data[,1]
is.bipartite(graph)
这 returns 值为“TRUE”。
请问您对此有何看法?这个新修改的图是二分图还是非二分图?
谢谢!
我正在使用 R 编程语言和“igraph”库。我试图更好地理解“双模式”图(有两种节点的图)的图结构。特别是,我试图了解如何“投射”两种模式(据我了解,这些通常是“二分”)图。(https://rpubs.com/pjmurphy/317838)
例如,我创建了一张“男人”和“女人”之间的关系图。虽然这个图有两种模式(男性和女性),但我不认为这个图是二分的(因为“边”可以存在于相同类型的节点之间:
library(igraph)
# I don't think this is a bipartite graph
gender_data <- data.frame(
"men" = c("john", "kevin", "mark", "kevin", "kevin", "mark", "henry", "mark", "susan", "john", "henry", "susan", "susan", "janet", "janet", "henry", "henry", "john"),
"women" = c("janet", "janet", "sarah", "lucy", "lucy", "susan", "janet", "susan", "lucy", "kevin", "lucy", "janet", "kevin", "mark", "lucy", "sarah", "mark", "mark")
)
#create directed graph
graph <- graph.data.frame(gender_data, directed=F)
graph <- simplify(graph)
V(graph)["john"]$color<-"red"
V(graph)["kevin"]$color<-"red"
V(graph)["mark"]$color<-"red"
V(graph)["janet"]$color<-"blue"
V(graph)["sarah"]$color<-"blue"
V(graph)["lucy"]$color<-"blue"
V(graph)["henry"]$color<-"red"
V(graph)["susan"]$color<-"blue"
plot(graph)
我读到,理解二分图的更好方法是通过“演员和电影”。不同的演员可以在同一部电影中,一个演员可以在不同的电影中——但演员不能与自己共享边缘,电影也不能与自己共享边缘。这是我对这样一个网络的解释:
film_data <- data.frame(
"movie" = c("movie_1", "movie_1", "movie_1", "movie_2", "movie_2", "movie_2", "movie_3", "movie_3", "movie_3", "movie_4", "movie_4", "movie_4", "movie_4", "movie_5", "movie_5", "movie_5", "movie_6", "movie_6"),
"actor" = c("actor_1", "actor_2", "actor_3", "actor_2", "actor_3", "actor_4", "actor_1", "actor_5", "actor_6", "actor_2", "actor_7", "actor_1", "actor_8", "actor_5", "actor_9", "actor_3", "actor_2", "actor_8")
)
#create directed graph
graph <- graph.data.frame(film_data, directed=F)
graph <- simplify(graph)
plot(graph)
但是,(根据这里的 Whosebug post:valued bipartite projection using R igraph),这个 actor 图仍然不是二分的(我不明白为什么):
is.bipartite(graph)
[1] FALSE
根据同一个Whosebugpost,actor graph还是可以转换成bipartite graph的(我不明白刚刚发生了什么):
V(graph)$type <- V(graph)$name %in% film_data[,1]
is.bipartite(graph)
[1] TRUE
从这里,可以进行“投射”两个独立图表的投影:
proj<-bipartite.projection(graph, V(graph)$type,multiplicity = TRUE)
proj
$proj1
IGRAPH b5bc5ca UNW- 9 16 --
+ attr: name (v/c), weight (e/n)
+ edges from b5bc5ca (vertex names):
[1] actor_1--actor_2 actor_1--actor_3 actor_1--actor_5 actor_1--actor_6 actor_1--actor_7 actor_1--actor_8 actor_2--actor_3 actor_2--actor_4
[9] actor_2--actor_7 actor_2--actor_8 actor_3--actor_4 actor_3--actor_5 actor_3--actor_9 actor_5--actor_6 actor_5--actor_9 actor_7--actor_8
$proj2
IGRAPH b5bc5ca UNW- 6 11 --
+ attr: name (v/c), weight (e/n)
+ edges from b5bc5ca (vertex names):
[1] movie_1--movie_3 movie_1--movie_4 movie_1--movie_2 movie_1--movie_6 movie_1--movie_5 movie_2--movie_4 movie_2--movie_6 movie_2--movie_5
[9] movie_3--movie_4 movie_3--movie_5 movie_4--movie_6
终于可以绘制两个投影了:
plot(proj$proj1)
plot(proj$proj2)
我的问题:
为什么原来的演员-电影图不是“二分图”?毕竟是无向循环的。
为什么
V(graph)$type <- V(graph)$name %in% film_data[,1]
行将演员-电影图转换为二分图?有什么理由
is.bipartite(proj$proj1) 1错误
is.bipartite(proj$proj2) 1错误
这条线
之间没有这种直接关系proj<-bipartite.projection(graph, V(graph)$type,multiplicity = TRUE)
如何“工作”?在原来的演员-电影图中,我 特意 输入了数据,这样两部电影或两个演员之间就没有直接关系了。例如,在“proj2”中,“movie_1”和“movie_2”之间有一条边——这是怎么发生的,为什么会发生?在我的原始数据中, movie_1 和 movie_2?假设actor_1、actor_2、actor_3、actor_4是男性,actor_5、actor_6、actor_7、actor_8、actor_9为女性。现在有没有办法进行 3 次预测?男演员投影,女演员投影,电影投影?
谢谢
除了你的演员和电影类比之外,我想补充一点,一个演员可以只能连接到 0 或更多部电影,而不能连接到其他演员。而电影只能连接到 0 个或多个演员。现在,对于问题:
A1.
当某个函数的输出与您的预期不符时,查看该函数的帮助页面通常会有所帮助。此命令将解释第一个问题:
?is.bipartite
Bipartite graphs have a type vertex attribute in igraph, this is boolean and FALSE for the vertices of the first kind and TRUE for vertices of the second kind.
[...]
is_bipartite
checks whether the graph is bipartite or not. It just checks whether the graph has a vertex attribute calledtype
.
因此,is_bipartite
不认为原始演员-电影图是二分图,因为该图没有名为 type
的顶点属性。 graph
中根本没有信息告诉它每个顶点属于哪个集合。我们将在下一个问题中添加此信息:
A2.
这里我们将查看您已经找到的示例,我将尝试对其进行解释。我们先再看看帮助页面:
?V
Create a vertex sequence (vs) containing all vertices of a graph. [...]
此函数 V()
从图中创建一系列顶点。 V(graph)
将列出 graph
中的所有顶点。我们希望 V(graph)$type
包含基本属性 type
.
如第一个帮助页面中所述,V(graph)$type 需要为 graph
中的每个顶点包含一个 TRUE/FALSE 值,这就是此代码中所做的:
V(graph)$type <- V(graph)$name %in% film_data[,1]
V(graph)$name
是一个包含所有顶点值的向量。 film_data[,1]
是一个包含所有主顶点(第一组顶点)值的向量。查看这两个R,研究一下他们的内容,你就会明白我的意思了。
最后,%in%
运算符检查左侧的每个项目是否存在于右侧的向量中。如果是,则 return 为真。如果不是,则 return 为 FALSE。在这种情况下,它将 return 一个向量,其中每个次要顶点(例如演员)为 TRUE,对于主要组中的顶点(例如电影)为 FALSE。
完整的构造 V(graph)$name %in% film_data[,1]
因此创建了一个 TRUE 和 FALSE 向量,其中 TRUE 表示顶点属于次要组。正如帮助页面所说,我们可以通过简单地将此信息存储在 V(graph)$type
.
graph
二分。
A3.
如果我们查看 V(proj$proj1)$type
,就像我们在 A1 中所做的那样,我们会看到 proj$proj1
不包含 type
属性。再次不知道它的顶点是主要还是次要组 - 此信息在 运行 bipartite.projection()
时丢失。但这一次没有必要;我们知道它不是二分图,因为它只包含一组。
您可以选择使用 bipartite.projection()
中的 remove.type = F
选项保留此信息。
A4.
二分投影显示哪些 actors
共享相同的 movies
,哪些 movies
共享相同的 actors
。
示例:在您的示例数据中,我们可以看到演员 6 仅与电影 3 相关联。电影 3 也与演员 1 和 5 相关联。二分投影将显示演员 6 仅与演员 1 和演员 5 相关联。
A5.
这里我会设计一个有两个集合(演员和电影)的图表,其中演员有一个额外的属性(男性)来指定他们的性别。
您之前构建图表的方式没有指定这些项目之间的关系。我不知道这种方法,我认为这不是指定图形的正确方法。 igraph manual pages 中提到的创建图形的方法有多种。我将演示一个接近你的方法:
items <- data.frame(
name = c("actorM1","actorM2","actorM3","actorF1","actorF2","actorF3","actorF4","movie1","movie2","movie3"),
movie = c(F,F,F,F,F,F,F,T,T,T),
male = c(T,T,T,F,F,F,F,NA,NA,NA)
)
items
relations <- data.frame(
a = c("actorM1","actorM1","actorM2","actorM3","actorM3","actorM3","actorF1","actorF2","actorF2","actorF3","actorF3","actorF3","actorF4"),
b = c("movie1", "movie2", "movie3", "movie1", "movie2", "movie3", "movie2", "movie2", "movie3", "movie1", "movie2", "movie3", "movie3")
)
relations
graph <- graph_from_data_frame(relations, directed=F, vertices=items)
graph
plot(graph)
上面我创建了两个数据框:
items
包含每个项目的条目(5 个演员和 3 部电影)及其特征(他们是电影,他们是男性),并且relations
列出了它们的连接方式。
然后我将这两个合并成一个图表 graph_from_data_frame()
。
您会记得下一步:我根据 $movie 的值分配集合。然后我策划电影。先不剧透演员,因为我们还需要分男女。
actors_movies <- bipartite.projection(graph, types = V(graph)$movie, remove.type = F)
plot(actors_movies$proj2)
我找不到比这更好的解决方案来拆分这个组:从投影中删除所有女性以绘制所有男性,然后从投影中删除所有男性以绘制所有女性。请注意,由于 bipartite.projection()
.
remove.type = F
,信息 $male
仍然可用
male = delete_vertices(actors_movies$proj1, V(actors_movies$proj1)$male == F)
plot(male)
female = delete_vertices(actors_movies$proj1, V(actors_movies$proj1)$male == T)
plot(female)
希望对您有所帮助。至少我喜欢学习 igraph。
卡斯帕 V. 回答得好!我只有一个评论:
假设我们通过将其中一个演员连接到另一个演员(actor_2 和 actor_3)来“破坏”演员-电影图:
film_data <- data.frame(
"movie" = c("movie_1", "movie_1", "movie_1", "movie_2", "movie_2", "movie_2", "movie_3", "movie_3", "movie_3", "movie_4", "movie_4", "movie_4", "movie_4", "movie_5", "movie_5", "movie_5", "movie_6", "movie_6", "actor_2"),
"actor" = c("actor_1", "actor_2", "actor_3", "actor_2", "actor_3", "actor_4", "actor_1", "actor_5", "actor_6", "actor_2", "actor_7", "actor_1", "actor_8", "actor_5", "actor_9", "actor_3", "actor_2", "actor_8", "actor_3")
)
#create directed graph
graph <- graph.data.frame(film_data, directed=F)
graph <- simplify(graph)
plot(graph)
据我了解,现在这张图不是二分图。
但是,如果我们使用您提供的代码:
V(graph)$type <- V(graph)$name %in% film_data[,1]
is.bipartite(graph)
这 returns 值为“TRUE”。
请问您对此有何看法?这个新修改的图是二分图还是非二分图?
谢谢!