如何用R语言实现按特定字符拆分字符串并转换数据框?
R语言:将指定数据转换为目标格式的方法
需求示例
原始数据:
data <- data.frame(ID = 1, Info = "Zebra fish (one)--Hello; blah", Value = 7)
目标格式:
new_data <- data.frame(ID = 1, CATEGORY = "Zebra Fish", TYPE1 = "one", TYPE2 = "Hello", Value = 7)
问:有没有可实现上述转换的工具函数?自己编写的代码无法正常运行,代码如下:
# Function to parse the info column parse_info <- function(info) { # Split by parentheses and dashes parts1 <- unlist(strsplit(info, "\\(|\\)")) category <- trimws(parts1[1]) type1 <- trimws(parts1[2]) # Further split by dashes and semicolons parts2 <- unlist(strsplit(parts1[3], "--|;")) type2 <- trimws(parts2[1]) return(c(category, type1, type2)) } # Apply the function to each row parsed <- t(apply(data, 1, function(row) { c(row['ID'], parse_info(row['Info']), row['Value']) })) # Create a new data frame new_data <- as.data.frame(parsed, stringsAsFactors = FALSE) names(new_data) <- c("ID", "CATEGORY", "TYPE1", "TYPE2", "VALUE")
问题分析
你写的代码存在几个核心问题:
apply(data, 1, ...)会把数据框的行强制转为字符向量,导致ID和Value丢失数值类型- 字符串分割后
parts1[3]的内容是--Hello; blah,用--|;分割后parts2[1]为空字符串,无法提取出Hello - 目标格式的
CATEGORY要求首字母大写(Zebra Fish),原始数据是Zebra fish,代码未处理大小写转换
解决方案
方法1:用tidyr::extract实现(简洁高效)
借助tidyverse工具包的extract函数,通过正则表达式直接提取分组,一步完成转换:
library(tidyverse) new_data <- data %>% extract( Info, into = c("CATEGORY", "TYPE1", "TYPE2"), regex = "(.*?)\\s*\\((.*?)\\)--(.*?);.*", remove = FALSE # 可选参数,保留原Info列 ) %>% mutate( CATEGORY = str_to_title(CATEGORY), # 自动将每个单词首字母大写 ID = as.integer(ID), Value = as.integer(Value) ) %>% select(ID, CATEGORY, TYPE1, TYPE2, Value)
方法2:修复原有自定义函数
调整字符串处理逻辑,同时保留数据类型:
library(dplyr) parse_info <- function(info) { # 提取括号前的分类内容并处理大小写 category <- str_extract(info, "^.*?(?=\\s*\\()") %>% trimws() %>% str_to_title() # 提取括号内的TYPE1内容 type1 <- str_extract(info, "(?<=\\().*?(?=\\))") %>% trimws() # 提取--和;之间的TYPE2内容 type2 <- str_extract(info, "(?<=--).*?(?=;)") %>% trimws() return(data.frame(CATEGORY = category, TYPE1 = type1, TYPE2 = type2, stringsAsFactors = FALSE)) } new_data <- data %>% rowwise() %>% bind_cols(parse_info(Info)) %>% ungroup() %>% select(ID, CATEGORY, TYPE1, TYPE2, Value)
方法3:基础R原生实现(无需额外包)
parse_info <- function(info) { # 提取分类内容 category <- sub("\\s*\\(.*", "", info) %>% trimws() # 手动处理首字母大写 category <- gsub("(^|\\s)([a-z])", "\\1\\U\\2", category, perl = TRUE) # 提取TYPE1 type1 <- sub(".*\\((.*?)\\).*", "\\1", info) %>% trimws() # 提取TYPE2 type2 <- sub(".*--(.*?);.*", "\\1", info) %>% trimws() return(list(CATEGORY = category, TYPE1 = type1, TYPE2 = type2)) } # 逐行处理并合并结果 parsed_list <- lapply(1:nrow(data), function(i) { row <- data[i, ] parsed <- parse_info(row$Info) data.frame( ID = row$ID, CATEGORY = parsed$CATEGORY, TYPE1 = parsed$TYPE1, TYPE2 = parsed$TYPE2, Value = row$Value, stringsAsFactors = FALSE ) }) new_data <- do.call(rbind, parsed_list)
以上三种方法均可生成符合要求的new_data格式。
内容的提问来源于stack exchange,提问作者bvowe
相关产品推荐
相关产品推荐

