R语言杂乱dataframe分块标记行提取为新增标识符列的实现方法
问题描述
现有一个格式杂乱的dataframe,结构为多个观测块循环出现,每个观测块的最后一行是对应块的标记行。该数据来自不可修改/重编程的设备输出,已从存储杂乱字符串的val列中提取出多类字段。
需求为通过匹配标记行中的PD字段识别标记行,将每个块的标记行内容作为标识符存入新增的part列,最终仅保留各块的有效观测行,实现逻辑不受每块观测数量、块总数量限制。
输入示例数据
val<-c("Settle0.90s10.0073", "Settle0.80s10.0070", "Settle0.70s10.0067"," 10/22/2110:51:4100PROG 0 PD Pass 0.0150", "Settle0.90s10.0073", "Settle0.80s10.0070", "Settle0.70s10.0067", "10/22/2110:52:0300PROG 0 PD Pass 0.0086") type<-c("Settle", "Settle", "Settle",NA,"Settle", "Settle", "Settle",NA) time_sec<-c(0.90,0.80,0.70,"10/22",0.90,0.80,0.70,"10/22") sec<-c("s","s","s",NA,"s","s","s",NA) press_psi<-c(10.0073,10.0070, 10.0067,NA,10.0073,10.0070, 10.0067,NA) df<-data.frame(val,type,time_sec,press_psi)
期望输出效果
val<-c("Settle0.90s10.0073", "Settle0.80s10.0070", "Settle0.70s10.0067", "Settle0.90s10.0073", "Settle0.80s10.0070", "Settle0.70s10.0067") type<-c("Settle", "Settle", "Settle","Settle", "Settle", "Settle") time_sec<-c(0.90,0.80,0.70,0.90,0.80,0.70) sec<-c("s","s","s","s","s","s") press_psi<-c(10.0073,10.0070, 10.0067,10.0073,10.0070, 10.0067) part<-c("10/22/2110:51:4100PROG 0 PD Pass 0.0150", "10/22/2110:51:4100PROG 0 PD Pass 0.0150", "10/22/2110:51:4100PROG 0 PD Pass 0.0150", "10/22/2110:52:0300PROG 0 PD Pass 0.0086", "10/22/2110:52:0300PROG 0 PD Pass 0.0086", "10/22/2110:52:0300PROG 0 PD Pass 0.0086") df<-data.frame(val,type,time_sec,press_psi,part)
现有实现问题
已写代码可拆分出各块的有效观测:
lapply(split(df, cumsum(grepl("PD", df$val))), tail, -1)
但需要手动为输出列表中每个dataframe新增part列后再合并,希望有更简便的实现方式。
解决方案
方案1:tidyverse实现(最简洁)
通过向上填充的逻辑直接匹配标记值,无需拆分合并:
library(dplyr) library(tidyr) result <- df %>% # 仅标记行赋值part内容,去除多余空白符 mutate(part = ifelse(grepl("PD", val), trimws(val), NA_character_)) %>% # 从下往上填充NA,每个块的有效观测自动匹配对应块的标记值 fill(part, .direction = "up") %>% # 过滤掉标记行,仅保留有效观测 filter(!grepl("PD", val))
方案2:base R实现
无需依赖第三方包:
# 定位所有标记行,提取对应part值 pd_pos <- grep("PD", df$val) pd_val <- trimws(df$val[pd_pos]) # 为每行分配所属块编号 df$block_id <- findInterval(seq(nrow(df)), pd_pos, rightmost.closed = TRUE) # 匹配part值 df$part <- pd_val[df$block_id] # 移除标记行和辅助列,得到最终结果 result <- df[-pd_pos, setdiff(names(df), "block_id")]
两种方案均完全适配任意块长度、任意块总数的场景,仅靠匹配PD识别标记行,无需手动处理列表拆分合并逻辑。
内容的提问来源于stack exchange,提问作者Mushroom Luvin
相关产品推荐
相关产品推荐

