r-如何使用带有mutate dplyr的循环



我有一个关于R的dplyr中for循环的问题。假设我有以下数据帧:

id <- c(rep(8, 9))
check <- c(0,1,1,0,0,1,0,0,0)
df <- data.frame(id, check)
df$count_x <- cumsum(df$check)
df$count_y <- NA
df$count_y[1] <- ifelse(df$check[1] == 0, 0, 1)
co <- df$count_y[1]

我想根据以下调整后的累积函数填充变量count_y:

for (idx in 2:nrow(df)){
if(df[idx, 2] == 1 & df[idx - 1, 2] == 0){
co <- 1
df[idx, 4] <- co 
} else if (df[idx, 2] == 1 & df[idx - 1, 2] == 1){
co <- co + 1
df[idx, 4] <- co
} else if (df[idx, 2] == 0){
df[idx, 4] <- co
} 
}

这个for循环的输出是正确的。然而,在我当前的数据集中,我有很多ID,使用for循环来迭代这些ID将花费太多时间。我正在尝试使用dplyr的功能来加快这个过程。

id <- c(rep(8, 9))
check <- c(0,1,1,0,0,1,0,0,0)
df <- data.frame(id, check)
df <- df %>% group_by(id) %>% mutate(count_x = cumsum(check),
count_y = NA) %>% ungroup()
df <- df %>% group_by(id) %>% mutate(count_y = replace(count_y, 1, ifelse(check[1] == 0, 0 , 1)))
count_n <- function(df){
co <- df$count_y[1]
for (idx in 2:nrow(df)){
if(df[idx, 2] == 1 & df[idx - 1, 2] == 0){
co <- 1
df[idx, 4] <- co 
} else if (df[idx, 2] == 1 & df[idx - 1, 2] == 1){
co <- co + 1
df[idx, 4] <- co
} else if (df[idx, 2] == 0){
df[idx, 4] <- co
}
}
}

如上所述,我想使用mutate来调用函数count_n来填充count_y。我知道我只传递一个变量,其中我必须传递一个数据帧,因为该函数依赖于列"check"(第2列(和"count_y"(第4列(。我尝试了多种选择(mutate_at、all等(,但都无法成功。我能做些什么不同的事情?

df <- df %>% group_by(id) %>% mutate_at(vars(count_y), ~count_n(.)) 

我认为这是使用purrr::accumulate2()的最佳情况。

CCD_ 2通常用于计算条件累积和。它将函数作为第二个参数。此函数应该有两个参数:累计输出co和当前计算值x

purrr::accumulate2()允许我们使用第二个变量进行迭代,这里我们使用lag(check)作为lx。棘手的是,第二个变量应该短一项,因为它与初始值无关。

这是与预期输出相匹配的代码。

library(tidyverse)
df = structure(list(id = c(8, 8, 8, 8, 8, 8, 8, 8, 8), 
check = c(0, 1, 1, 0, 0, 1, 0, 0, 0), 
count_x = c(0, 1, 2, 2, 2, 3, 3, 3, 3)), 
row.names = c(NA, -9L), class = "data.frame")

df %>% 
mutate(
count_y = accumulate2(check, lag(check)[-1], function(co, x, lx){
case_when(
x==0 ~ co,
x==1 & lx==0 ~ 1,
x==1 & lx==1 ~ co+1,
TRUE ~ 999 #error value in case of unexpected input
)
})
)
#>   id check count_x count_y
#> 1  8     0       0       0
#> 2  8     1       1       1
#> 3  8     1       2       2
#> 4  8     0       2       2
#> 5  8     0       2       2
#> 6  8     1       3       1
#> 7  8     0       3       1
#> 8  8     0       3       1
#> 9  8     0       3       1

创建于2021-05-05由reprex包(v2.0.0(

第一个问题是函数中没有返回任何内容。第二个问题是,在编写修改整个tibble的函数时,不需要使用mutate_at(甚至不需要使用更适合单个变量的mutate(。让它工作的最简单的方法是添加一个return语句,并在下面的行中运行它:

count_n <- function(df){

co <- df$count_y[1]

for (idx in 2:nrow(df)){
if(df[idx, 2] == 1 & df[idx - 1, 2] == 0){
co <- 1
df[idx, 4] <- co 
} else if (df[idx, 2] == 1 & df[idx - 1, 2] == 1){
co <- co + 1
df[idx, 4] <- co
} else if (df[idx, 2] == 0){
df[idx, 4] <- co
}
}

return(df)
}
df %>% group_by(id) %>% count_n(.)

然而,我会使用Dan上面的答案,因为它更干净,并且具有不运行for循环的优点,这不是很"干净";R〃:(

最新更新