在R中计算鸟类当日取食点与前一日选择取食点的距离
问题描述
需要为鸟类取食数据创建一个新变量,计算当日每个取食点与**该鸟类前一日选中的取食点(即bp==1且日期为前一日的行)**之间的欧氏距离。示例数据如下:
library(tibble) reprex <- tibble(bird = c("A", "A", "A", "B", "B", "B", "C", "C"), feedLoc = c("x","y", "x", "x", "y", "x", "y", "z"), date = as.Date(c("2020-05-10", "2020-05-11", "2020-05-11", "2020-05-24", "2020-05-25", "2020-05-25", "2020-05-22", "2020-05-23")), h = c(100, 123, 45, 75, 89, 64, 99, 101), v = c(89, 23, 65, 92, 29, 90, 120, 34), bp = c(1, 1, 0, 1, 0, 1, 1, 0))
原数据输出:
# A tibble: 8 × 6 bird feedLoc date h v bp <chr> <chr> <date> <dbl> <dbl> <dbl> 1 A x 2020-05-10 100 89 1 2 A y 2020-05-11 123 23 1 3 A x 2020-05-11 45 65 0 4 B x 2020-05-24 75 92 1 5 B y 2020-05-25 89 29 0 6 B x 2020-05-25 64 90 1 7 C y 2020-05-22 99 120 1 8 C z 2020-05-23 101 34 0
最初尝试按bird和feedLoc分组、按日期排序后用lag()函数偏移坐标,但排序后的上一行不一定是前一日的数据,导致计算错误。
解决方案
核心思路是先提取每个鸟类前一日选中的取食点坐标,再通过日期匹配将坐标合并到原表,最后计算欧氏距离。使用dplyr实现:
library(dplyr) # 1. 提取bp=1的行,生成匹配当日的键(date+1),并保留前一日的坐标 prev_selected <- reprex %>% filter(bp == 1) %>% mutate(match_date = date + 1) %>% select(bird, match_date, prev_h = h, prev_v = v) # 2. 原表与前一日选中点左连接,计算距离 result <- reprex %>% left_join(prev_selected, by = c("bird" = "bird", "date" = "match_date")) %>% mutate( distance_to_prev_bp = case_when( !is.na(prev_h) ~ sqrt((h - prev_h)^2 + (v - prev_v)^2), TRUE ~ NA_real_ # 没有前一日选中点时设为NA ) ) %>% select(-match_date) # 移除辅助列 print(result)
输出结果
# A tibble: 8 × 7 bird feedLoc date h v bp prev_h prev_v distance_to_prev_bp <chr> <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 A x 2020-05-10 100 89 1 NA NA NA 2 A y 2020-05-11 123 23 1 100 89 72.8 3 A x 2020-05-11 45 65 0 100 89 57.7 4 B x 2020-05-24 75 92 1 NA NA NA 5 B y 2020-05-25 89 29 0 75 92 65.8 6 B x 2020-05-25 64 90 1 75 92 11.2 7 C y 2020-05-22 99 120 1 NA NA NA 8 C z 2020-05-23 101 34 0 99 120 86.0
说明
- 首先筛选
bp==1的行,将日期加1作为match_date,这样当日的行可以通过bird和date精准匹配到前一日的选中点。 - 左连接确保所有原表行都被保留,没有前一日数据的行(如每个鸟类的第一条记录)距离设为
NA。 - 直接用欧氏距离公式
sqrt((h - prev_h)^2 + (v - prev_v)^2)完成计算。
内容的提问来源于stack exchange,提问作者milburns
相关产品推荐
相关产品推荐

