Цикл For, рассчитать прогнозируемое движение, удалить строку, если вне диапазона - PullRequest
0 голосов
/ 23 октября 2018

У меня есть набор данных, содержащий движение транспортного средства, где время и положение транспортного средства регистрируются с помощью GPS.Проблема состоит в том, что существуют дублирующие значения (подмена) для нескольких транспортных средств, и я не могу идентифицировать истинное транспортное средство, за исключением предположения, что в первый раз, когда транспортное средство вводится, оно является истинным транспортным средством.Мое намерение состоит в том, чтобы создать fore-цикл, который вычисляет предсказанное движение от одной позиции до следующей, и если следующее значение находится вне этого значения, строка будет удалена.Это также удалит выбросы, при которых одна позиция по какой-то причине крайне отключена.

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

Идея состоит в том, чтобы запустить цикл, который берет позицию из строки 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 голосов
/ 23 октября 2018

Хорошо, у вас есть 2 проблемы здесь, у вас есть исследовательская задача, где вам нужно определить подходящее расстояние для сравнения пар спуфинга в зависимости от координат, но в первую очередь вам нужно определить пары спуфинга и идентификатор их предыдущего известного не.спуфинг координат.Первая проблема - это проблема исследования, и я не буду углубляться в это, но, возможно, поиск в Интернете о том, как рассчитать расстояния на основе координат, поможет вам.Ниже предлагается решение второй проблемы, части кодирования, при условии, что вы хотите выбрать минимальное расстояние до последней известной позиции без спуфинга.

Сначала вы можете взять мой тот же пример, выполнив следующее:

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.Мне также интересно, если кто-то знает более элегантный способ сделать это, кроме явных циклов, которые, возможно, могут выполнять работу за меньшее количество шагов, но я склонен избегать их.

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() выше.

...