Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R, dplyr: cumulative version of n_distinct

Tags:

r

dplyr

cumsum

I have a dataframe as follows. It is ordered by column time.

Input -

df = data.frame(time = 1:20,
            grp = sort(rep(1:5,4)),
            var1 = rep(c('A','B'),10)
            )

head(df,10)
   time grp var1
1   1   1    A
2   2   1    B
3   3   1    A
4   4   1    B
5   5   2    A
6   6   2    B
7   7   2    A
8   8   2    B
9   9   3    A
10 10   3    B

I want to create another variable var2 which computes no of distinct var1 values so far i.e. until that point in time for each group grp . This is a little different from what I'd get if I were to use n_distinct.

Expected output -

   time grp var1 var2
1   1   1    A    1
2   2   1    B    2
3   3   1    A    2
4   4   1    B    2
5   5   2    A    1
6   6   2    B    2
7   7   2    A    2
8   8   2    B    2
9   9   3    A    1
10 10   3    B    2

I want to create a function say cum_n_distinct for this and use it as -

d_out = df %>%
  arrange(time) %>%
  group_by(grp) %>%
  mutate(var2 = cum_n_distinct(var1))
like image 955
steadyfish Avatar asked Aug 28 '14 15:08

steadyfish


1 Answers

A dplyr solution inspired from @akrun's answer -

Ths logic is basically to set 1st occurrence of each unique values of var1 to 1 and rest to 0 for each group grp and then apply cumsum on it -

df = df %>%
  arrange(time) %>%
  group_by(grp,var1) %>%
  mutate(var_temp = ifelse(row_number()==1,1,0)) %>%
  group_by(grp) %>%
  mutate(var2 = cumsum(var_temp)) %>%
  select(-var_temp)

head(df,10)

Source: local data frame [10 x 4]
Groups: grp

   time grp var1 var2
1     1   1    A    1
2     2   1    B    2
3     3   1    A    2
4     4   1    B    2
5     5   2    A    1
6     6   2    B    2
7     7   2    A    2
8     8   2    B    2
9     9   3    A    1
10   10   3    B    2
like image 94
steadyfish Avatar answered Sep 24 '22 07:09

steadyfish