如何在大数据集中为每个name批量实现点数统计、ggplot可视化及排序?
批量处理多用户GPS场地使用分析方案
问题背景
手上有150万+行GPS数据,包含200+个独立用户(name字段),需要按每个用户统计其在各个场地多边形(site_polygons)的使用情况,包括:
- 每个场地的GPS点数映射绘图
- 每公顷使用量计算与排序
已能完成单个用户的分析,但批量处理遇到瓶颈。
示例数据
结构化R数据
structure(list(name = c("name1", "name1", "name2", "name2", "name3", "name3"), lat = c(50.40868, 50.40881, 50.40801, 50.40592, 50.39382, 50.43382), lng = c(-4.822094, -4.882094, -4.882658, -4.922658, -4.884558, -4.882658), time_stamp = structure(c(1672531320, 1672531440, 1672531560, 1672531680, 1672531320, 1672531440), tzone = "UTC", class = c("POSIXct", "POSIXt")), group = c("a", "a", "a", "a", "b", "b")), row.names = c(NA,-6L), class = c("tbl_df", "tbl", "data.frame"))
表格形式
| name | lat | lng | time_stamp | Group |
|---|---|---|---|---|
| name1 | 50.40868 | -4.882094 | 01/01/2023 00:02 | a |
| name1 | 50.40880 | -4.882658 | 01/01/2023 00:04 | a |
| name2 | 50.40801 | -4.883009 | 01/01/2023 00:06 | a |
| name2 | 50.40592 | -4.849149 | 01/01/2023 00:06 | a |
| name3 | 50.39382 | -4.884077 | 01/01/2023 00:06 | b |
| name3 | 50.40868 | -4.882139 | 01/01/2023 00:02 | b |
| name3 | 50.40880 | -4.882636 | 01/01/2023 00:04 | b |
单个用户分析代码(参考)
场地使用点数映射
library(sf) library(ggplot2) # 绘制场地边界+单个用户GPS点 ggplot() + geom_sf(data = site) + geom_sf(data = name1) # 计算每个场地内的GPS点数 inter_name1 <- st_intersects(site, name1) site$count_name1 <- lengths(inter_name1) # 绘制场地点数热力图 ggplot(site) + geom_sf(aes(fill = count_name1))
每公顷使用量计算
library(dplyr) site_use_name1 <- site %>% group_by(site_polygons) %>% summarise(area = sum(Area_ha), n_name1 = sum(count_name1), n_name1_per_ha = n_name1/area) %>% arrange(-n_name1_per_ha)
场地使用排序
ranked_name1 <- site_use_name1 %>% arrange(desc(n_name1_per_ha)) %>% mutate(rank = 1:nrow(site_use_name1))
批量处理解决方案
步骤1:预处理GPS数据
先把整个GPS数据集转成sf对象,按name分组:
# 加载必要包 library(sf) library(dplyr) library(purrr) library(ggplot2) # 将GPS数据转为sf点对象(假设原始数据框名为gps_data) gps_sf <- gps_data %>% st_as_sf(coords = c("lng", "lat"), crs = st_crs(site)) # 确保和site的坐标系一致 # 按name拆分数据,得到每个用户的sf对象列表 gps_by_name <- split(gps_sf, gps_sf$name)
步骤2:批量计算场地使用统计
写一个函数处理单个用户的数据,然后用map()批量执行:
# 定义单个用户的分析函数 analyze_user <- function(user_sf, site_sf) { # 计算每个场地内的GPS点数 inter <- st_intersects(site_sf, user_sf) site_temp <- site_sf %>% mutate(count = lengths(inter)) # 计算每公顷使用量并排序 site_use <- site_temp %>% group_by(site_polygons) %>% summarise(area = sum(Area_ha), n_points = sum(count), per_ha = n_points / area) %>% arrange(desc(per_ha)) %>% mutate(rank = row_number(), user = unique(user_sf$name)) # 添加用户名标识 return(site_use) } # 批量执行所有用户的分析,结果合并为一个数据框 all_user_stats <- map_dfr(gps_by_name, analyze_user, site_sf = site)
步骤3:批量生成场地使用热力图
同样用函数+批量映射实现,自动保存图片到指定文件夹:
# 创建保存图片的文件夹 dir.create("user_site_maps", showWarnings = FALSE) # 定义绘图函数 plot_user_map <- function(user_sf, site_sf) { user_name <- unique(user_sf$name) # 计算场地点数 inter <- st_intersects(site_sf, user_sf) site_temp <- site_sf %>% mutate(count = lengths(inter)) # 生成绘图 p <- ggplot() + geom_sf(data = site_temp, aes(fill = count)) + geom_sf(data = user_sf, size = 0.5, color = "red") + labs(title = paste0("用户", user_name, "场地使用点数分布"), fill = "GPS点数") + theme_minimal() # 保存图片 ggsave(filename = paste0("user_site_maps/", user_name, "_site_map.png"), plot = p, width = 10, height = 8) return(p) } # 批量生成所有用户的地图 walk(gps_by_name, plot_user_map, site_sf = site)
步骤4:快速查看排序结果
可以按用户筛选查看其场地排序,或者生成每个用户的排序表格:
# 查看单个用户的排序结果 filter(all_user_stats, user == "name1") # 批量导出每个用户的排序表格到csv dir.create("user_rank_tables", showWarnings = FALSE) all_user_stats %>% group_split(user) %>% walk(function(df) { user_name <- unique(df$user) write.csv(df, paste0("user_rank_tables/", user_name, "_rank.csv"), row.names = FALSE) })
内容的提问来源于stack exchange,提问作者Jackijones
相关产品推荐
相关产品推荐

