图与网络分析—R实现(一)
图与网络
一个网络G,也可以称为图(graph)或网络图,是一种包含了节点V(即网络参与者,也称顶点)与边E(即节点之间的连接关系)的数学结构,记作G={V,E}。可以使用一个矩阵来存放节点之间的连接关系,这个矩阵称为邻接矩阵。如果网络中两个节点之间的边是有方向的,即从节点u出发指向节点v,这就是一个有向网络(有向图),否则称为无向网络(无向图)。网络的边也可以赋予权重,称为加权网络。
一、R的igraph包
igraph包是一个用来解决图与网络问题以及对其进行可视化的包。igraph是一个“历史悠久”的开源项目,提供了一组简单易用且功能强大的网络分析工具,igraph有多种语言接口,包括了R\Python\C++等等。尽管(无论在R还是Python中)已经有了更多的网络分析和可视化工具,igraph依然是最好的出发点。
igraph包中创建图的对象的函数是
make_graph(edges, ..., n = max(edges), isolates = NULL,directed = TRUE,dir = directed, simplify = TRUE)
1.其中edges参数为边组成的向量,这个向量中的元素既可以是数字也可以是字符,也可以是literals参数(但不经常用)。比如如果是数字,c(1,2)表示一条从点1到点2的边,c(1,2,2,3)表示两条边,一条从1到2,另一条从2到3,注意图中的点的编号不能用0来命名,否则会报错,至于原因就不太清楚啦;字母的原理与数字相同
2.n为最大边数,只在edges参数中的元素是数字的时候有用,但我还是不太清楚这个参数的实质作用是什么,好像一般情况下用不到。
3.isolates为孤立的点组成的向量,但只有在edges参数中的元素是字符时才有用,比如make_graph(c('a','b','b','c'),isolates = c('d','e'))这个图有两条边ab,bc,还有两个孤立的点d和e.
4.directed为一个布尔型参数,TRUE表示有向图,FALSE表示无向图,dir参数与directed参数是一样的,但两者不能同时出现。
5.simplify参数只有在edges参数使用literals时才有用。
make_graph(edges, ..., n = max(edges), isolates = NULL,directed = TRUE,dir = directed, simplify = TRUE)
1其中edges参数为边组成的向量,这个向量中的元素既可以是数字也可以是字符,也可以是literals参数(但不经常用)。比如如果是数字,c(1,2)表示一条从点1到点2的边,c(1,2,2,3)表示两条边,一条从1到2,另一条从2到3,注意图中的点的编号不能用0来命名,否则会报错,至于原因就不太清楚啦;字母的原理与数字相同
2.n为最大边数,只在edges参数中的元素是数字的时候有用,但我还是不太清楚这个参数的实质作用是什么,好像一般情况下用不到。
3.isolates为孤立的点组成的向量,但只有在edges参数中的元素是字符时才有用,比如make_graph(c('a','b','b','c'),isolates = c('d','e'))这个图有两条边ab,bc,还有两个孤立的点d和e.
4.directed为一个布尔型参数,TRUE表示有向图,FALSE表示无向图,dir参数与directed参数是一样的,但两者不能同时出现。
5.simplify参数只有在edges参数使用literals时才有用。
二、图的数据结构
图是一组顶点:通常用V(Vertex)表示顶点集合;一组边:通常用E (Edge) 表示边的集合,边是顶点对:如(v, k) ∈E ,其中v, k ∈ V;有向图的边表示从v指向k的边(单行线),无向图的边是无向边(v, k)(双向线);边的权:通常用W(Weight)表示权的集合,这三个集合构成的三元有序组就表示一个赋权图。简单图一般不考虑多重边和自回路,如下图所示。
library("igraph")
m <- matrix( c(1,2,6, 1,3,5, 1,4,4, 1,6,4, 3,6,4, 3,7,3, 4,7,3, 5,8,5, 6,8,4, 7,8,6) ,ncol = 3,byrow = T)
#创建一个无向图
g <- make_graph(t(m[,1:2]),directed = FALSE)
#创建一个有向图
h <- make_graph(t(m[,1:2]),directed = TRUE)
graph_attr(g,'weight') <- m[,3] #加载权重
graph_attr(h,'weight') <- m[,3] #加载权重
E(g)$weight=m[,3]
E(h)$weight=m[,3]
#也可以用第一个函数获得图的权
graph_attr(g,'weight') #得到g的权
plot(g,edge.label = graph_attr(g,'weight')) #图1
plot(h,edge.label = graph_attr(h,'weight')) #图2


