按行检测指定列范围连续非NA值并生成条件判断列
处理R语言数据框的连续非NA值检测需求
样本数据框
df <- data.frame(New=c("X2", "k 5, N 8", "N30","k 6, N 3", "K5", "S12", "K5", "k 1, N 18"), K_10=c(NA, NA, 3, 4,0,2,NA, NA), K_11=c(NA, NA, NA, 4,0,3,NA, NA), K_12=c(NA, 2, NA, NA,0,NA,NA,0), K_13=c(0, 3, 5, NA,0,5,NA,NA), K_14=c(NA, 3, 1, 2,10,10,NA,NA), K_15=c(NA, 2, 3, 5,15,10,NA,2), K_16=c(NA, 10, 1, 6,43,10,NA,56), K_17=c(NA, 5, 1, 3,1,10,NA,23), K_18=c(NA, 6, 4, 2,0,10,NA,12), K_19=c(NA, 3, 8, NA,3,10,NA,90), K_20=c(NA, 3, 19, 2,6,10,NA,59), K_21=c(NA, 3, 10, 2,8,10,NA,11), K_22=c(NA, 3, NA, 2,9,10,NA,10), K_23=c(NA, 3, NA, 2,90,10,NA,9))
需求说明
- 新增列
At_most_5:按行检测K_11至K_18列,判断最长连续非NA值的长度是否≤5,是则为TRUE,否则为FALSE。 - 新增列
Between_2_5:按行检测K_11至K_18列,判断是否存在长度在2到5之间的连续非NA值,是则为TRUE,否则为FALSE。 - 新增列
New_S:仅针对New列符合"k 数字, N 数字"格式的行,判断K_11至K_18列最长连续非NA值长度是否≤5(结果为TRUE/FALSE);其余行标记为Not Applicable。
解决方案代码
library(dplyr) # 定义函数:计算一行中连续非NA的最大长度 get_max_run <- function(x) { run_info <- rle(!is.na(x)) non_na_runs <- run_info$lengths[run_info$values] if (length(non_na_runs) == 0) 0 else max(non_na_runs) } # 定义函数:检查一行中是否存在长度2-5的连续非NA段 get_has_between_run <- function(x) { run_info <- rle(!is.na(x)) non_na_runs <- run_info$lengths[run_info$values] any(non_na_runs >= 2 & non_na_runs <= 5) } # 处理数据框 df_processed <- df %>% rowwise() %>% mutate( # 提取当前行K_11到K_18的所有值 k_segment = list(c_across(K_11:K_18)), # 计算最大连续非NA长度 max_non_na_run = get_max_run(k_segment), # 生成At_most_5列 At_most_5 = max_non_na_run <= 5, # 生成Between_2_5列 Between_2_5 = get_has_between_run(k_segment), # 生成New_S列 New_S = case_when( grepl("k \\d+, N \\d+", New, ignore.case = TRUE) ~ as.character(max_non_na_run <= 5), TRUE ~ "Not Applicable" ) ) %>% ungroup() %>% # 删除临时中间列 select(-k_segment, -max_non_na_run)
验证结果
运行上述代码后,df_processed将与预期结果一致:
print(df_processed) # New K_10 K_11 K_12 K_13 K_14 K_15 K_16 K_17 K_18 K_19 K_20 K_21 K_22 K_23 At_most_5 Between_2_5 New_S # 1 X2 NA NA NA 0 NA NA NA NA NA NA NA NA NA NA TRUE FALSE Not Applicable # 2 k 5, N 8 NA NA 2 3 3 2 10 5 6 3 3 3 3 3 FALSE FALSE FALSE # 3 N30 3 NA NA 5 1 3 1 1 4 8 19 10 NA NA FALSE FALSE Not Applicable # 4 k 6, N 3 4 4 NA NA 2 5 6 3 2 NA 2 2 2 2 TRUE TRUE TRUE # 5 K5 0 0 0 0 10 15 43 1 0 3 6 8 9 90 FALSE FALSE Not Applicable # 6 S12 2 3 NA 5 10 10 10 10 10 10 10 10 10 10 FALSE FALSE Not Applicable # 7 K5 NA NA NA NA NA NA NA NA NA NA NA NA NA NA FALSE FALSE Not Applicable # 8 k 1, N 18 NA NA 0 NA NA 2 56 23 12 90 59 11 10 9 TRUE TRUE TRUE
性能优化(针对数千行数据集)
如果rowwise在大数据量下速度较慢,可改用purrr::pmap逐行处理,性能更优:
library(purrr) # 改用pmap的版本 df_processed <- df %>% mutate( k_segment = pmap(select(., K_11:K_18), c), max_non_na_run = map_dbl(k_segment, get_max_run), At_most_5 = max_non_na_run <=5, Between_2_5 = map_lgl(k_segment, get_has_between_run), New_S = case_when( grepl("k \\d+, N \\d+", New, ignore.case = TRUE) ~ as.character(max_non_na_run <=5), TRUE ~ "Not Applicable" ) ) %>% select(-k_segment, -max_non_na_run)
内容的提问来源于stack exchange,提问作者newfinder
相关产品推荐
相关产品推荐

