在R中跨数据框匹配值并计算Flow变量的实现方法
嘿,作为R新手不用发愁,你的需求完全可以实现——先从你想到的for loop入手帮你理清逻辑,再给你更高效的向量化方案,毕竟数据量大的时候循环会有点慢~
首先咱们先构造一组示例数据,方便你跟着代码跑:
# 构造示例数据 df1 <- data.frame( CityYear = c("NY2000", "LA2000", "DC2000", "NY2001", "LA2001"), City = c("NY", "LA", "DC", "NY", "LA"), Year = c(2000, 2000, 2000, 2001, 2001), Value = c(10, 20, 30, 15, 25) ) df2 <- data.frame( City1 = c("NY", "NY", "LA", "DC", "NY"), City2 = c("LA", "DC", "NY", "NY", "LA"), # 包含重复配对 Connections = c(5, 3, 5, 3, 4) )
方法一:用for loop实现(新手友好,逻辑清晰)
循环的思路就是逐个处理每个城市-年份的观测,找到同一年份的其他城市,再匹配对应的连接数计算总和:
# 先给df1新增Flow列,初始值设为0 df1$Flow <- 0 # 外层循环:遍历df1的每一行 for (i in 1:nrow(df1)) { # 提取当前行的城市和年份 current_city <- df1$City[i] current_year <- df1$Year[i] # 筛选出同一年份、非当前城市的所有记录 other_cities <- df1[df1$Year == current_year & df1$City != current_city, ] # 初始化当前观测的Flow总和 total_flow <- 0 # 内层循环:遍历每个其他城市,计算对应贡献 for (j in 1:nrow(other_cities)) { target_city <- other_cities$City[j] # 找到当前城市和目标城市的所有配对(不管City1/City2的顺序) conn_records <- df2[ (df2$City1 == current_city & df2$City2 == target_city) | (df2$City1 == target_city & df2$City2 == current_city), "Connections" ] # 把所有连接数相加,再乘以目标城市的Value,累加到total_flow total_flow <- total_flow + sum(conn_records) * other_cities$Value[j] } # 把计算好的Flow赋值给当前行 df1$Flow[i] <- total_flow } # 查看结果 print(df1)
这段代码跑起来后,你就能看到每个CityYear对应的Flow值了,比如NY2000的Flow就是(5+4)*20 + 3*30 = 270,和你的需求完全匹配~
方法二:用tidyverse实现(更高效,适合大数据)
如果你的数据量很大,循环会比较慢,这时候用tidyverse的向量化操作会快很多,逻辑是通过连接来批量处理所有配对:
library(tidyverse) # 步骤1:给df1做自连接,得到同一年份的所有城市配对(排除自己和自己) city_pairs <- df1 %>% inner_join(df1, by = "Year", suffix = c("_origin", "_target")) %>% filter(City_origin != City_target) # 步骤2:连接df2的连接数数据,处理City1/City2的两种顺序 city_pairs_with_conn <- city_pairs %>% # 先匹配City_origin=City1、City_target=City2的情况 left_join(df2, by = c("City_origin" = "City1", "City_target" = "City2")) %>% # 再匹配City_origin=City2、City_target=City1的情况 left_join(df2, by = c("City_origin" = "City2", "City_target" = "City1"), suffix = c("", "_reverse")) %>% # 合并两个方向的连接数,没有的用0填充 mutate(Connections = coalesce(Connections, Connections_reverse, 0)) %>% select(-Connections_reverse) # 删掉多余的列 # 步骤3:按原始城市-年份分组,计算Flow总和 flow_results <- city_pairs_with_conn %>% group_by(CityYear_origin, City_origin, Year_origin) %>% summarise(Flow = sum(Connections * Value_target, na.rm = TRUE), .groups = "drop") %>% # 重命名列,和原df1对齐 rename(CityYear = CityYear_origin, City = City_origin, Year = Year_origin) # 合并回原df1,得到完整结果 df1_final <- df1 %>% left_join(flow_results, by = c("CityYear", "City", "Year")) # 查看结果 print(df1_final)
这个方法不需要写循环,靠tidyverse的连接和分组操作就能批量完成计算,速度比循环快很多,而且代码更简洁易维护~
内容的提问来源于stack exchange,提问作者giorgio farace
相关产品推荐
相关产品推荐

