Reputation: 167
I have a number of GPS points.
points <- structure(list(counter = 1:6, lon = c(11.8300715, 11.8296697,
11.8268708, 11.8267236, 11.8249612, 11.8251062), lat = c(48.1099048,
48.10884, 48.1067431, 48.1066077, 48.1037673, 48.103318), dist = c(46.8463805878941,
33.4921440879536, 10.6101735030534, 18.6085009578724, 6.97253109610173,
9.8912817449265)), row.names = c(NA, -6L), class = c("data.table",
"data.frame"))
I would like to smooth the track out. To do so i would like to apply the following calculation
points[n].latitude = points[n-1].latitude * 0.3 + points[n].latitude * .4 + points[n+1].latitude * .3
points[n].longitude = points[n-1].longitude * 0.3 + points[n].longitude * .4 + points[n+1].longitude * .3
So basically i need to iterate through the structure and apply the operation to previos and the next entry. What is the best way to do so? I would like to avoid a for loop. Thank you for advice.
Upvotes: 0
Views: 68
Reputation: 160417
Try this hack:
library(data.table)
cols <- c("lon", "lat")
mysmooth <- function(z, wts = c(0.3, 0.4, 0.3)) { notna <- !is.na(z); sum(z[notna] * wts[notna]) / sum(wts[notna]); }
points[, (cols) := lapply(.SD, function(z) zoo::rollapply(c(NA,z,NA), 3, mysmooth)), .SDcols = cols]
points
# counter lon lat dist
# 1: 1 11.82990 48.10945 46.846381
# 2: 2 11.82895 48.10853 33.492144
# 3: 3 11.82767 48.10733 10.610174
# 4: 4 11.82624 48.10580 18.608501
# 5: 5 11.82553 48.10448 6.972531
# 6: 6 11.82504 48.10351 9.891282
The intent of c(NA,z,NA)
is to somehow deal with partial vectors. By default, zoo::rollapply
will either:
partial=FALSE
will cause the return vector to be shorter than the source, because it only uses full windows. In this data with k=3
, this results in losing one value on the left and one value on the right (assuming align="center"
); orpartial=TRUE
send vectors of length less-than-3 to the function. When this happens, I assume that your function would be (value[n]*0.4 * value[n+1]*0.3)/0.7
(and similar for the right side).I should add that because I do a partial weighted-average, that the end points smoothing will be biased inwards.
Upvotes: 3
Reputation: 1305
All you need is to perform the calcs using the build-in shift function
setDT(points)[, (latitude.new) := shift(latitude, type='lag')*0.3 +
latitude * 0.4 +
shift(latitude, type='lead')*3,]
See here for more info How to create a lag variable within each group?.
Upvotes: 1