Increase from previous value by condition in R [duplicate]


Increase from previous value by condition in R [duplicate]



This question already has an answer here:



I was searching for an answer to my specific problem, but I didn't find a conclusion.



I have a dataframe with data


ID a
1 0
2 0
3 1
4 1
5 1
6 1
7 0
8 1
9 1
10 0
11 1
12 0
13 0



Now i want to add "b" column with number increase from previous b if a == 1



Result like this


ID a b
1 0 0
2 0 0
3 1 1
4 1 2
5 1 3
6 1 4
7 0 0
8 1 1
9 1 2
10 0 0
11 1 1
12 0 0
13 0 0
14 1 1
15 1 2
16 1 3
17 1 4



Thanks in advance!



This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.




3 Answers
3



Using dplyr an option can be to group on cumsum(a==0). This will create a group which got a previous row (if available with a=0 for all rows with a=1. Now, lag(cumsum(a==1)) will provide expected count.


dplyr


cumsum(a==0)


a=0


a=1


lag(cumsum(a==1))


library(dplyr)

df %>% group_by(grp = cumsum(a==0)) %>%
mutate(b = ifelse(a==1, lag(cumsum(a==1))+1,0)) %>%
ungroup() %>%
select(-grp) %>%
as.data.frame()

# ID a b
# 1 1 0 0
# 2 2 0 0
# 3 3 1 1
# 4 4 1 2
# 5 5 1 3
# 6 6 1 4
# 7 7 0 0
# 8 8 1 1
# 9 9 1 2
# 10 10 0 0
# 11 11 1 1
# 12 12 0 0
# 13 13 0 0



Data:


df <- read.table(text="
ID a
1 0
2 0
3 1
4 1
5 1
6 1
7 0
8 1
9 1
10 0
11 1
12 0
13 0",
header = TRUE, stringsAsFactors = FALSE)



How about the following using base R's rle


rle


df$b <- unlist(mapply(
function(len, val) if (val == 0) rep(0, len) else 1:len,
rle(df$a)$lengths, rle(df$a)$values));
df;
# ID a b
#1 1 0 0
#2 2 0 0
#3 3 1 1
#4 4 1 2
#5 5 1 3
#6 6 1 4
#7 7 0 0
#8 8 1 1
#9 9 1 2
#10 10 0 0
#11 11 1 1
#12 12 0 0
#13 13 0 0


df <- read.table(text =
"ID a
1 0
2 0
3 1
4 1
5 1
6 1
7 0
8 1
9 1
10 0
11 1
12 0
13 0", header = T)





Yeah!! Thank you very much for help
– Quý
Jul 1 at 9:18





Our result matches which means solutions are correct. I was slightly confused by OP's expected data having 17 rows.
– MKR
Jul 1 at 9:23


OP's





@MKR Yes so was I; I think OP must've used a slightly different input data for his expected output. @markus posted a a nice (and earlier) answer using data.table::rleid, that he took down again, perhaps also because of this confusion. A pity.
– Maurits Evers
Jul 1 at 9:28


data.table::rleid





You're very welcome @Quý!
– Maurits Evers
Jul 1 at 9:33





@MauritsEvers Undeleted my answer after reading your comment.
– markus
Jul 1 at 10:26



Here is one approach that uses rleid() from data.table to create a grouping variable that we use inside ave(). We then calculate the cumsum per group which will be 0 whenever a == 0.


rleid()


data.table


ave()


cumsum


0


a == 0


library(data.table)
df$new_b <- with(df, ave(a, rleid(a), FUN = cumsum))
df
# ID a b new_b
#1 1 0 0 0
#2 2 0 0 0
#3 3 1 1 1
#4 4 1 2 2
#5 5 1 3 3
#6 6 1 4 4
#7 7 0 0 0
#8 8 1 1 1
#9 9 1 2 2
#10 10 0 0 0
#11 11 1 1 1
#12 12 0 0 0
#13 13 0 0 0
#14 14 1 1 1
#15 15 1 2 2
#16 16 1 3 3
#17 17 1 4 4



Once data.table is loaded you could also do


data.table


setDT(df)[, new_b := cumsum(a), rleid(a)]



data


df <- structure(list(ID = 1:17, a = c(0L, 0L, 1L, 1L, 1L, 1L, 0L, 1L,
1L, 0L, 1L, 0L, 0L, 1L, 1L, 1L, 1L), b = c(0L, 0L, 1L, 2L, 3L,
4L, 0L, 1L, 2L, 0L, 1L, 0L, 0L, 1L, 2L, 3L, 4L)), .Names = c("ID",
"a", "b"), class = "data.frame", row.names = c(NA, -17L))

Popular posts from this blog

How to input without newline? (Python)

C++ thread error: no type named ‘type’ MINGW

Analog for TagView in flutter