Q:

Days since a variable changed dplyr

Does anyone know of a dplyr method for calculating the number of days since a variable changed (by groups)?  For example, consider the number of days since a particular store last changed its price.
library(dplyr)
df <- data.frame(store = c(34, 34, 34, 34, 34, 28, 28, 28, 81, 81),
                 date  = c(20111231, 20111224, 20111217, 20111210, 20111203,
                           20111224, 20111217, 20111203, 20111231, 20111224),
                 price = c(3.45, 3.45, 3.45, 3.36, 3.45, 3.17, 3.25, 3.15,
                           3.49, 3.17))
df <- df %>% mutate(date = as.Date(as.character(date), format = "%Y%m%d")) %>%
        arrange(store, desc(date)) %>% group_by(store) %>% 
        mutate(pchange = price - lead(price))
df$days.since.change <- c(7, 14, 0, 21, 14, 7, 7, 0, 7, 0)

I'm trying to use dplyr to generate a variable called days.since.change. For example, store 34 charged $3.45 on 2012-12-31, a price which had been in effect for 21 days (since it charged $3.36 on 2012-12-10).  The variable appears manually above.  The challenge is that a store might change its price back to an earlier price level, which invalidates some grouping strategies.

A:

One option is to calculate the number of days between each price listing for each store and then adding a second grouping variable to group together consecutive dates during which the price didn't change.  Then just take the cumulative sum over the days that passed.
I did this with the dataset sorted by date in ascending order with lag instead of lead to avoid using arrange twice but of course you could change this around.  I also left the group variable in the dataset, which you likely won't want and could remove by ungrouping and then using select.
df %>% mutate(date = as.Date(as.character(date), format = "%Y%m%d")) %>%
    arrange(store, date) %>% 
    group_by(store) %>% 
    mutate(pchange = price - lag(price), dchange = as.numeric(date - lag(date))) %>%
    group_by(store, group = cumsum(c(1, diff(price) != 0))) %>%
    mutate(dchange = cumsum(dchange))

Source: local data frame [10 x 6]
Groups: store, group

   store       date price pchange dchange group
1     28 2011-12-03  3.15      NA      NA     1
2     28 2011-12-17  3.25    0.10      14     2
3     28 2011-12-24  3.17   -0.08       7     3
4     34 2011-12-03  3.45      NA      NA     1
5     34 2011-12-10  3.36   -0.09       7     2
6     34 2011-12-17  3.45    0.09       7     3
7     34 2011-12-24  3.45    0.00      14     3
8     34 2011-12-31  3.45    0.00      21     3
9     81 2011-12-24  3.17      NA      NA     1
10    81 2011-12-31  3.49    0.32       7     2

