对于循环,计算预测的运动,如果超出范围则删除行

时间:2018-10-23 07:10:15

标签: r for-loop geolocation gps spatial

我有一个包含车辆运动的数据集,其中车辆时间和位置通过GPS记录。问题在于,其中有几辆汽车存在重复的值(欺骗),并且我无法识别出真正的汽车。我的意图是创建一个前循环,该循环计算从一个位置到下一个位置的预测运动,如果下一个值在该值之外,则该行将被删除。这也将删除离群值,因为某些原因,离群值极高。

Dataset
Vehicle ID      Time                 Lat     Long    Max Speed (kts)
1             01.01.2013 12:00:00    9.535   18.536     20
1             01.01.2013 12:10:00    9.539   18.539     20
1             01.01.2013 12:20:00    65.535  35.545     20
1             01.01.2013 12:30:00    65.835  35.545     20
1             01.01.2013 12:40:00    9.541   18.542     20
1             01.01.2013 12:50:00    66.135  35.536     20
1             01.01.2013 13:00:00    9.543   18.545     20
2             05.01.2013 17:00:00    13.535  15.536     30

该想法是运行一个循环,如果“车辆ID” =“车辆ID” +1,则从第1行获取位置,并通过计算下一行与第二行之间的时间(时间+ 1)来计算可能行驶的最大距离。并将其乘以最大速度。然后计算理论上车辆在(时间+ 1)处的最大和最小纬度和经度,如果位置在这些最大值之外,则该行将被删除,并且循环将在下一行运行相同的语句。

类似这样的东西:

if vehicle ID = vehicle ID[n+1], 
then (create latmax and latmin) ( time[n+1] - time ) * maximum speed +- latitude &
then (create lonmax and lonmin) ( time[n+1] - time ) * maximum speed +- longitude
then if lat[n+1] > latmax & lat[n+1] < latmin & lon[n+1] > lonmax & lon[n+1] < lonmax (deleterow) if not, do the same at next line

这应该导致删除示例中的第3、4和6行。对于第8行,有一辆新车,并且允许较大的位置偏差。

此方法没有考虑到地球是圆形的事实,并且纬度之间的距离越接近北极或南极,距离越短。最好的解决方案是通过在公式中进行数学求解,或者使用distm或类似方法来计算真实距离,从而考虑到这一点。在公式中实现余弦是最简单的方法。但是,离群值和真实位置之间的偏差通常很大,以至于在实际操作中该数据集的曲率并不重要。

1 个答案:

答案 0 :(得分:0)

好吧,这里有2个问题,您有一个研究问题,您需要定义适当的距离,以比较坐标对中的欺骗对,但是最重要的是,您需要定义欺骗对及其以前已知的非对数的ID。 -欺骗坐标。第一个问题是研究问题,我不会对其进行深入研究,但是也许在互联网上搜索如何基于坐标来计算距离会有所帮助。假设您要选择到最新的已知非欺骗位置的最小距离,则下面提出第二个问题的解决方案,即编码部分。

首先,您可以通过运行以下示例来作为我的示例:

dput(df)
structure(list(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L), structure(c(1L, 
1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L), .Label = c("01.01.2013", "05.01.2013"
), class = "factor"), structure(c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 
8L, 3L), .Label = c("12:00:00", "12:10:00", "12:20:00", "12:30:00", 
"12:40:00", "12:50:00", "13:00:00", "17:00:00"), class = "factor"), 
    c(9.535, 9.635, 65.535, 65.835, 9.935, 66.135, 10.235, 13.535, 
    40.535), c(18.536, 18.636, 35.536, 35.536, 18.936, 35.536, 
    19.236, 15.536, 40.545), c(20L, 20L, 20L, 20L, 20L, 20L, 
    20L, 30L, 20L)), .Names = c("Vehicle ID", "date", "Time", 
"Lat", "Long", "Max Speed (kts)"), class = "data.frame", row.names = c(NA, 
-9L))

我的方法是使用一系列apply函数。我也很感兴趣是否有人知道除 explicit 循环以外的一种更优雅的方法,这也许可以用更少的步骤完成工作,但我倾向于避免这种情况。

