Package visNetwork

Chào các bạn, hôm nay Nhi xin giới thiệu với các bạn package visNetwork trong R. Công dụng của package này là vẽ những network tương tác, tức là sơ đồ network của bạn có tính “động” và người đọc có thể tác động lên nó như chơi với một chùm bong bóng.

Minh họa

Trong thí dụ minh họa này, Nhi sẽ vẽ network cho một vấn đề đơn giản nhất,đó là phân tích tương quan giữa 13 biến số và 1 biến số đích.

Những packages sẽ được dùng trong thí dụ này:

library(tidyverse)
## Loading tidyverse: ggplot2
## Loading tidyverse: tibble
## Loading tidyverse: tidyr
## Loading tidyverse: readr
## Loading tidyverse: purrr
## Loading tidyverse: dplyr
## Conflicts with tidy packages ----------------------------------------------
## filter(): dplyr, stats
## lag():    dplyr, stats
library(igraph)
## 
## Attaching package: 'igraph'
## The following objects are masked from 'package:dplyr':
## 
##     as_data_frame, groups, union
## The following objects are masked from 'package:purrr':
## 
##     compose, simplify
## The following object is masked from 'package:tidyr':
## 
##     crossing
## The following object is masked from 'package:tibble':
## 
##     as_data_frame
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## The following object is masked from 'package:base':
## 
##     union
library(RColorBrewer)
library(visNetwork)

Bước 1: Tải dữ liệu và Tạo ma trận tương quan

Đầu tiên Nhi tải dữ liệu và dọn dẹp nó 1 chút

df=read.table("https://ww2.amstat.org/publications/jse/datasets/fat.dat.txt")

df= df[,c(2, 5:7, 10:19)]

names(df)=c("brozek_fat","age","weight","height","neck","chest","abdomen","hip","thigh","knee","ankle","biceps","forearm","wrist")
df= df[-42,] #wrong value ?

head(df)
##   brozek_fat age weight height neck chest abdomen   hip thigh knee ankle
## 1       12.6  23 154.25  67.75 36.2  93.1    85.2  94.5  59.0 37.3  21.9
## 2        6.9  22 173.25  72.25 38.5  93.6    83.0  98.7  58.7 37.3  23.4
## 3       24.6  22 154.00  66.25 34.0  95.8    87.9  99.2  59.6 38.9  24.0
## 4       10.9  26 184.75  72.25 37.4 101.8    86.4 101.2  60.1 37.3  22.8
## 5       27.8  24 184.25  71.25 34.4  97.3   100.0 101.9  63.2 42.2  24.0
## 6       20.6  24 210.25  74.75 39.0 104.5    94.4 107.8  66.0 42.0  25.6
##   biceps forearm wrist
## 1   32.0    27.4  17.1
## 2   30.5    28.9  18.2
## 3   28.8    25.2  16.6
## 4   32.4    29.4  18.2
## 5   32.2    27.7  17.7
## 6   35.7    30.6  18.8

Sau đó Nhi chuyển data thành matrix rồi dùng hàm scale() để chuẩn hóa nó.

dfscale=df%>%as.matrix()%>%scale()

m=as.matrix(cor(dfscale))

Chúng ta đã tạo ra 1 correlation matrix m

Chuyển matrix tương quan thành graph

Nhắc lại một chút về graph và network: Đây là một dạng sơ đồ biểu diễn mối liên hệ (edges) giữa các phần tử (nodes). Như vậy matrix tương quan cũng có thể được xem như 1 network trong đó mỗi biến số lần lượt bắt cặp với chính nó (đường chéo matrix) và với mỗi biến số còn lại.

Trước hết Nhi loại bỏ đường chéo khỏi matrix. Sau đó chuyển matrix thành một dataframe, rồi lọc bỏ, chỉ giữ lại những liên hệ với 1 biến số đích là brozek_fat.

dataframe này được đưa vào package igraph để tạo ra 1 graph. Nhưng đây chỉ mới là network cơ bản, để package visNetwork có thể hiểu được nó, ta phải chuyển đổi từ igraph sang visNetwork bằng hàm toVisNetworkData

# From matrix to network

diag(m)<-0

cdf=data.frame(row=rownames(m)[row(m)[upper.tri(m)]],
               col=colnames(m)[col(m)[upper.tri(m)]],
               corr=m[upper.tri(m)])

names(cdf)=c("from","to","corr")

cdf=subset(cdf,cdf$from=="brozek_fat")

graph<-graph_from_data_frame(cdf)

vg = toVisNetworkData(graph)

Chuẩn bị bảng màu để trang trí cho network

Trong network của chúng ta có 13 edges và 13 nodes, nối với 1 node trung tâm là brozek_fat, do đó ta cần 13 màu khác nhau. Nhi có ý tưởng sẽ tô màu theo độ mạnh tương quan (-1 đến 1), nên sẽ tạo ra 13 màu liên tục từ xanh đến đỏ.

#Testing color

coledges=colorRampPalette(c("royalblue","red"))
plot(rep(1,13),col=(coledges(13)), pch=19,cex=3)

colnodes=colorRampPalette(c("#d3dfff","#ffd3d3"))
plot(rep(1,13),col=(colnodes(13)), pch=19,cex=3)

Vẽ network động tương tác bằng visNetwork

Cơ chế hoạt động của package visNetwork rất đơn giản, nó cần 2 dataframe, một cho nodes, 1 cho edges. Các thuộc tính của edges và nodes như hình dáng, máu sắc, kích thước… được quy định trong mỗi dataframe.

Ta tạo edges data trước, cái này hơi tế nhị, vì ta cần tô màu cho edges theo hệ số tương quan, và độ dài, độ dày của edges cũng sẽ tỉ lệ với hệ số tương quan.

edges = as.data.frame(vg$edges)%>%.[order(.$corr),]

edges=edges%>%mutate(.,label=round(.$corr,2),
               length = (1-.$corr)*500,
               width = .$corr*3,
               color=coledges(13),
               shadow = TRUE)

Sau đó ta làm đến nodes data, màu sắc của nodes cũng được tô theo hệ số tương quan.

nodes=data.frame(id=c(vg$nodes[1,1],edges$to),
                 label=c(vg$nodes[1,1],edges$to),
                 shape=c('circle',rep('ellipse',13)),
                 value=c(1,edges$corr),
                 color=c("gold",colnodes(13)),
                 shadow = TRUE)

Bây giờ ta có thể vẽ hình:

Các bạn có thể chơi đùa với network thỏa thích, như một chùm bong bóng.

visNetwork(nodes, edges,
           main = "A correlation network") %>% 
  visInteraction(navigationButtons = TRUE)%>%
  visNodes(physics=T)%>%
  visEdges(physics=T,
           arrows =list(from = list(enabled = TRUE, scaleFactor = 0.8)))

Nhận xét:

Tạm biệt các bạn.