如何用base R或dplyr高效按条件填充数据框reGrp列?
高效生成
reGrp列的实现方案(base R & dplyr) 需求规则
reGrp列的取值逻辑如下:
- 当
grpRnk≠2时,直接使用reSeq的值 - 当
grpRnk=2且为首次出现时,使用reSeq的值 - 当
grpRnk=2且为非首次出现时,继承上一行的reGrp值
数据示例
Element grpRnk reSeq reGrp Explanation of reGrp values 1 B NA 1.1 1.1 since grpRnk <> 2, use reSeq value 2 R NA 1.1 1.1 since grpRnk <> 2, use reSeq value 3 R 2 2.0 2.0 since grpRnk = 2 and it is the first instance of grpRnk 2, use reSeq value 4 R 2 3.0 2.0 since grpRnk = 2 and it is not the first instance of grpRnk 2, borrow the reGrp value from the row above 5 B NA 1.2 1.2 since grpRnk <> 2, use reSeq value 6 X 1 1.1 1.1 since grpRnk <> 2, use reSeq value 7 X 1 1.2 1.2 since grpRnk <> 2, use reSeq value
现有实现代码
library(dplyr) data <- data.frame( Element = c("B","R","R","R","B","X","X"), grpRnk = c(NA,NA,2,2,NA,1,1), reSeq = c(1.1,1.1,2,3,1.2,1.1,1.2) ) data %>% mutate(reGrp = ifelse(grpRnk == 2 & is.na(lag(grpRnk)),reSeq,NA)) %>% mutate(reGrp = ifelse(is.na(reGrp) & grpRnk == lag(grpRnk) & grpRnk ==2,lag(reGrp),reGrp)) %>% mutate(reGrp = ifelse(is.na(reGrp),reSeq,reGrp))
优化方案
1. dplyr 单步逻辑实现
利用case_when定义初始值,结合fill函数完成连续值填充,仅需两次操作即可完成,避免重复改写同一列:
library(dplyr) library(tidyr) data %>% mutate( reGrp = case_when( # 非grpRnk=2的行直接取reSeq grpRnk != 2 ~ reSeq, # 首次出现的grpRnk=2行取reSeq grpRnk == 2 & (lag(grpRnk, default = 0) != 2) ~ reSeq, # 其余grpRnk=2的行暂设为NA TRUE ~ NA_real_ ) ) %>% # 向下填充连续grpRnk=2行的NA值 fill(reGrp, .direction = "down")
2. base R 无依赖实现
通过分组标记和聚合函数直接完成赋值,无需额外包:
data_base <- data # 生成连续grpRnk=2块的分组ID grp_tags <- cumsum(!is.na(data_base$grpRnk) & data_base$grpRnk == 2 & (is.na(lag(data_base$grpRnk)) | lag(data_base$grpRnk) != 2)) # 按规则赋值reGrp data_base$reGrp <- with(data_base, ifelse(grpRnk != 2, reSeq, ave(reSeq, grp_tags, FUN = function(x) x[1])))
内容的提问来源于stack exchange,提问作者Village.Idyot
相关产品推荐
相关产品推荐

