Search code examples
rtailhead

Taking the differences in rows using head and tail functions in R


I have such data

id Pos
1    1
2    10
3    4
4    2
5    3
6    16

What I want to do is take the difference between the rows of Pos conditional on the id. If id is an odd number, then the difference is 1-10=-9. If id is an even number, the difference is 10-1=9.

So I should get

difference
-9
9
2
-2
-13
13

I tried this

q <- ifelse( (id %% 1) == 0,(tail(Pos, -1) - head(Pos, -1)), (head(Pos, -1) - tail(Pos, -1)) )

but it worked for the odds number only.

Any idea how to do this in R?

Cheers

Günal


Solution

  • An option is to create a group for each two elements with gl, take the difference of 'Pos', replicate twice (or n()), and change the sign based on the odd/even row_number()

    library(dplyr)
    df1 %>% 
        group_by(grp = as.integer(gl(n(), 2, n()))) %>% 
        mutate(Diff = rep(diff(Pos), n())) %>% 
        ungroup %>% 
        select(-grp) %>%
        mutate(Diff =  Diff * c(1, -1)[(id %%2) + 1])
    # A tibble: 6 x 3
    #     id   Pos  Diff
    #  <int> <int> <dbl>
    #1     1     1    -9
    #2     2    10     9
    #3     3     4     2
    #4     4     2    -2
    #5     5     3   -13
    #6     6    16    13
    

    If we need a solution with head/tail from base R

    i1 <-  with(df1, rep((tail(Pos, -1) - head(Pos, -1))[c(TRUE, FALSE)], each = 2))    
    c(1, -1)[(df1$id %%2) + 1] * i1
    #[1]  -9   9   2  -2 -13  13
    

    data

    df1 <-  structure(list(id = 1:6, Pos = c(1L, 10L, 4L, 2L, 3L, 16L)), 
      class = "data.frame", row.names = c(NA, 
    -6L))