You may try this.
# a smaller test data set
x <- rnorm(24, 10, 10)
y <- rnorm(24, 20, 10)
loc <- rep(c("A", "B"), each = 4)
year <- rep(1999:2001, each = 8)
df <- data.frame(x, y, loc, year)
df
# apply function on subsets defined by location and year
# use tail and head to 'lag' y and x
by(df, df[ , c("loc", "year")], function(x){
with(x, atan2(y = tail(y, - 1) - head(y, -1), x = tail(x, -1) - head(x, - 1)))
})
# loc: A
# year: 1999
# [1] 2.306794 -2.363359 1.065151
# ---------------------------------------------------------------------------
# loc: B
# year: 1999
# [1] -1.077345 1.161944 -2.101823
# ---------------------------------------------------------------------------
# loc: A
# year: 2000
# [1] -1.76557207 1.79463661 -0.05251002
# ---------------------------------------------------------------------------
# loc: B
# year: 2000
# [1] 2.753115 -1.468055 -1.624389
# ...snip...
A dplyr
alternative. Because the length of the result of the function within each group does not equal the group size or 1 in this case, dplyr
is not happy at all to chew on a data frame (see here and here). A work-around is to feed dplyr
with a data.table
. Of course a data.table
only solution would then be cleanest here. I leave that to someone more familiar with data.table
than me...
library(data.table)
library(dplyr)
dt <- data.table(df)
dt %.%
group_by(loc, year) %.%
mutate(
atan = atan2(lead(y, default = NULL) - lag(y, default = NULL),
lead(x, default = NULL) - lag(x, default = NULL)))
# x y loc year atan
# 1 19.826573 18.354265 A 1999 2.30679446
# 2 11.856696 27.153197 A 1999 -2.36335869
# 3 -3.362242 12.150775 A 1999 1.06515149
# 4 11.126841 38.320662 A 1999 2.30679446
# 5 12.616396 31.782969 A 2000 -1.76557207
# 6 8.492305 10.877870 A 2000 1.79463661
# 7 4.921766 26.561845 A 2000 -0.05251002
# 8 14.398730 26.063752 A 2000 -1.76557207
# 9 11.800173 30.215422 A 2001 -2.74907150
# 10 -6.473259 22.650127 A 2001 0.11997030
# 11 6.528055 24.217425 A 2001 -1.71122202
# 12 4.951238 13.062497 A 2001 -2.74907150
# 13 1.640049 19.886848 B 1999 -1.07734532
# 14 4.123603 15.269110 B 1999 1.16194418
# 15 14.548780 39.330885 B 1999 -2.10182331
# 16 6.925468 26.350556 B 1999 -1.07734532
# ...snip...