在每个人多次旅行的数据框中插入缺失的纬度、经度

interpolate missing lat, lon in dataframe with multiple trips per individual

我有以下数据框 (df) 并想以等距间隔(例如每 250 米)或时间间隔(例如每 2 分钟)插入经纬度坐标。

> head(df)
   ID Latitude Longitude  trip   date.time
1  1 10.30447 -109.2323    1 2005-01-07 11:25:26
2  1 10.30425 -109.2321    1 2005-01-07 11:25:36
3  1 10.30314 -109.2326    1 2005-01-07 11:25:46
4  1 10.30199 -109.2328    1 2005-01-07 11:25:56
5  1 10.30079 -109.2334    1 2005-01-07 11:26:06
6  1 10.30006 -109.2331    1 2005-01-07 11:26:16

我尝试使用 R 包 zoo 和我在发布的类似问题中找到的以下代码来做到这一点:

full.time    <- with(df,seq(date.time[1],tail(date.time,1),by=1))
library(zoo)
df.zoo <- zoo(df[,3:4],df$date.time)        # convert to zoo object
result <- na.approx(df.zoo,xout=full.time)  # interpolate; result is also a zoo object
head(result)

但是,由于我的数据框包含多个人 (df$ID) 的多次旅行 (df$trip),我收到以下错误消息:

> df.zoo <- zoo(df[,3:4],df$date.time)        # convert to zoo object
Warning message:
In zoo(df[, 3:4], df$datetime) :
some methods for “zoo” objects do not work if the index entries in ‘order.by’ are not unique

如何 运行 以上代码(在循环中?)计算个人行程?

您的样本不具有代表性:您要求以 2 分钟为增量进行插值,但数据集跨度 < 2 分钟。所以在这个例子中我使用了 30 秒。增量。此外,您只提供了 1 个 ID/type 组合,因此无法验证它是否如您所愿。尽管如此它应该。

有几种方法可以做到这一点;我发现 data.table 是最方便的 - 而且肯定是最快的。

df$date.time <- as.POSIXct(df$date.time)  # make sure date.time is POSIXct
library(data.table)
interp.time <- function(var,dt) approx(dt,var,xout=seq(min(dt),max(dt),by="30 sec"))$y
result <- setDT(df)[,lapply(.SD,interp.time,dt=date.time), 
                     by=list(ID,trip), 
                     .SDcols=c("Latitude","Longitude","date.time")]
result[,date.time:=as.POSIXct(date.time, origin="1970-01-01")]
result
#    ID trip Latitude Longitude           date.time
# 1:  1    1 10.30447 -109.2323 2005-01-07 11:25:26
# 2:  1    1 10.30199 -109.2328 2005-01-07 11:25:56

对距离执行此操作有点复杂,因为我们当然不能在 lon/lat 数据上使用欧氏距离。下面的解决方案使用 geotools 包中的 distHaversine(...) 来计算累积 Haversine 距离,然后对其进行插值。这里我们使用50m而不是250m。

library(geosphere)    # for distHaversine
get.dist <- function(lon, lat) distHaversine(tail(cbind(lon,lat),-1),head(cbind(lon,lat),-1))
df[,dist:=c(0,cumsum(get.dist(Longitude,Latitude))),by=list(ID,trip)]

interp.dist <- function(var,dist) approx(dist,var,xout=seq(min(dist),max(dist),by=50))$y
result <- setDT(df)[,lapply(.SD,interp.dist,dist=dist), 
                    by=list(ID,trip), 
                    .SDcols=c("Latitude","Longitude","dist")]

# plot the result
plot(Latitude~Longitude,df, pch=20, asp=1)
lines(Latitude~Longitude,df, col="blue")
points(Latitude~Longitude,result, col="red")
lines(Latitude~Longitude,result, col="red")

请注意,您必须将绘图的纵横比设置为 1:1,否则距离会失真。