在R中按Code内最近位置将天气数据连接至参与者数据列表
问题原因与解决方法
核心问题
你在for循环中每次将连接结果赋值给同一个merge变量,导致前一个参与者的结果被后一个覆盖,最终仅保留最后一个参与者的连接数据。
解决步骤
- 初始化存储容器:创建一个空列表,用于保存每个参与者的处理结果,避免赋值覆盖。
- 遍历处理每个参与者:对每个参与者的分Code子数据框,与对应Code的天气数据进行空间连接,再将该参与者的所有子结果合并为单个sf对象。
- 合并所有结果(可选):将所有参与者的结果合并为一个完整的sf数据框,并添加参与者标识以便区分。
修正后的完整代码
library(sf) library(purrr) #Participant1 HR<- c(60,62,61,60,60,61) Code<- c("0_0", "0_1", "1_1", "0_2", "2_2", "0_0") Lat <- c("1.295824", "1.295824", "1.295826", "1.295828", "1.295830", "1.295830") Lon <- c("103.8494", "103.8494", "103.8494", "103.8494", "103.8494", "103.8494") P1 <- data.frame(HR, Code, Lat, Lon) #Participant2 HR<- c(71,70,69,71,72, 70) Code<- c("0_0", "0_1", "1_1", "1_1", "0_2", "2_2") Lat <- c("1.295995", "1.295977", "1.295995", "1.295992", "1.295987", "1.295992") Lon <- c("103.8492", "103.8492", "103.8492", "103.8492", "103.8492", "103.8492") P2 <- data.frame(HR, Code, Lat, Lon) #Participant3 HR<- c(68,67,65,66,68, 68) Code<- c("0_0", "0_1", "1_1", "0_2", "2_2", "2_2") Lat <- c("1.295773", "1.295770", "1.295769", "1.295769", "1.295772", "1.295769") Lon <- c("103.8493", "103.8493", "103.8493", "103.8493", "103.8493", "103.8493") P3 <- data.frame(HR, Code, Lat, Lon) #Creating a list of df from participant data ListP <- list(P1, P2, P3) # 修正:先将Lat/Lon转为数值型,再创建sf对象并指定CRS ListP <- lapply(ListP, function(x) { x$Lat <- as.numeric(x$Lat) x$Lon <- as.numeric(x$Lon) sf::st_as_sf(x, coords = c("Lon", "Lat"), crs = 4326) # 坐标顺序:经度在前、纬度在后,指定WGS84坐标系 }) #Creating Weather df Tair <- c(30, 31, 32, 30, 21) Code<- c("0_0", "0_1", "1_1", "0_2", "2_2") Lat <- c("1.296033", "1.296028", "1.296020","1.296013", "1.296008") Lon <- c("103.8493", "103.8493", "103.8493", "103.8493", "103.8493") Weather <- data.frame(Tair, Code, Lat, Lon) # 修正:天气数据同样转换坐标为数值型并指定CRS Weather$Lat <- as.numeric(Weather$Lat) Weather$Lon <- as.numeric(Weather$Lon) Weather <- sf::st_as_sf(Weather, coords = c("Lon", "Lat"), crs = 4326) #splitting into nested data frames by Code ListP <- lapply(ListP, function(x) split(x, f=x$Code)) Weather <- split(x=Weather, f=Weather$Code) # 用for循环处理并存储结果 merged_results <- list() for(i in seq_along(ListP)) { # 对当前参与者的各Code子数据框,与对应天气数据做空间连接 merged_part <- purrr::map2(ListP[[i]], Weather, st_join, join = st_nearest_feature) # 将当前参与者的所有Code子结果合并为单个sf对象 merged_part <- do.call(rbind, merged_part) # 存入结果列表 merged_results[[i]] <- merged_part } # 可选:合并所有参与者结果,添加参与者ID final_merged <- do.call(rbind, merged_results) final_merged$participant_id <- rep(paste0("P", 1:length(ListP)), sapply(merged_results, nrow)) # 查看最终结果 head(final_merged)
额外说明
- 原代码中Lat和Lon是字符型,转换为sf对象时会导致坐标解析错误,因此添加了
as.numeric()转换步骤,并指定了标准地理坐标系(WGS84,EPSG:4326)。 - 使用
do.call(rbind, ...)将每个参与者按Code拆分的子结果合并,避免嵌套列表结构,方便后续分析。 - 如果偏好函数式编程风格,也可以用
lapply替代for循环,代码更简洁:
# 方法2:用lapply替代for循环 merged_results <- lapply(ListP, function(participant) { merged <- map2(participant, Weather, st_join, join = st_nearest_feature) do.call(rbind, merged) }) final_merged <- do.call(rbind, merged_results) final_merged$participant_id <- rep(paste0("P", 1:3), sapply(merged_results, nrow))
内容的提问来源于stack exchange,提问作者yuliya
相关产品推荐
相关产品推荐