spoofingtestdb <- df[,1:3]
df$spoofing <- duplicated(spoofingtestdb)|duplicated(spoofingtestdb, fromLast = T)
df$datetime <- dmy_hms(paste0(df$date,"-", df$Time))
df$candidatespreviousposition <- apply(df, 1, function(x) which(df$`Vehicle ID`== x["Vehicle ID"] & !df$spoofing & (as_datetime(df$datetime) < as_datetime(x["datetime"])) )   )
df$latestpreviousposition <- NA
for(i in 1: nrow(df)){
  if(length(df$candidatespreviousposition[[i]]>0)) df$latestpreviousposition[[i]] <- df$candidatespreviousposition[[i]][which.max(df$datetime[df$candidatespreviousposition[[i]]])]
}
df$spoofingkey <- paste0(df$`Vehicle ID`, df$datetime)
df$spoofingid <- ifelse(df$spoofing,  apply(df, 1, function(x) which(df$spoofingkey==x["spoofingkey"])), NA)
df$lat1 <- apply(df, 1, function(x) df$Lat[x[["spoofingid"]][1]][which(!is.na(df$Lat[x[["spoofingid"]][1]]))]  )
df$long1 <- apply(df, 1, function(x) df$Long[x[["spoofingid"]][1]][which(!is.na(df$Long[x[["spoofingid"]][1]]))] )
df$latinit <- apply(df, 1, function(x) df$Lat[x["latestpreviousposition"]])
df$latinit <- ifelse(df$spoofing, df$Lat[df$latestpreviousposition], NA)
df$longinit <- ifelse(df$spoofing, df$Long[df$latestpreviousposition], NA)
getdistance <- function(latinit, longinit, lat, long) {
  distance1 <- abs(lat-latinit)+abs(long-longinit)
}
df$distance <- ifelse(df$spoofing, getdistance(df$latinit, df$longinit, df$Lat, df$Long), NA )
df$spoofingnumber <- apply(df, 1, function(x) paste0(x["spoofingid"], collapse=""))
#apply(df, 1, function(x) which(df$spoofingnumber==x["spoofingnumber"]))
df$ismindistance <- apply(df, 1, function(x) x["distance"] == min(df$distance[which(df$spoofingnumber==x["spoofingnumber"])]))
df$tokeep <- ifelse(is.na(df$ismindistance)|df$ismindistance, T, F)
result <-  df[df$tokeep,]
result

这里仅使用基本距离计算功能。结果如下所示,在您的示例中,您可以看到第二行已被删除,相对于先前的已知位置仅保留了最小距离。

  Vehicle ID       date     Time    Lat   Long Max Speed (kts) spoofing            datetime candidatespreviousposition
1          1 01.01.2013 12:00:00  9.535 18.536              20    FALSE 2013-01-01 12:00:00                           
2          1 01.01.2013 12:10:00  9.635 18.636              20    FALSE 2013-01-01 12:10:00                          1
4          1 01.01.2013 12:30:00 65.835 35.536              20    FALSE 2013-01-01 12:30:00                       1, 2
5          1 01.01.2013 12:40:00  9.935 18.936              20    FALSE 2013-01-01 12:40:00                    1, 2, 4
6          1 01.01.2013 12:50:00 66.135 35.536              20    FALSE 2013-01-01 12:50:00                 1, 2, 4, 5
7          1 01.01.2013 13:00:00 10.235 19.236              20    FALSE 2013-01-01 13:00:00              1, 2, 4, 5, 6
8          2 05.01.2013 17:00:00 13.535 15.536              30    FALSE 2013-01-05 17:00:00                           
9          1 01.01.2013 12:20:00 40.535 40.545              20     TRUE 2013-01-01 12:20:00                       1, 2
  latestpreviousposition          spoofingkey spoofingid   lat1  long1 latinit longinit distance spoofingnumber ismindistance tokeep
1                     NA 12013-01-01 12:00:00         NA                    NA       NA       NA             NA            NA   TRUE
2                      1 12013-01-01 12:10:00         NA                    NA       NA       NA             NA            NA   TRUE
4                      2 12013-01-01 12:30:00         NA                    NA       NA       NA             NA            NA   TRUE
5                      4 12013-01-01 12:40:00         NA                    NA       NA       NA             NA            NA   TRUE
6                      5 12013-01-01 12:50:00         NA                    NA       NA       NA             NA            NA   TRUE
7                      6 12013-01-01 13:00:00         NA                    NA       NA       NA             NA            NA   TRUE
8                     NA 22013-01-05 17:00:00         NA                    NA       NA       NA             NA            NA   TRUE
9                      2 12013-01-01 12:20:00       3, 9 65.535 35.536   9.635   18.636   52.809        c(3, 9)          TRUE   TRUE

选择适合自己的距离功能后,只需替换上面的getdistance()功能即可。