如何按F/P/C标签拆分数据集列,多匹配时生成其余列重复的多行?
R实现:拆分多标签字符串列并生成多行数据
问题描述
我有一个数据集,其中某一列的值为字符串,格式为:F: 任意内容; F: 任意内容; P: 任意内容; P: 任意内容; C:任意内容; C: 任意内容;。需要将该列拆分为F、P、C三列,当存在多个F(或P、C)时,需为每个匹配项生成一行,其余列保持不变。
示例输入
Name Value GOs Ab1 1000 "F: f1; F: f2; P: p1" Bb1 2000 "P: p1; F: f1" Cb1 3000 "C: c1; F: f1"
期望输出
Name Value F P C Ab1 1000 f1 p1 - Ab1 1000 f2 p1 - Bb1 2000 f1 p1 - Cb1 3000 f1 - c1
尝试使用str_match(a, "F:\\s*(.*?)\\s*;")仅能匹配第一个结果,需要获取所有匹配项。测试数据集代码:
df <- data.frame(Name = c("A","B","C"),Value = c(10,20,30),GOs= c("F: f1; F: f2; P: p1","P: p1; F: f1","C: c1; F: f1"))
解决方案
使用stringr包的str_extract_all获取所有匹配项,结合dplyr的行处理与展开功能实现需求,完整代码如下:
library(dplyr) library(stringr) # 加载测试数据 df <- data.frame(Name = c("A","B","C"),Value = c(10,20,30),GOs= c("F: f1; F: f2; P: p1","P: p1; F: f1","C: c1; F: f1")) # 处理流程 result <- df %>% # 提取所有F、P、C对应的内容,生成列表列 mutate( F = str_extract_all(GOs, "(?<=F:\\s).*?(?=\\s*;|$)"), P = str_extract_all(GOs, "(?<=P:\\s).*?(?=\\s*;|$)"), C = str_extract_all(GOs, "(?<=C:\\s).*?(?=\\s*;|$)") ) %>% # 按行处理,统一各列表列的长度 rowwise() %>% mutate( max_len = max(length(F), length(P), length(C)), # 空列表替换为"-",短列表填充至最长长度 F = if (length(F) == 0) rep("-", max_len) else rep(F, length.out = max_len), P = if (length(P) == 0) rep("-", max_len) else rep(P, length.out = max_len), C = if (length(C) == 0) rep("-", max_len) else rep(C, length.out = max_len) ) %>% ungroup() %>% # 将列表列展开为多行 unnest(c(F, P, C)) %>% # 移除临时列和原GOs列 select(-GOs, -max_len) # 输出结果 print(result)
关键说明
str_extract_all:通过正则表达式的正向零宽断言,精准捕获每个标签后的内容,一次性获取所有匹配项,解决了str_match仅匹配第一个结果的问题。- 行内统一长度:按行计算当前行F/P/C列表的最大长度,将短列表重复填充到相同长度,确保展开时每行的标签值一一对应。
unnest:将列表列拆分为多行,每个标签匹配项单独占一行,同时保留原数据的其他列内容。
内容的提问来源于stack exchange,提问作者Isidro Sobrino
相关产品推荐
相关产品推荐

