Welcome to R Square

用 R 创建网络图

楚新元 / 2019-12-04


用网络图来形象的展示人与人之间的交往密切程度或者全球进出口贸易比较直观。下面笔者将做一些尝试用 R 创建网络图。

无向网路图

library(igraph)
set.seed(123)
g1 = graph(
  edges = c(1, 2, 2, 3, 2, 4, 1, 4, 5, 5, 3, 6), 
  directed = FALSE
)
print(g1)
#> IGRAPH 77c5f38 U--- 6 6 -- 
#> + edges from 77c5f38:
#> [1] 1--2 2--3 2--4 1--4 5--5 3--6
plot(g1)

有向网络图

set.seed(123)
g2 = graph(
  edges = c(1, 2, 2, 3, 2, 4, 1, 4, 5, 5, 3, 6), 
  directed = TRUE
)
print(g2)
#> IGRAPH 7fe2f50 D--- 6 6 -- 
#> + edges from 7fe2f50:
#> [1] 1->2 2->3 2->4 1->4 5->5 3->6
plot(g2)

以上两图基本反映了网络图的基本原理,但是没有考虑到他们之间的权重,试想一下,如果存在以下贸易关系:

那么该如何作图呢?一个朴素的思想是让 1, 2 出现 3 次,2, 3 出现 2 次,……,下面我们验证这个思路是否可行?

加权有向网络图尝试

set.seed(123)
g3_w = graph(
  c(
    1, 2, 1, 2, 1, 2, 
    2, 3, 2, 3, 
    2, 4, 
    1, 4, 
    3, 6
  ),
  directed = TRUE
)
print(g3_w)
#> IGRAPH 7481426 D--- 6 8 -- 
#> + edges from 7481426:
#> [1] 1->2 1->2 1->2 2->3 2->3 2->4 1->4 3->6
plot(g3_w)

呵呵,确实可行!很明显国家(地区)2 在整个网络中处于核心地位。但是这种画法在实践中需要对原始数据根据贸易额进行加工,十分不方便。

通过参数设置权重

set.seed(123)
df = data.frame(
  p1 = c(1, 2, 2, 1, 3), 
  p2 = c(2, 3, 4, 4, 6), 
  wt = c(3, 2, 1, 1, 1)
)
gdf = graph_from_data_frame(
  df, directed = TRUE
)
print(gdf)
#> IGRAPH 21f2010 DN-- 5 5 -- 
#> + attr: name (v/c), wt (e/n)
#> + edges from 21f2010 (vertex names):
#> [1] 1->2 2->3 2->4 1->4 3->6
plot(gdf, edge.width=E(gdf)$wt)

加入权重参数(wt)的好处是,我们不需要对原数据进行改造,十分方便。图中连线粗细程度反映权重大小。因此,我们只需要出口国、进口国和出口额三个变量组成数据框就可以很容易用 R 生成贸易关系网络图。

真实贸易数据实战

# 加载相关 R 包
library(openxlsx)
library(dplyr)
library(igraph)

# 读取数据(数据来源:联合国商品贸易统计数据库)
data = read.xlsx("./data/trade2017.xlsx") 
set.seed(1234) # 设置随机数种子
data |> 
  filter(
    Trade.Flow == "Export",  # 此处只选择出口数据
    `Trade.Value.(US$)` >= 1000000000  # 此处剔除小于 10 亿美元的记录
  ) |>  
  select(Reporter, Partner, `Trade.Value.(US$)`) |> 
  rename(
    p1 = Reporter,
    p2 = Partner,
    value = `Trade.Value.(US$)`
  ) |> 
  graph.data.frame(directed = TRUE) %>%
  plot(
    edge.width = E(.)$value / 10000000000, 
    vertex.size = 3, 
    vertex.color = "red", 
    vertex.label.dist = 0.6, 
    edge.arrow.size = 0.1
  )

注:1.此处只选择出口数据是因为 A 国出口到 B 国,相当于 B 国从 A 国进口,因此只需要保留进口或者出口即可;2.如果显示所有信息,不利于发现关键信息,因此剔除出口额中小于一定金额的记录(行)。