I want to transform the following dataframe without using a loop, changing the value of 'a' in the 1st and every 3rd element after to a value of 5 if the value of 'b' at that row is 1.
df <- data.frame(a =c(2,2,2,2,2,2,2,2,2,2),b = c(1,1,0,1,1,0,0,1,1,1))
df
a b
1 2 1
2 2 1
3 2 0
4 2 1
5 2 1
6 2 0
7 2 0
8 2 1
9 2 1
10 2 1
transforming df such that the value of 'a' at index 1,4,10 of column a is replaced by 5 since the value of 'b' is 1 at index of 1,4,10 in column b
df
a b
1 5 1
2 2 1
3 2 0
4 5 1
5 2 1
6 2 0
7 2 0
8 2 1
9 2 1
10 5 1
I have tried usingdf[(seq(1,to=nrow(df),by=3))]==1
to check for value in 'b' at those specific indexes, but I am not sure how to incorporate it to change the value in 'a' without the use of a loop
CodePudding user response:
You may try
library(dplyr)
df %>%
tibble::rownames_to_column() %>%
rowwise %>%
mutate(rowname = as.numeric(rowname),
a = ifelse((rowname %% 3 == 1) && b == 1 , 5, a)) %>%
select(-rowname)
a b
<dbl> <dbl>
1 5 1
2 2 1
3 2 0
4 5 1
5 2 1
6 2 0
7 2 0
8 2 1
9 2 1
10 5 1
CodePudding user response:
For a base R solution,
df[intersect(seq(1,nrow(df),by=3), which(df$b == 1)),'a'] <- 5
Returns,
> df
a b
1 5 1
2 2 1
3 2 0
4 5 1
5 2 1
6 2 0
7 2 0
8 2 1
9 2 1
10 5 1
CodePudding user response:
You can keep the dplyr
solution to a single line using @Park's calculation.
library(dplyr)
df <- data.frame(a =c(2,2,2,2,2,2,2,2,2,2),b = c(1,1,0,1,1,0,0,1,1,1))
mutate(df, a = ifelse(row_number() %% 3 == 1 & b == 1, 5, a))
#> a b
#> 1 5 1
#> 2 2 1
#> 3 2 0
#> 4 5 1
#> 5 2 1
#> 6 2 0
#> 7 2 0
#> 8 2 1
#> 9 2 1
#> 10 5 1
CodePudding user response:
In base R, you can use
df$a[seq_len(nrow(df)) %% 3 == 1 & df$b == 1] <- 5
df
# a b
#1 5 1
#2 2 1
#3 2 0
#4 5 1
#5 2 1
#6 2 0
#7 2 0
#8 2 1
#9 2 1
#10 5 1