在R语言中不使用group_by处理单列:保留每组首个TRUE其余设为NA
问题
现有一列a仅包含NA和TRUE两种值,需要生成新列a_deduplicated,规则为:保留每段连续TRUE中的第一个TRUE,其余TRUE设为NA,且无其他列可用于分组。
示例效果如下:
| a | a_deduplicated |
|---|---|
| NA | NA |
| NA | NA |
| NA | NA |
| TRUE | TRUE |
| TRUE | NA |
| NA | NA |
| TRUE | TRUE |
| TRUE | NA |
| TRUE | NA |
| NA | NA |
| NA | NA |
| TRUE | TRUE |
| TRUE | NA |
| TRUE | NA |
| TRUE | NA |
测试用数据集:
df <- structure(list(a = c(NA, NA, NA, TRUE, TRUE, NA, TRUE, TRUE, TRUE, NA, NA, TRUE, TRUE, TRUE, TRUE), a_deduplicated = c(NA, NA, NA, TRUE, NA, NA, TRUE, NA, NA, NA, NA, TRUE, NA, NA, NA)), class = c("tbl_df","tbl", "data.frame"), row.names = c(NA, -15L))
解决方案
方法1:Base R 原生实现(利用rle())
rle()函数能快速识别连续重复的序列,适合处理这类连续值标记需求:
# 复制原数据避免修改原始数据 df_result <- df # 对a列进行游程编码 rle_obj <- rle(df_result$a) # 生成目标列的标记向量 output_vec <- unlist(Map(function(val, len) { if (isTRUE(val)) { c(TRUE, rep(NA, len - 1)) } else { rep(NA, len) } }, rle_obj$values, rle_obj$lengths)) # 赋值给新列 df_result$a_deduplicated <- output_vec
方法2:Tidyverse 实现(dplyr包)
如果日常使用tidyverse工具链,可以通过lag()函数对比前后行的值来实现:
library(dplyr) df_result <- df %>% mutate( a_deduplicated = if_else( condition = a == TRUE & lag(a, default = FALSE) != TRUE, true = TRUE, false = NA ) )
验证结果
运行任意一种方法后,可通过以下代码验证结果是否符合预期:
all.equal(df_result$a_deduplicated, df$a_deduplicated) # 输出 TRUE 则表示匹配成功
内容的提问来源于stack exchange,提问作者Oluf Sändrostrom
相关产品推荐
相关产品推荐

