如何在R语言中计算分组数据行间距离与时间差的所有可能组合?
在R语言中计算分组钞票数据的行间距离与时间差所有组合
我来帮你搞定这个问题!要计算每张钞票(按bid分组)所有位置点之间的时间差和地理距离,咱们可以用R里的dplyr做分组处理,再结合geosphere包计算球面距离,步骤非常清晰:
1. 准备数据
首先把你提供的原始数据转换成R的数据框:
# 构建数据框 df <- data.frame( bid = c(123,123,123,123,456,456,456,456,234,234,234,234), ts = c(0,23,45,50,0,12,27,19,0,8,15,23), latitude = c(38.40513,38.41180,42.20771,40.22803,39.12882,38.46078,40.53698,39.04038,39.18274,39.58652,41.32383,40.26008), longitude = c(41.83777,41.68493,43.36318,43.00208,42.73877,42.79847,42.57617,42.17070,41.17445,43.61317,41.49377,42.01927) )
2. 加载必要的包
我们需要两个包:dplyr用来做分组和数据操作,geosphere用来计算经纬度之间的地理距离:
library(dplyr) library(geosphere)
3. 计算无序两两组合的时间差与距离
如果只需要无序的组合(比如点A和点B的组合只算一次,不区分起点终点),可以用下面的代码:
result_unordered <- df %>% # 按钞票ID分组 group_by(bid) %>% # 对每个分组单独处理 group_modify(function(group_data, group_key) { # 生成当前组内所有行的两两配对(i<j,避免重复) row_combos <- combn(nrow(group_data), 2) # 把组合转换成数据框,提取对应的数据并计算指标 combo_results <- data.frame( row_idx_1 = row_combos[1,], row_idx_2 = row_combos[2,] ) %>% mutate( # 提取两个点的时间戳 ts_1 = group_data$ts[row_idx_1], ts_2 = group_data$ts[row_idx_2], # 提取经纬度(注意geosphere函数要求先经度后纬度) lon_1 = group_data$longitude[row_idx_1], lat_1 = group_data$latitude[row_idx_1], lon_2 = group_data$longitude[row_idx_2], lat_2 = group_data$latitude[row_idx_2], # 计算时间差(取绝对值,因为无序组合不区分先后) time_diff_days = abs(ts_2 - ts_1), # 计算球面距离(Haversine公式,单位为米) distance_m = distHaversine(cbind(lon_1, lat_1), cbind(lon_2, lat_2)) ) %>% # 整理输出列,保留有用信息 select( bid = group_key$bid, ts_1, ts_2, time_diff_days, lat_1, lon_1, lat_2, lon_2, distance_m ) return(combo_results) }) %>% # 取消分组,方便后续操作 ungroup()
代码解释
group_by(bid):将数据按钞票ID拆分,每组对应一张钞票的所有位置记录;combn(nrow(group_data), 2):生成当前组内所有行的两两组合,比如4行的组会生成6种不重复的组合;distHaversine():用Haversine公式计算两点间的球面距离,结果单位是米,若需要公里可除以1000;- 最后整理输出列,让结果更清晰易读。
你可以用head(result_unordered)查看前几行结果,大概是这样:
# A tibble: 6 × 9 bid ts_1 ts_2 time_diff_days lat_1 lon_1 lat_2 lon_2 distance_m <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 123 0 23 23 38.405 41.838 38.412 41.685 17386. 2 123 0 45 45 38.405 41.838 42.208 43.363 427219. 3 123 0 50 50 38.405 41.838 40.228 43.002 262464. 4 123 23 45 22 38.412 41.685 42.208 43.363 410414. 5 123 23 50 27 38.412 41.685 40.228 43.002 245617. 6 123 45 50 5 42.208 43.363 40.228 43.002 222766.
4. 计算有序两两组合的时间差与距离
如果需要有序的组合(比如区分起点和终点,(A,B)和(B,A)都保留),可以把combn换成expand.grid,代码如下:
result_ordered <- df %>% group_by(bid) %>% group_modify(function(group_data, group_key) { # 生成所有有序组合,排除自己和自己的配对 row_combos <- expand.grid( row_idx_1 = 1:nrow(group_data), row_idx_2 = 1:nrow(group_data) ) %>% filter(row_idx_1 != row_idx_2) combo_results <- row_combos %>% mutate( ts_1 = group_data$ts[row_idx_1], ts_2 = group_data$ts[row_idx_2], lon_1 = group_data$longitude[row_idx_1], lat_1 = group_data$latitude[row_idx_1], lon_2 = group_data$longitude[row_idx_2], lat_2 = group_data$latitude[row_idx_2], # 时间差保留正负,体现先后顺序 time_diff_days = ts_2 - ts_1, distance_m = distHaversine(cbind(lon_1, lat_1), cbind(lon_2, lat_2)) ) %>% select(bid = group_key$bid, ts_1, ts_2, time_diff_days, lat_1, lon_1, lat_2, lon_2, distance_m) return(combo_results) }) %>% ungroup()
注意事项
如果你的数据量很大,组合数会快速增长(n行的组,无序组合数是n*(n-1)/2,有序组合数是n*(n-1)),要注意内存使用情况,必要时可以分批处理。
内容的提问来源于stack exchange,提问作者nateswill
相关产品推荐
相关产品推荐