连通:如果从v到k存在一条(无向)路径,则称v和k是连通的。连通图(Connected Graph):如果对于图的任一两个顶点v、k∈V,v和k都是连通的,则称该图为连通图。连通是图最重要的性质,表面我们所研究的对象图是一个有机整体。
2.1 图的邻接矩阵
邻接矩阵(Adjacency Matrix)是表示顶点之间相邻关系的矩阵。设任意图,其中顶点集,边集 ,称矩阵 为图G的邻接矩阵,其中
G的邻接矩阵是一个的阶方阵:
①对无向图而言,邻接矩阵一定是对称的,而且主对角线一定为零(在此仅讨论无向简单图),副对角线不一定为0,有向图则不一定如此。
②无向图的邻接矩阵一定是对称的,而有向图的邻接矩阵不一定对称。
无向网络的邻接矩阵(对称阵)
若节点和节点之间存在连接,则令矩阵中第行第列上的元素;若节点和节点之间不存在连接,则令矩阵元素。
有向矩阵的邻接矩阵(非对称阵)
若节点和节点之间存在有向连接,则令矩阵元素;若节点和节点之间不存在有向连接,则令矩阵元素。
图1的邻接矩阵为
get.adjacency(g)
[1,] . 1 1 1 . . . .
[2,] 1 . . . . 1 . .
[3,] 1 . . . . 1 1 .
[4,] 1 . . . . . 1 .
[5,] . . . . . . . 1
[6,] . 1 1 . . . . 1
[7,] . . 1 1 . . . 1
[8,] . . . . 1 1 1 .
图2的邻接矩阵为(!!!有向边默认以行为起点)
get.adjacency(h)
[1,] . 1 1 1 . . . .
[2,] . . . . . 1 . .
[3,] . . . . . 1 1 .
[4,] . . . . . . 1 .
[5,] . . . . . . . 1
[6,] . . . . . . . 1
[7,] . . . . . . . 1
[8,] . . . . . . . .
2.2 赋权图的加权邻接矩阵(Labeled Adjacency Matrix)
加权邻接矩阵是把图的顶点视为一个矩阵,其中的数字代表着顶点之间的权重。对于赋权图,其边的权重为,构造矩阵,其中
若节点 和节点之间存在连接,则令矩阵中第行第列上的元素;若节点和节点之间不存在连接,则令矩阵元素。可见,网络的邻接矩阵是加权网络的特例,是权重值只有1和0两个取值的加权邻接矩阵。
A | B | C | D | E | |
---|---|---|---|---|---|
A | 0 | 2 | 0 | 0 | 2 |
B | 0 | 0 | 4 | 4 | 0 |
C | 0 | 0 | 0 | 6 | 0 |
D | 0 | 0 | 0 | 0 | 8 |
E | 0 | 10 | 0 | 0 | 0 |
图1的加权邻接矩阵
get.adjacency(g,attr = "weight",sparse = T)
[1,] . 6 5 4 . . . .
[2,] 6 . . . . 4 . .
[3,] 5 . . . . 4 3 .
[4,] 4 . . . . . 3 .
[5,] . . . . . . . 5
[6,] . 4 4 . . . . 4
[7,] . . 3 3 . . . 6
[8,] . . . . 5 4 6 .
加权邻接矩阵是一种用来表示网络节点之间的连接结构,以及不同用户的相似度的矩阵,它的作用不容小觑。在图论领域,加权邻接矩阵可以用来描述图的拓朴结构,也可以用来解决最短路径问题,在人工智能领域、金融工程领域甚至许多应用领域中还有十分广泛的应用。
2.3 图的边缘列表(Edge List)
边缘列表,也称边列表,图的储存结构之一。边缘列表(EL),是具有连接顶点及其权重的边的集合,因此其空间开销为E(边的数量)。
边索引 | from | to |
---|---|---|
0 | 0 | 1 |
1 | 0 | 2 |
2 | 1 | 2 |
3 | 1 | 3 |
4 | 2 | 4 |
5 | 3 | 4 |
6 | 4 | 5 |
7 | 5 | 6 |
在上图中,共有8条边,因此列表的长度为8,在数据表示中,因为是无权重图,所以权重值并未体现出来,如顶点0,与顶点1和顶点2相连,可以看到EL[0]=(0,1) ,EL[1]=(0, 2)。为了提高查询的效率,我们已经对上方的数组使用排序函数先按照起点排序,再按照终点排序,这样完成后,相同的起点的边就是挨在一起的,相同起点的终点也是有顺序的,查询起来相对会快一些。
图1的边列表
get.data.frame(g)
from to
1 1 2
2 1 3
3 1 4
4 2 6
5 3 6
6 3 7
7 4 7
8 5 8
9 6 8
10 7 8
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!