Reputation: 115
I'm aware that the title may be a little confusing but please allow me to clarify. I have a column with values
> df
Direction
139
118
180
142
185
224
137
245
I have the following formula
((pt1 - pt2 + 180)%%360 - 180)
I would like to insert this formula to calculate the difference between each consecutive instance Example:
((139 - 118 + 180)%%360 - 180) = 21
((118 - 180 + 180)%%360 - 180) = -62
Some of the things I've tried
Creating the function
angle <- function(turn1, turn2) {
coursediff <- ((turn1 - turn2 + 180)
%%360 - 180)
coursediff
}
angle(118, 180)
## [1] -62
Trying to use it for each consecutive row for column Direction, creating a new column named Diff
df$Diff <- with(df,
ave(Direction, ID, FUN=function(angle) c(NA, diff(angle))))
Or
df %>% group_by(ID) %>%
mutate(gap=angle(c(NA,diff(Direction)), 1))
Or
index <- function(angle) c(0, diff(angle))
DT <- data.table(df)
DT[, Diff := index(Direction), by = "ID"]
Or even
transform(df,
Diff=unlist(tapply(Direction, ID,
function(angle) c(0, diff(Direction)))))
All the above attempts are giving me the same answers as if I were to simply take the difference per row, like so
df$Diff <- c(NA, diff(df$Direction))
This is what I get now
> df
Direction Diff ID
139 NA 1
118 -21 1
180 62 1
142 -38 1
185 NA 2
224 39 2
137 -87 2
245 108 2
I hope someone can help me out, much appreciated!
Upvotes: 0
Views: 64
Reputation: 13680
When you do
angle(118, 180)
## [1] -62
Means
angle(line1, line2)
You are comparing a direction with its consecutive, e.g. the next one.
In the other functions you wrote, the order is reversed, that is
angle(line2, line1)
Just fix that and you obtain the result you want:
library(dplyr)
df %>%
group_by(ID) %>%
mutate(diff = (Direction - lead(Direction) + 180) %% 360 -180)
#> Source: local data frame [8 x 4]
#> Groups: ID [2]
#>
#> Direction Diff ID diff
#> <int> <int> <int> <dbl>
#> 1 139 NA 1 21
#> 2 118 -21 1 -62
#> 3 180 62 1 38
#> 4 142 -38 1 NA
#> 5 185 NA 2 -39
#> 6 224 39 2 87
#> 7 137 -87 2 -108
#> 8 245 108 2 NA
Upvotes: 2
Reputation: 38520
You can use ave
and diff
in base R like this.
dat$diff <- ave(dat$Direction, dat$ID,
FUN=function(x) c(NA, (rev((diff(rev(x))) + 180) %% 360) -180))
Here, we calculate in the desired order by feeding diff
the reversed vector using rev
and return the vector in the desired order using rev
on the output of diff
. Note that we need to use c(NA, ..)
to add a missing value for each ID.
which returns
dat
Direction Diff ID diff
1 139 NA 1 NA
2 118 -21 1 21
3 180 62 1 -62
4 142 -38 1 38
5 185 NA 2 NA
6 224 39 2 -39
7 137 -87 2 87
8 245 108 2 -108
data
dat <-
structure(list(Direction = c(139L, 118L, 180L, 142L, 185L, 224L,
137L, 245L), Diff = c(NA, -21L, 62L, -38L, NA, 39L, -87L, 108L
), ID = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L)), .Names = c("Direction",
"Diff", "ID"), row.names = c(NA, -8L), class = "data.frame")
Upvotes: 1