如何将航运航次数据转换为visNetwork/igraph可用的From-To格式?
拆分航运数据港口字段并构建网络图数据的R实现思路
Hey Dhiraj, 我懂你现在的痛点——要把带航次ID的航运数据拆成From/To港口对,还要保留Commencing、Loading这些功能属性,最后用visNetwork或者igraph做网络图可视化,之前试了for循环没搞定对吧?别慌,咱们用更简洁高效的方法来解决这个问题。
首先,先模拟一下你的数据集结构(方便后续演示):
# 模拟你的航运数据集 shipping_data <- data.frame( VoyageID = c(1,1,1,2,2,2,2,3,3,3), PortName = c("Shanghai", "Shanghai", "Singapore", "Rotterdam", "Antwerp", "Hamburg", "Rotterdam", "Los Angeles", "Long Beach", "Oakland"), PortFunction = c("Commencing", "Loading", "Discharging", "Commencing", "Waiting", "Loading", "Discharging", "Commencing", "Waiting", "Discharging") )
核心思路:按航次分组配对港口
每个航次是一个连续的港口序列,我们需要按航次ID分组,把每个港口和它的下一个港口自动配对成From/To,同时保留对应的功能属性。用dplyr的分组函数比手动写for循环靠谱得多,能避免索引错误、分组遗漏这些坑。
1. 生成From/To字段与功能属性
library(dplyr) # 按航次分组,生成港口流转对 network_data <- shipping_data %>% group_by(VoyageID) %>% mutate( From = PortName, To = lead(PortName), # 取当前航次下一个港口作为To From_Function = PortFunction, # 保留出发港口的功能 To_Function = lead(PortFunction) # 保留到达港口的功能 ) %>% ungroup() %>% filter(!is.na(To)) # 过滤每个航次的最后一行(无后续港口,无需作为起点)
这里的lead()函数是关键——它会在每个航次分组内,把下一行的PortName和PortFunction移到当前行,自动完成港口配对,完美适配多卸载港口的场景(比如一个航次有A→B→C→D多个港口,会生成A→B、B→C、C→D三行数据)。
2. 为可视化准备节点和边数据
visNetwork和igraph都需要独立的节点数据集和边数据集,咱们来整理一下:
节点数据(所有唯一港口)
nodes <- network_data %>% # 合并From和To的港口,保留功能属性 select(PortName = From, Function = From_Function) %>% bind_rows(network_data %>% select(PortName = To, Function = To_Function)) %>% distinct(PortName, .keep_all = TRUE) %>% mutate(id = PortName) # visNetwork要求节点有唯一id,这里直接用港口名
边数据(港口流转关系)
edges <- network_data %>% select( from = From, to = To, label = paste(From_Function, "→", To_Function), # 边的标签显示功能流转 voyage_id = VoyageID # 保留航次ID,方便后续筛选 )
3. 用visNetwork快速生成网络图
library(visNetwork) visNetwork(nodes, edges) %>% visEdges(arrows = "to") %>% # 添加箭头明确流转方向 visOptions(highlightNearest = TRUE) %>% # 点击节点时高亮相邻节点 visLayout(randomSeed = 123) # 固定布局种子,避免每次刷新布局变化
为什么之前的for循环没成功?
大概率是手动循环时没处理好分组逻辑——比如没有正确按航次ID隔离数据,或者遗漏了每个航次最后一个节点的过滤。用dplyr的分组函数可以自动处理这些细节,比手动循环更稳定高效。
内容的提问来源于stack exchange,提问作者Dhiraj
相关产品推荐
相关产品推荐

