【问题标题】:R: Understanding GraphR:理解图
【发布时间】:2020-12-10 22:24:07
【问题描述】:

我正在使用 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)

但是,(根据此处的此 stackoverflow 帖子:valued bipartite projection using R igraph),此演员图仍然不是二分的(我不明白为什么):

is.bipartite(graph)
[1] FALSE

根据同样的stackoverflow帖子,actor图仍然可以转换为二分图(我不明白刚刚发生了什么):

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)

我的问题:

  1. 为什么原来的演员-电影图表不是“二分”的?毕竟,它是无向和循环的。

  2. 为什么V(graph)$type &lt;- V(graph)$name %in% film_data[,1] 线会将演员-电影图转换为二分图?

  3. 有什么原因

    is.bipartite(proj$proj1) 1 错误

    is.bipartite(proj$proj2) 1 错误

  4. 这条线proj&lt;-bipartite.projection(graph, V(graph)$type,multiplicity = TRUE)如何“工作”?在原始演员-电影图中,我专门输入了数据,这样两部电影或两个演员之间就没有直接关系。例如,在“proj2”中,“movie_1”和“movie_2”之间有一条边——这是怎么发生的,为什么会这样?在我的原始数据中,movie_1和movie_2之间没有这种直接关系?

  5. 假设 actor_1、actor_2、actor_3、actor_4 是男性,actor_5、actor_6、actor_7、actor_8、actor_9 是女性。现在有没有办法进行3个预测?男演员投影,女演员投影,电影投影?

谢谢

【问题讨论】:

    标签: r graph data-visualization nodes


    【解决方案1】:

    除了你的演员和电影类比之外,我想补充一点,演员只能连接到 0 部电影或更多电影,而不能连接到其他演员。电影只能连接到 0 个或多个演员。现在,对于问题:

    A1.

    当某个函数的输出与您的期望不符时,查看该函数的帮助页面通常会有所帮助。该命令将解释第一个问题:

    ?is.bipartite
    

    二分图在 igraph 中有一个 type vertex 属性,对于第一种顶点是布尔值和 FALSE,对于第二种顶点是 TRUE。

    [...]

    is_bipartite 检查图是否为二分图。它只是检查图形是否具有名为type 的顶点属性。

    因此,is_bipartite 不认为原始演员-电影图是二分图,因为该图没有称为 type 的顶点属性。 graph 中根本没有任何信息告诉它每个顶点属于哪个集合。我们将在下一个问题中添加此信息:

    A2.

    在这里,我们将查看您已经找到的示例,我将尝试对其进行解释。让我们先再次查看帮助页面:

    ?V

    创建一个包含图的所有顶点的顶点序列(vs)。 [...]

    这个函数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% 运算符检查左侧的每个项目是否存在于右侧的向量中。如果是,则返回 TRUE。如果不是,则返回 FALSE。在这种情况下,它将为每个次要顶点(例如演员)返回一个为 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。

    【讨论】:

    • 非常感谢您的回答!我看了你的回答好几遍,学到了很多!
    • 关于 A3,我试过: proj
    • 关于A4:你的解释很完美,非常感谢......我想我终于明白了投影在这种情况下的含义
    • 嗨,Caspar V.!我发表了与您的答案相关的评论,您有时间可以看一下吗?谢谢!
    【解决方案2】:

    很好的答案卡斯帕五世!我只有一条评论:

    假设我们通过将一个演员连接到另一个演员(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)
    

    这将返回“TRUE”值。

    您能否就此发表意见?这个新的修正图是二分的还是不是二分的?

    谢谢!

    【讨论】:

    • 很好的旁注。实际上,您创建的图不是二分图:“演员”部分具有相邻的顶点。函数is.bipartite()(或其名称)具有高度误导性。它只告诉您图形是否具有称为type 的所需顶点属性。它不检查构成图二分的其他特征。
    猜你喜欢
    • 1970-01-01
    • 2021-03-10
    • 1970-01-01
    • 2015-12-04
    • 2015-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多