如何用R拆分数据框中+分隔内容并生成对应多行记录
解决方案
这里提供两种实现方式,分别基于tidyverse工具包和Base R,都能满足需求:
方法一:使用tidyverse工具包
tidyverse的函数组合可以更简洁地实现数据处理逻辑:
library(tidyverse) # 原数据框 df <- data.frame(Gene= c("A", "B", "C","D","E","F"), G1=c("GH13_22+CBM4", "GH109+PL7+GH9","GT57", "AA3","",""), G2=c("GH13_22","","GT57+GH15","AA3", "GT41","PL+PL2"), G3=c("GH13", "GH1O9","", "CBM34+GH13+CBM48", "GT41","GH16+CBM4+CBM54+CBM32")) # 处理逻辑 df2 <- df %>% group_by(Gene) %>% mutate( # 拆分各列的"+"分隔内容,空字符串转为空列表 G1_list = str_split(G1, "\\+") %>% map(~ if(.x == "") character(0) else .x), G2_list = str_split(G2, "\\+") %>% map(~ if(.x == "") character(0) else .x), G3_list = str_split(G3, "\\+") %>% map(~ if(.x == "") character(0) else .x), # 计算当前Gene组需要扩展的最大行数 max_rows = max(lengths(G1_list), lengths(G2_list), lengths(G3_list)) ) %>% # 按最大行数扩展每组的行数 uncount(max_rows) %>% # 生成行索引,用于提取对应位置的元素 mutate(row_idx = row_number()) %>% # 提取元素,超出拆分长度的位置填空字符串 mutate( G1 = map2_chr(G1_list, row_idx, ~ if(.y <= length(.x)) .x[.y] else ""), G2 = map2_chr(G2_list, row_idx, ~ if(.y <= length(.x)) .x[.y] else ""), G3 = map2_chr(G3_list, row_idx, ~ if(.y <= length(.x)) .x[.y] else "") ) %>% # 移除辅助列 select(-G1_list, -G2_list, -G3_list, -max_rows, -row_idx) %>% ungroup() # 查看结果 print(df2)
方法二:使用Base R
如果不想加载第三方包,Base R的循环处理也能实现需求:
# 原数据框(设置stringsAsFactors=FALSE确保字符类型) df <- data.frame(Gene= c("A", "B", "C","D","E","F"), G1=c("GH13_22+CBM4", "GH109+PL7+GH9","GT57", "AA3","",""), G2=c("GH13_22","","GT57+GH15","AA3", "GT41","PL+PL2"), G3=c("GH13", "GH1O9","", "CBM34+GH13+CBM48", "GT41","GH16+CBM4+CBM54+CBM32"), stringsAsFactors = FALSE) result_list <- list() # 循环处理每个Gene for(g in unique(df$Gene)){ sub_df <- df[df$Gene == g, ] # 拆分各列内容,空字符串转为空向量 g1_split <- if(sub_df$G1 == "") character(0) else strsplit(sub_df$G1, "\\+")[[1]] g2_split <- if(sub_df$G2 == "") character(0) else strsplit(sub_df$G2, "\\+")[[1]] g3_split <- if(sub_df$G3 == "") character(0) else strsplit(sub_df$G3, "\\+")[[1]] # 计算当前Gene需要的最大行数 max_len <- max(length(g1_split), length(g2_split), length(g3_split)) # 扩展各列,不足的位置填空字符串 g1_expand <- c(g1_split, rep("", max_len - length(g1_split))) g2_expand <- c(g2_split, rep("", max_len - length(g2_split))) g3_expand <- c(g3_split, rep("", max_len - length(g3_split))) # 生成当前Gene的结果子框 sub_result <- data.frame(Gene = rep(g, max_len), G1 = g1_expand, G2 = g2_expand, G3 = g3_expand, stringsAsFactors = FALSE) result_list[[g]] <- sub_result } # 合并所有子数据框并重置行名 df2 <- do.call(rbind, result_list) rownames(df2) <- NULL # 查看结果 print(df2)
两种方法最终生成的df2都与你给出的期望输出完全一致。
内容的提问来源于stack exchange,提问作者Umar
相关产品推荐
相关产品推荐

