前情回顾:
Gephi网络图极简教程
Network在单细胞转录组数据分析中的应用
网络数据统计分析笔记|| 为什么研究网络
书接上回,我们来看看如何构建网络以及可以对网络做的基本操作,主要用的R包是igraph。
- 创建网络图
- 图的表示
- 图的增删
- 图的修饰
- 图的属性
igraph是一个用于创建和操作图以及分析网络的R包。它是用C编写的,也以Python和R包的形式存在。此外,还存在一个Mathematica接口。该软件广泛应用于网络科学及相关领域的学术研究。据谷歌Scholar统计,截止2015年6月5日,介绍该软件的出版物有5623次引用。
创建网络图
网络用节点描述元素,用连线描述元素间关系。一个图是包含节点集合与边集合的数学结构。其中节点数称为图的阶数(order),边的数量称为图的规模(size)。
在创建图之前我们来认识一下igraph包。
# install.packages("pacman")
rm(list = ls())
library(sand)
# CHUNK 1
library(igraph)
library(pacman)
length(p_functions(igraph))
[1] 784
grep('graph_from',p_functions(igraph),value = T)
[1] "graph_from_adj_list" "graph_from_adjacency_matrix" "graph_from_atlas"
[4] "graph_from_data_frame" "graph_from_edgelist" "graph_from_graphdb"
[7] "graph_from_graphnel" "graph_from_incidence_matrix" "graph_from_isomorphism_class"
[10] "graph_from_lcf" "graph_from_literal"
可以看到igraph 共有 784个函数,其中读入数据的有11个,功能可谓是全的很啊。我们先从最简单的做起,构建一个手写的图:
g <- graph_from_literal(1-2, 1-3, 2-3, 2-4, 3-5, 4-5,
4-6, 4-7, 5-6, 6-7)
plot(g)
查看图的属性
V(g)
+ 7/7 vertices, named, from e2c1098:
[1] 1 2 3 4 5 6 7
E(g)
+ 10/10 edges from e2c1098 (vertex names):
[1] 1--2 1--3 2--3 2--4 3--5 4--5 4--6 4--7 5--6 6--7
print_all(g)
IGRAPH e2c1098 UN-- 7 10 --
+ attr: name (v/c)
+ edges (vertex names):
1 -- 2, 3
2 -- 1, 3, 4
3 -- 1, 2, 5
4 -- 2, 5, 6, 7
5 -- 3, 4, 6
6 -- 4, 5, 7
7 -- 4, 6
在g的结构描述中,字母U表示该图是无向的(undirected),即一条边的两个节点没方向和次序。简单有向图可以这样构建:
dg <- graph_from_literal(1-+2, 1-+3, 2++3)
plot(dg)
要想使图有意义,我们就需要给图起名字:
par(mfrow=c(1,3))
dg <- graph_from_literal(1-+2, 1-+3, 2++3)
plot(dg)
dg <- graph_from_literal(Sam-+Mary, Sam-+Tom,
+ Mary++Tom)
print_all(dg)
IGRAPH ea00245 DN-- 3 4 -- # UN 变成DN
+ attr: name (v/c)
+ edges from ea00245 (vertex names):
[1] Sam ->Mary Sam ->Tom Mary->Tom Tom ->Mary
plot(dg)
V(dg)$name <- c("Sam1", "Mary1", "Tom_1")
E(dg)
+ 4/4 edges from ea00245 (vertex names):
[1] Sam1 ->Mary1 Sam1 ->Tom_1 Mary1->Tom_1 Tom_1->Mary1
> # ---
> ## + 4/4 edges from 062bf79 (vertex names):
> ## [1] Sam ->Mary Sam ->Tom Mary->Tom Tom ->Mary
> # ---
plot(dg)
我们无法想象手动用+-
号来构建一个成千上百的网络图,一般的图都是在数据文件里,存在三种表示图的格式:
- 邻接列表
- 边列表
- 邻接矩阵
邻接表(graph_adjacency_list):邻接表是图的一种链式存储结构。在邻接表中,对图中每一个顶点建立一个单链表,第i个单链表中的节点表示依附于顶点vi的边(对有向图是以顶点vi为尾的弧)。每一个结点有三个域组成,当中邻接点域指示与顶点vi邻接的点在途中的位置,链域指示下一条边或者弧的结点;数据域存储和边或者弧相关的信息。如权值等。每一个链表上附设一个表头结点。
边列表简单来说就是边跟边的两个顶点。
E(dg)
+ 4/4 edges from ea00245 (vertex names):
[1] Sam1 ->Mary1 Sam1 ->Tom_1 Mary1->Tom_1 Tom_1->Mary1
图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息。
设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为:
as_adjacency_matrix(dg)
3 x 3 sparse Matrix of class "dgCMatrix"
Sam1 Mary1 Tom_1
Sam1 . 1 1
Mary1 . . 1
Tom_1 . 1 .
三者之间的对应 关系可以用下图表示:
鉴于矩阵是多数编程语言的基本数据对象,邻接矩阵经常作为网络图的存储方式。但是如果是大型的网络,如果不转化为稀疏矩阵,一般的矩阵会非常低效。在文章的开头我们展示了几个其他数据读入igraph的函数,以生成对应的网络。read_graph函数能够从文件或http连接读取各种表示形式的图形。
igraph绘制的网络图导入到gephi
install and load
install.packages("rgexf", dependencies=TRUE)
library(rgexf)
cg1 <- erdos.renyi.game(10, 0.8)
nodes <- data.frame(cbind(V(cg1), as.character(V(cg1))))
edges <- t(Vectorize(get.edge, vectorize.args='id')(cg1, 1:ecount(cg1)))
write.gexf(nodes, edges)
图的表示
刚生成或者导入的图可能不是我们需要的图,对图的各种操作不可或缺,包括取子图、删节点,增加边,甚至是合并图。在一张图上有了感兴趣的区域,我们一般会采取取子图的操作,子图的定义是某图的边和点均来自母图。如取g前5个节点的子图:
h <- induced_subgraph(g, 1:5)
print_all(h)
IGRAPH ae29f26 UN-- 5 6 --
+ attr: name (v/c)
+ edges from ae29f26 (vertex names):
[1] 1--2 1--3 2--3 2--4 3--5 4--5
plot(h)
图中节点和边的纳入与删除,可以通过对集合和使用加号或减号操作符实现。上面的图可以:
h <- g - vertices(c(6,7))
print_all(h)
plot(h)
相似地,g也可以由h生成:
h <- h + vertices(c(6,7))
g <- h + edges(c(4,6),c(4,7),c(5,6),c(6,7))
print_all(g)
IGRAPH 77655ae UN-- 7 10 --
+ attr: name (v/c)
+ edges (vertex names):
1 -- 2, 3
2 -- 1, 3, 4
3 -- 1, 2, 5
4 -- 2, 5, 6, 7
5 -- 3, 4, 6
6 -- 4, 5, 7
7 -- 4, 6
plot(g)
图的并,交,差,补。
图的并集
h1 <- h
h2 <- graph_from_literal(4-6, 4-7, 5-6, 6-7)
g <- graph.union(h1,h2)
print_all(g)
IGRAPH 1cc06a7 UN-- 7 10 --
+ attr: name (v/c)
+ edges (vertex names):
1 -- 2, 3
2 -- 1, 3, 4
3 -- 1, 2, 5
4 -- 2, 5, 6, 7
5 -- 3, 4, 6
6 -- 4, 5, 7
7 -- 4, 6
plot(g)
网络图的修饰
一幅图(graph,network)要有实际的意义,就要有与相应的网络图所关联的值。将一个图与这些属性(attributes)关联在一起的过程称为图的修饰(decorating)。在igraph中节点和边的属性可以通过$
符号获得和修改。
V(dg)$name
[1] "Sam" "Mary" "Tom"
V(dg)$gender <- c("M","F","M")
V(g)$color <- c("red","blue")
plot(g)
也可以将某些计算的节点特征值用这种方式保存,并用于可视化化或者统计。
同样地,边的属性用于描述元素之间的关系,如强弱,正负等。边的属性在在许多分析中可以认为是权重,有权重的图称为含权图(weighted graph)。
is_weighted(g)
[1] FALSE
wg <- g
E(wg)$weight <- runif(ecount(wg))
is_weighted(wg)
[1] TRUE
plot(wg)
其实图本身也可以有属性,如:
g$name <- "Toy Graph"
使用数据框
大型的网络图不可能手动输入,而是采用数据框来存储和读入。igraph的节点和边属性可以存在节点和边文件的数据框中。
library(sand)
head(elist.lazega)
V1 V2
1 V1 V17
2 V2 V7
3 V2 V16
4 V2 V17
5 V2 V22
6 V2 V26
head(v.attr.lazega)
Name Seniority Status Gender Office Years Age Practice School
1 V1 1 1 1 1 31 64 1 1
2 V2 2 1 1 1 32 62 2 1
3 V3 3 1 1 2 13 67 1 1
4 V4 4 1 1 1 31 59 2 3
5 V5 5 1 1 2 31 59 1 2
6 V6 6 1 1 2 29 55 1 1
> g.lazega <- graph_from_data_frame(elist.lazega,
+ directed="FALSE",
+ vertices=v.attr.lazega)
> g.lazega$name <- "Lazega Lawyers"
> # CHUNK 21
> vcount(g.lazega)
[1] 36
> # CHUNK 22
> ecount(g.lazega)
[1] 115
> # CHUNK 23
> vertex_attr_names(g.lazega)
[1] "name" "Seniority" "Status" "Gender" "Office" "Years" "Age" "Practice" "School"
> # ---
> ## [1] "name" "Seniority" "Status" "Gender"
> ## [5] "Office" "Years" "Age" "Practice"
> ## [9] "School"
> # ---
> plot(g.lazega)
V(g.lazega)$color = V(g.lazega)$Seniority
plot(g.lazega)
关于图
简单图:在无向图中,关联一对顶点的无向边如果多于1条,则称这些边为平行边,平行边的条数称为重数。在有向图中,关联一对顶点的有向边如果多于1条,并且这些边的始点与终点相同(也就是它们的的方向相同),称这些边为平行边。含平行边的图称为多重图,既不含平行边也不包含自环的图称为简单图。
is_simple(g)
[1] TRUE
构建多重图
mg <- g + edge(2,3)
is_simple(mg)
[1] FALSE
print_all(mg)
plot(mg)
在网络数据分析中,常需要将多重图转化为加权的简单图:
E(mg)$weight <- 1
# plot(mg)
# ?simplify
wg2 <- igraph::simplify(mg)
is_simple(wg2)
[1] TRUE
print_all(wg2)
IGRAPH c219b27 UNW- 7 10 --
+ attr: name (v/c), color (v/c), weight (e/n)
+ edges (vertex names):
1 -- 2, 3
2 -- 1, 3, 4
3 -- 1, 2, 5
4 -- 2, 5, 6, 7
5 -- 3, 4, 6
6 -- 4, 5, 7
7 -- 4, 6
E(wg2)$weight
[1] 1 1 2 1 1 1 1 1 1 1
plot(wg2)
图的连通性,如果两个节点之间通过一条边链接,我们称两者是邻接的(adjacent),这些节点可以称为邻居(neighbors)。
neighbors(g,5)
+ 3/7 vertices, named, from 1cc06a7:
[1] 3 4 6
类似地,两条边通过一个节点相连,称两者是邻接的。节点的度(degree)定义为其关联的边的数量。
degree(g)
1 2 3 4 5 6 7
2 3 3 4 3 3 2
如果是有向图,节点度可以进一步分为入度(in-degree)与出度(out-degree)分别代表指向与离开节点边的数量。
degree(dg, mode="in")
Sam Mary Tom
0 2 2
degree(dg, mode="out")
Sam Mary Tom
2 1 1
描述图移动的概念:
通路(walk)是一个节点和边交替的序列
通路的长度length
不存在重复边的通路为迹(trail)
不存在重复节点的通路为路径(path)
起点和终点相同的迹为回路(circuit)
如果图中存在节点到另一个节点的一条通路,则可称节点到是可达的(reachable),若所有节点从任意节点均可达,则称图是连通的(connected)。图的组件(component)是一个最大化的连通子图。
is_connected(g)
[1] TRUE
clusters(g)
$membership
1 2 3 4 5 6 7
1 1 1 1 1 1 1
$csize
[1] 7
$no
[1] 1
对于有向图,有弱连通和强连通之别:
is_connected(dg,mode="weak")
[1] TRUE
is_connected(dg,mode="strong")
[1] FALSE
图中节点的距离(distance),被定义为节点间最短路径长度。图中最长的距离的值称为直径(diameter)
diameter(g, weights=NA)
[1] 3
特殊类型的图
g.full <- make_full_graph(7)
g.ring <- make_ring(7)
g.tree <- make_tree(7, children=2, mode="undirected")
g.star <- make_star(7, mode="undirected")
par(mfrow=c(2, 2), mai = c(0.2, 0.2, 0.2, 0.2))
plot(g.full,main='compele graph')
plot(g.ring,main= 'regular graph')
plot(g.tree,main='tree')
plot(g.star,main='star')
一个无环的有向图称做有向无环图(directed acycline praph)。简称DAG 图。DAG 图是一类较有向树更一般的特殊有向图。
is_dag(dg)
[1] FALSE
二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
g.bip <- graph_from_literal(actor1:actor2:actor3,
movie1:movie2, actor1:actor2 - movie1,
actor2:actor3 - movie2)
V(g.bip)$type <- grepl("^movie", V(g.bip)$name)
print_all(g.bip, v=T)
IGRAPH f306940 UN-B 5 4 --
+ attr: name (v/c), type (v/l)
+ vertex attributes:
| name type
| [1] actor1 FALSE
| [2] actor2 FALSE
| [3] actor3 FALSE
| [4] movie1 TRUE
| [5] movie2 TRUE
+ edges from f306940 (vertex names):
[1] actor1--movie1 actor2--movie1 actor2--movie2 actor3--movie2
图的投影
proj <- bipartite_projection(g.bip)
print_all(proj[[1]])
IGRAPH 9a82b4d UNW- 3 2 --
+ attr: name (v/c), weight (e/n)
+ edges from 9a82b4d (vertex names):
[1] actor1--actor2 actor2--actor3
print_all(proj[[2]])
IGRAPH 9a82b4d UNW- 2 1 --
+ attr: name (v/c), weight (e/n)
+ edge from 9a82b4d (vertex names):
[1] movie1--movie2
par(mfrow=c(1, 3), mai = c(0.2, 0.2, 0.2, 0.2))
plot(g.bip)
plot(proj[[1]])
plot(proj[[2]])
https://igraph.org/r/
存储在图的形式——邻接列表
https://visualgo.net/zh/graphds
https://gk.palem.in/iGraphExport.html
https://www.cnblogs.com/alan-blog-TsingHua/p/10924894.html
网友评论