You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:58:55