在探寻数据之间的关系时,由于数据类型的限制,很多时候我们可以从数据的现实角度出发去选择方法,而不是一昧地从头尝试不同方法去分类。假如我们用的是传染病在市面上的传播路径数据,亦或是病毒对于基因的感染模块,就可以采用社交网络分析的方法,它的原理是类似于我们平时使用软件时会弹出“你可能认识的人”,通过比对非共同好友的共同好友数来判断两人是否认识。
以下是一个例子:
# 安装必要的包
if (!require("igraph")) install.packages("igraph")
if (!require("tidygraph")) install.packages("tidygraph")
if (!require("ggraph")) install.packages("ggraph")library(igraph)
library(tidygraph)library(ggraph)
library(dplyr)# 生成模拟社交网络数据 - 50个节点的小世界网络
set.seed(123)
social_net <- sample_smallworld(1, 50, 3, 0.1)# 添加节点属性
V(social_net)$name <- paste("用户", 1:50)
V(social_net)$gender <- sample(c("男", "女"), 50, replace = TRUE)
V(social_net)$age <- sample(18:60, 50, replace = TRUE)# 添加边属性(关系强度)
E(social_net)$strength <- runif(ecount(social_net), 0.1, 1)# 转换为tidygraph对象
tidy_net <- as_tbl_graph(social_net)# 计算网络指标并添加到网络对象
tidy_net <- tidy_net %>% activate(nodes) %>% mutate(degree = degree(social_net),closeness = closeness(social_net),betweenness = betweenness(social_net))# 社区检测
communities <- cluster_louvain(social_net)# 添加社区信息到两个网络对象
V(social_net)$community <- communities$membership
tidy_net <- tidy_net %>% activate(nodes) %>% mutate(community = as.factor(communities$membership))# 查看社区划分
print(paste("检测到", length(communities), "个社区"))
print(sizes(communities))# 可视化社区结构 (使用tidygraph对象)
ggraph(tidy_net, layout = "fr") + geom_edge_link(aes(alpha = strength), show.legend = FALSE) +geom_node_point(aes(color = community, size = betweenness)) +geom_node_text(aes(label = name), size = 3, repel = TRUE) +scale_color_brewer(palette = "Set1") +theme_graph() +labs(title = "社交网络社区结构",subtitle = "节点大小代表中介中心性,颜色代表不同社区",color = "社区")# 基于共同好友的好友推荐
recommend_friends <- function(net, user_id, n = 3) {# 获取用户当前好友current_friends <- neighbors(net, user_id)# 找出有共同好友但还不是好友的用户candidates <- setdiff(V(net)[unlist(neighborhood(net, 1, current_friends))],c(user_id, current_friends))# 计算共同好友数common_friends <- sapply(candidates, function(x) {length(intersect(neighbors(net, user_id), neighbors(net, x)))})# 返回推荐列表recs <- data.frame(user_id = candidates,user_name = V(net)$name[candidates],common_friends = common_friends) %>% arrange(desc(common_friends)) %>% head(n)return(recs)
}# 为用户1推荐3个可能的好友
recommend_friends(social_net, 1, 3)
输出:
Community sizes1 2 3 4 5 6
11 5 12 5 9 8 user_id user_name common_friends
1 5 用户 5 3
2 49 用户 49 3
3 6 用户 6 2
从输出中可以看到,社区之间存在明显的人数差异,说明网络存在社群结构;而用户5和49拥有一样的共友数量,则说明他们的社交重叠度更高,更有可能是认识的,从图中也能看到靠的更近。