如何用dplyr在多条件下计算DataFrame列的滚动最大值或最小值?
问题
我正尝试使用dplyr,按多条件以「滚动方式」计算DataFrame某列每行的最大值。这里的「滚动方式」指计算范围从顶部(第1行)锚定,延伸至当前计算行(而非数组底部)。下方是可复现代码生成的DataFrame,我需要用dplyr重现对应Excel逻辑的目标值。
可复现代码:
library(dplyr) myDF <- data.frame( Names = c("R","R","B","R","X","X"), Group = c(0,1,1,2,2,0), Code1 = c(1,3,8,2,4,5) )
我的尝试代码(曾实现浮动数组版sumifs,但无法实现maxifs/minifs):
myDF %>% mutate(maxIfs = sapply(1:n(), function(x) max(Code1[1:x][(Names[1:x] == Names[x]) & (Group[1:x] == Group[x])])))
编辑后的代码(修正部分问题):
myDF %>% mutate(maxIfs = sapply(1:n(), function(x) max(Code1[1:x][(Names[1:x] == Names[x]) & (Group[1:x] == 0)], 0)))
解决方案
方法1:优化sapply实现
你的编辑后代码已经接近目标,这里优化空值处理逻辑,避免无匹配时返回-Inf:
myDF %>% mutate(maxIfs = sapply(1:n(), function(x) { # 筛选第1行到当前行中,Names匹配且Group为0的Code1值 filtered_vals <- Code1[1:x][Names[1:x] == Names[x] & Group[1:x] == 0] # 无匹配值返回0,否则返回最大值 if (length(filtered_vals) == 0) 0 else max(filtered_vals) }))
方法2:tidyverse风格实现(用purrr替代sapply)
用purrr::map_dbl让代码更符合tidyverse的可读性要求:
library(purrr) myDF %>% mutate(maxIfs = map_dbl(row_number(), ~{ # 取当前行及之前的所有行 current_slice <- slice(., 1:.x) # 筛选符合条件的行 matched_rows <- filter(current_slice, Names == Names[.x], Group == 0) # 计算最大值或返回0 if (nrow(matched_rows) == 0) 0 else max(matched_rows$Code1) }))
方法3:高效分组累积计算(适合大数据集)
如果数据集较大,逐行处理效率偏低,可以按Names分组后用累积逻辑计算:
myDF %>% group_by(Names) %>% mutate( # 标记当前行是否满足Group==0条件 is_valid = Group == 0, # 累积收集符合条件的Code1值 cumulative_codes = accumulate(is_valid, ~if (.y) c(.x, Code1[cur_row()]) else .x), # 计算每个累积列表的最大值,空列表返回0 maxIfs = map_dbl(cumulative_codes, ~if (length(.x) == 0) 0 else max(.x)) ) %>% ungroup() %>% select(-is_valid, -cumulative_codes) # 移除中间辅助列
内容的提问来源于stack exchange,提问作者Village.Idyot
相关产品推荐
相关产品推荐

