1

Test data Frame:

a<-data.frame(True_False = c(T,F,F,F,F,T,F,T,T,T,F,F,F,F,F,F,F,F))
  True_False
1        TRUE
2       FALSE
3       FALSE
4       FALSE
5       FALSE
6        TRUE
7       FALSE
8        TRUE
9        TRUE
10       TRUE
11      FALSE
12      FALSE
13      FALSE
14      FALSE
15      FALSE
16      FALSE
17      FALSE
18      FALSE

Using this, I would like to edit this column or make a new one which has a True at least once every third row. Meaning I would need to check the current row, if False, and if the previous two rows are False, then make it a True. Otherwise leave it as it is. Using Zoo, Dplyr, and Rollapply, I get close.

library(zoo)
library(tidyverse)
    b<-a%>%
  mutate(Roll = ifelse(rollapplyr(Input,3,sum, partial = T) == 0,T,Input))
b$Desired<-c(T,F,F,T,F,T,F,T,T,T,F,F,T,F,F,T,F,F)

   Input  Roll Desired
1   TRUE  TRUE    TRUE
2  FALSE FALSE   FALSE
3  FALSE FALSE   FALSE
4  FALSE  TRUE    TRUE
5  FALSE  TRUE   FALSE
6   TRUE  TRUE    TRUE
7  FALSE FALSE   FALSE
8   TRUE  TRUE    TRUE
9   TRUE  TRUE    TRUE
10  TRUE  TRUE    TRUE
11 FALSE FALSE   FALSE
12 FALSE FALSE   FALSE
13 FALSE  TRUE    TRUE
14 FALSE  TRUE   FALSE
15 FALSE  TRUE   FALSE
16 FALSE  TRUE    TRUE
17 FALSE  TRUE   FALSE
18 FALSE  TRUE   FALSE

Essentially my issue is that it will rollapply the sum to the whole column, and then add the Trues after. Thus, we have Trues that are not necessary. So is there a way I can do this in which the True is applied before going to the next row? I assume I need to use an apply of some sort, but that is an area I'm not familiar with, and even reading the documentation I'm not sure how to do this directly.

Silentdevildoll
  • 1,187
  • 1
  • 6
  • 12

3 Answers3

1

Looks like you need something like this. Here is one approach (not the cleanest):

a<-data.frame(True_False = c(T,F,F,F,F,T,F,T,T,T,F,F,F,F,F,F,F,F))
a$Desired<-NA
a$Desired[4:nrow(a)]<-sapply(4:nrow(a),function(z){
  if(z%%3==1 & a$True_False[z]==F & a$True_False[z-1]==F & a$True_False[z-2]==F){a$True_False[z]<-T}else{a$True_False[z]}
})
a$Desired[1:3]<-a$True_False[1:3]
JeanVuda
  • 1,738
  • 14
  • 29
1

Due to the fact that you need to update your vector on the fly to process further operations, I'd say a simple for-loop is the way to go:

for(i in 3:nrow(a)){
  a$True_False[i] <- ifelse(sum(a$True_False[(i-2):i]) == 0, T, a$True_False[i])
}

> a
   True_False
1        TRUE
2       FALSE
3       FALSE
4        TRUE
5       FALSE
6        TRUE
7       FALSE
8        TRUE
9        TRUE
10       TRUE
11      FALSE
12      FALSE
13       TRUE
14      FALSE
15      FALSE
16       TRUE
17      FALSE
18      FALSE
LAP
  • 6,605
  • 2
  • 15
  • 28
1

Define an update function f and run it through Reduce.

f <- function(x, i) {
  if (i >= 3 && all(!x[seq(to = i, length = 3)])) x[i] <- TRUE
  x
}
transform(a, new = Reduce(f, init = True_False, seq_along(True_False)))

giving:

   True_False   new
1        TRUE  TRUE
2       FALSE FALSE
3       FALSE FALSE
4       FALSE  TRUE
5       FALSE FALSE
6        TRUE  TRUE
7       FALSE FALSE
8        TRUE  TRUE
9        TRUE  TRUE
10       TRUE  TRUE
11      FALSE FALSE
12      FALSE FALSE
13      FALSE  TRUE
14      FALSE FALSE
15      FALSE FALSE
16      FALSE  TRUE
17      FALSE FALSE
18      FALSE FALSE
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341