如何用dplyr的case_when实现不同行调用不同tidyr::extract规则?
按行应用不同正则拆分数据框列的解决方案
问题背景
需要对数据框df的第1-3行,用正则^(.*?_.*?)_(.*)$拆分col1列(按第二个下划线拆分);第4-6行则用正则^(.*?)_(.*)$拆分(按第一个下划线拆分)。之前尝试用case_when结合extract()的写法错误,核心原因是extract()是面向整个数据框的批量操作函数,无法在case_when中逐行返回单个值。
可行实现方法
方法一:拆分数据框分别处理后合并
这种方法逻辑直观,把数据按行号分成两组,分别应用拆分规则后再合并:
library(tidyr) library(dplyr) # 示例数据 df <- tibble(col1 = c("2397_A_run379_CTTGTACT_S119_L004_R1_001", "3779_A_run535_TTATAGCC_S91_L003_R1_001", "4958_BV_run685_GCGTACGT_S89_L005_R1_001", "5126AA_S27_L004_R1_001", "5126AF_S32_L004_R1_001", "5126AL_S38_L004_R1_001")) # 分两组处理后合并 df_processed <- bind_rows( # 处理前3行 df %>% slice(1:3) %>% extract(col1, into = c("col1", "col2"), "^(.*?_.*?)_(.*)$"), # 处理后3行 df %>% slice(4:6) %>% extract(col1, into = c("col1", "col2"), "^(.*?)_(.*)$") ) print(df_processed)
方法二:逐行匹配正则提取
使用rowwise()实现逐行判断,结合stringr::str_match获取匹配结果,再拆分到目标列:
library(tidyr) library(dplyr) library(stringr) # 示例数据 df <- tibble(col1 = c("2397_A_run379_CTTGTACT_S119_L004_R1_001", "3779_A_run535_TTATAGCC_S91_L003_R1_001", "4958_BV_run685_GCGTACGT_S89_L005_R1_001", "5126AA_S27_L004_R1_001", "5126AF_S32_L004_R1_001", "5126AL_S38_L004_R1_001")) df_processed <- df %>% mutate(row_num = row_number()) %>% rowwise() %>% mutate( # 按行号选择正则匹配 match_res = if (row_num <= 3) { str_match(col1, "^(.*?_.*?)_(.*)$") } else { str_match(col1, "^(.*?)_(.*)$") }, # 提取匹配到的分组 col1 = match_res[2], col2 = match_res[3] ) %>% ungroup() %>% # 移除临时列 select(-row_num, -match_res) print(df_processed)
说明
extract()是批量处理数据框的函数,不能在case_when中使用,因为case_when要求每个分支返回单个值,而extract()返回的是数据框。- 方法一适合分组规则明确的场景,代码简洁;方法二更灵活,可应对更复杂的逐行判断逻辑。
内容的提问来源于stack exchange,提问作者LDT
相关产品推荐
相关产品推荐

