我有一个庞大的数据集(> 900万行),这些数据是在站点上检测到单个动物时的时间和位置的。我想计算每只动物在每只动物之间在每只动物之间移动的路径之间的距离,以及每只动物在两只动物之间移动所花费的时间。然后,我想总结路径所有部分的总距离和时间。
对于此数据集中的每个人,每次在固定点检测到数据时都会对其进行组织。如果该人在固定点上连续很长一段时间,那么该时间段内有多个记录(相隔约30 s)。
我可以总结一下下面的数据,每当一个人在一个车站时,该行就会得到1行(请参见下文)。但是,当一个人多次前往同一个站点时,输出无法识别。
例如
id <- c("A", "A", "A", "A", "A", "A", "A", "A", "B", "B")
site <- c("a", "a", "b", "a", "c", "c", "c", "d", "a", "b")
time <- seq(1:10)
lat <- c(1, 1, 2, 1, 3, 3, 3, 4, 1, 2)
lon <- c(1, 1, 2, 1, 3, 3, 3, 4, 1, 2)
df <- data.frame(id, site, time, lat, lon)
df %>% group_by(id, site, lat, lon) %>%
summarize(timeStart = min(time),
timeEnd = max(time))
# A tibble: 6 x 6
# Groups: id, site, lat [?]
id site lat lon timeStart timeEnd
<fct> <fct> <dbl> <dbl> <dbl> <dbl>
1 A a 1 1 1 4
2 A b 2 2 3 3
3 A c 3 3 5 7
4 A d 4 4 8 8
5 B a 1 1 9 9
6 B b 2 2 10 10
一种对数据进行分组的方法,这样,将对同一站点的多次访问(中间有其他站点的行程)识别为行程的单独“行程”。
然后,我需要计算每个站点之间的大圆距,以及timeEnd(第一站点)和timeStart(第二站点)之间的时间差。
答案 0 :(得分:3)
首先,data.table
函数rleid
用于创建分组变量:对于每个人,站点的每个 change 都代表一个新的组。在每个组中,计算所需的统计信息:
library(data.table)
library(geosphere)
setDT(df)
df2 <- df[ , .(id = id[1],
site = site[1],
lat = lat[1],
lon = lon[1],
first_time = min(time),
last_time = max(time)),
by = .(id_site = rleid(id, site))]
然后,对于每个个体,使用geosphere::distHaversine
计算连续位置之间的连续大圆距离。为避免个人只有一个或两个记录*时出现问题,请添加一些检查:
df2[ , dist := if(.N == 1){
0 } else if(.N == 2){
c(0, distHaversine(c(lon[1], lat[1]), c(lon[2], lat[2])))
} else c(0, distHaversine(as.matrix(.SD[ , .(lon, lat)]))), by = id]
# id_site id site lat lon first_time last_time dist
# 1: 1 A a 1 1 1 2 0.0
# 2: 2 A b 2 2 3 3 157401.6
# 3: 3 A a 1 1 4 4 157401.6
# 4: 4 A c 3 3 5 7 314755.2
# 5: 5 A d 4 4 8 8 157281.8
# 6: 6 B a 1 1 9 9 0.0
# 7: 7 B b 2 2 10 10 157401.6
# 8: 8 C a 1 1 11 11 0.0
因此,对于每个人,每个新站点仅计算一次一次距离。这与其他答案不同,在另一个答案中,每个时间步长之间执行距离计算(似乎很多)。
*尝试例如distHaversine(cbind(1, 1))
(distGeo(cbind(1, 1))
)或distHaversine(cbind(c(1, 1), c(1, 2)))
(distGeo(cbind(c(1, 1), c(1, 2)))
)
数据
我添加了一个只有一条记录的个人作为测试用例。
id <- c("A", "A", "A", "A", "A", "A", "A", "A", "B", "B", "C")
site <- c("a", "a", "b", "a", "c", "c", "c", "d", "a", "b", "a")
time <- seq(1:11)
lat <- c(1, 1, 2, 1, 3, 3, 3, 4, 1, 2, 1)
lon <- c(1, 1, 2, 1, 3, 3, 3, 4, 1, 2, 1)
df <- data.frame(id, site, time, lat, lon)
答案 1 :(得分:2)
这可能不是您的完整解决方案,但这是一个好的开始。 这将找到每行数据之间的距离和时间差,并在id在行之间更改时将值设置为NA。
df <- data.frame(id, site, time, lat, lon)
library(geosphere)
library(dplyr)
#sort data by id and time
df<-df[order(df$id, df$time), ]
#find distance between each point in column
# Note longitude is the first column
df$distance<-c(NA, distGeo(df[,c("lon", "lat")]))
#find delta time between each row for each id
df<-df %>% group_by(id) %>% mutate(dtime=case_when(site != lag(site) ~ time-lag(time),
TRUE ~ NA_integer_))
#remove distances where there was no delta time (row pairs with different ids)
df$distance[is.na(df$dtime)]<-NA
#id summary
df%>% summarize(disttraveled=sum(distance, na.rm=TRUE), totaltime=sum(dtime, na.rm=TRUE))