Creating a Counter Function with DPLYR

I have the following dataset:

my_data = structure(list(id = c("A", "A", "A", "A", "A", "B", "B", "B", 
"B"), result = c("AAA", "BBB", "CCC", "AAA", "CCC", "DDD", "BBB", 
"BBB", "DDD")), class = "data.frame", row.names = c(NA, -9L))

For each unique ID, am interested in learning about how to write a general function that updates a "counter variable" under certain conditions.

For example - for each unique ID:

  • if result = AAA then counter restarts to 0
  • if result = BBB then counter = counter + 1
  • if result = CCC then counter = counter + 2
  • if result = DDD then counter = counter - 1.

Here is my attempt to do this:

library(dplyr)

my_data %>%
  group_by(id) %>%
  mutate(counter = ifelse(result == "AAA", 0, 
         ifelse(result == "BBB", 1, 
     ifelse(result == "CCC", 2, 
         ifelse(result == "DDD", -1, 
     ifelse(result == 1, cumsum(result), 0))))))

However, I don't think the results are correct - when I look at the results:

# A tibble: 9 x 3
# Groups:   id [2]
  id    result counter
  <chr> <chr>    <dbl>
1 A     AAA          0
2 A     BBB          1
3 A     CCC          2
4 A     AAA          0
5 A     CCC          2
6 B     DDD         -1
7 B     BBB          1
8 B     BBB          1
9 B     DDD         -1

In the third row, the value of the counter should be 3 : 0 (result from row1) + 1 (result from row2) + 2 (result from row3).

I am trying different ways to debug this function to match my requirements, but so far nothing is working.

Can someone please show me how to correct this?

Thanks!

Note: I think the expected output should look something like this:

  id result counter
1  A    AAA       0
2  A    BBB       1
3  A    CCC       3
4  A    AAA       0
5  A    CCC       2
6  B    DDD      -1
7  B    BBB       0
8  B    BBB       1
9  B    DDD       0

this seems to do it


group_by(my_data, id) |>
  mutate(
    instance = case_when(
      result == "BBB" ~ 1,
      result == "CCC" ~ 2,
      result == "DDD" ~ -1,
      TRUE ~ 0
    ),
    plaincounter = cumsum(instance),
    resetcounter = cumsum(ifelse(result == "AAA", plaincounter, 0)),
    counter = plaincounter - resetcounter
  )
2 Likes

@ nirgrahamuk: Thank you for your answer! Do you know why result="AAA" needs to be specified?

Im afraid i dont undrdtand the question, can you rephrase ?

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.