使用 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
第一个回答:
我们可以使用 lag
和 cumsum
:
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
我有这样的 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
第一个回答:
我们可以使用 lag
和 cumsum
:
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