How to compute relative difference in a circular domain (weekday) in R

431 views Asked by At

I would like to find the relative distance from a given day of week to another day of week. Assume the following R input of relative differences from day 0, in days:

day <- c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)

The domain has a periodicity of one week (thus 7 days). I would like to get the following values:

relativedist <- c(0, 1, 2, 3, 3, 2, 1, 0, 1, 2, 3, 3, 2, 1, 0)

using modulo is a natural first guess, but as expected, not correct - it does not work for circular domains:

day%%4 

results in

[1] 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2

I looked at packages circular and circStats, but failed to find an applicable function.

2

There are 2 answers

2
IRTFM On BEST ANSWER

In this case the pmin function will give the correct answer but your data is arranged to start and stop at a natural boundary, so you will need to make sure it's as general as you need (it did deliver the same sequence with 1:20 as input as the diffFromNearest function offered by @NickK):

> pmin( day %% 7, rev(day)%%7)
 [1] 0 1 2 3 3 2 1 0 1 2 3 3 2 1 0

The pmin and pmax functions do "side-by-side comparisons of two vectors.

This implements the logic in @NickK's procedure using pmin and modulus arithmetic:

pmin( day %% 7, (7-day)%%7)


> replicate( 20, {day = sample(1:30, 20); identical( pmin( day %% 7, (7-day)%%7), 
                                                     diffFromNearest(day, 7) )} )
 [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[16] TRUE TRUE TRUE TRUE TRUE
1
Nick Kennedy On

One way of solving this would be the following:

day <- c(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14)
diffFromNearest <- function(x, modulus) {
  dif <- x %% modulus
  ifelse(dif > modulus %/% 2, modulus - dif, dif)
}
diffFromNearest(day, 7)

 [1] 0 1 2 3 3 2 1 0 1 2 3 3 2 1 0