使用 R 应用 ifelse 而不应用 for 循环

Apply ifelse without applying a for loop using R

我有这样的 2 列数据:

v1 = c(0, 29, 32, 29, 32, 28, -59, 30)
v2 = c(0, 0, 0, 0, 1, 1, 0, 1)

data = data.frame(v1, v2)

   v1 v2
1   0  0
2  29  0
3  32  0
4  29  0
5  32  1
6  28  1
7 -59  0
8  30  1

我想按如下方式更改列 v2 的值:如果 v1 的值为负,则将 v2 的所有先前 1 更改为 0。我可以使用 [=11= 应用 for 循环来完成此操作].有没有办法在不应用 for 循环的情况下做同样的事情(可能使用 dplyr 包)?

更新 我的实际问题比我之前解释的情况更普遍。对于造成的混乱,我深表歉意。我的数据可以有多个负值,如给定示例所示:

不需要花哨的东西,找到最后一个 1 并在 2 个步骤中将所有前面的 1 覆盖为零

# Find last one
lastO <- max(which(data$v1))
if(length(last0)){
  # Overwrite all v2 where v2 == 1 and the row is prior to the last row in v1
  data$v2[data$v2 == 1 & seq.int(lastO) < lastO] <- 0
}

一个 dplyr 解决方案 cumsum() 确定 v1 < 0:

的位置
library(dplyr)

data %>%
  mutate(v2 = ifelse(row_number() < which.max(cumsum(v1 < 0)), 0, v2))

   v1 v2
1   0  0
2  29  0
3  32  0
4  29  0
5  32  0
6  28  0
7 -59  0
8  30  1

如果数据有多个负值:

data <- data.frame(v1 = c(0, 29, 32, 60, -30, 31, -31, 31),
                   v2 = c(0,  0,  0,  1,   0,  1,   0,  1))

我的代码给出(result 列):

   v1 v2 result
1   0  0      0
2  29  0      0
3  32  0      0
4  60  1      0
5 -30  0      0
6  31  1      0
7 -31  0      0
8  31  1      1

最后更新:

v1= c(0 , 29,  32 , 60, -30 , 31, -31,  31  )
v2=c(0, 0, 0, 1, 0, 1,0,1)
data=data.frame(v1,v2)
data %>% 
  group_by(group_id = lag(cumsum(v1<0), default=0)) %>% 
  mutate(v2 = lag(cumsum(v1<0), default = min(v2))) %>% 
  ungroup() %>% 
  select(-group_id)
    v1    v2
  <dbl> <dbl>
1     0     0
2    29     0
3    32     0
4    60     0
5   -30     0
6    31     0
7   -31     0
8    31     1

第一个回答: 我们可以使用 lagcumsum:

library(dplyr)
data %>% 
  mutate(v2 = lag(cumsum(v1<0), default = 0))
   v1 v2
1   0  0
2  29  0
3  32  0
4  29  0
5  32  0
6  28  0
7 -59  0
8  30  1