R语言数据框列字符串拆分报错:替换行数不匹配问题求助
你遇到的报错本质是strsplit返回的是列表,而data.frame的普通列默认存储原子向量(单个值/长度相同的向量),直接把列表赋值给单元格会导致R误解你的赋值维度,从而抛出"replacement has x rows, data has y"的错误。下面分几种常见需求给你对应的解决方法:
需求1:保留拆分后的向量作为列表列(每个单元格是一个向量)
如果你希望第二列的每个单元格仍然是拆分后的字符向量(比如c("A", "B", "C", "D", "E")),不需要展开,只需要把列转换为列表列即可:
用base R实现
# 假设第二列名为col2,先获取拆分后的列表,再赋值为列表列 letters$col2 <- as.list(strsplit(letters$col2, split = "\\|"))
这里注意|是正则表达式的特殊字符,所以要用\\|转义(你之前写的[|]也可以,效果一样)。赋值时用as.list()把strsplit返回的列表直接转为data.frame的列表列,这样每个单元格就是一个完整的向量。
用tidyverse(dplyr)实现
如果你习惯用tidyverse工具链,写法更直观:
library(dplyr) letters <- letters %>% mutate(col2 = strsplit(col2, split = "\\|"))
需求2:把拆分后的元素展开成单独的行(长格式)
如果想把每个拆分出的字母单独占一行(比如1行变5行),适合后续做分组统计,用tidyr的separate_rows函数:
library(tidyr) # 生成新的长格式data.frame letters_long <- letters %>% separate_rows(col2, sep = "\\|")
运行后原来的15行会变成对应行数(比如每行拆5个元素的话就是75行),每个字母单独一行。
需求3:把拆分后的元素拆分成多个列(宽格式)
如果想把拆分出的每个字母放到单独的列里(比如1列变5列),用tidyr的separate函数:
library(tidyr) # 生成新的宽格式data.frame,into指定新列名 letters_wide <- letters %>% separate(col2, into = paste0("letter_", 1:5), sep = "\\|", fill = "right")
这里into参数定义了新列的名称,fill = "right"可以处理某些行拆分后元素数量不足的情况(用NA填充)。
为什么你的循环会报错?
你的循环里,strsplit(letters[i,2], split = "[|]")返回的是长度为1的列表,里面才是你要的向量。直接把这个列表赋值给letters[i,2],R会误以为你要替换多行数据,所以报错。如果一定要用循环(不推荐,R是向量优先语言,循环效率低),需要用[[1]]取出列表里的向量,再用list()包裹赋值:
for(i in 1:nrow(letters)){ letters[i,2] <- list(strsplit(letters[i,2], split = "[|]")[[1]]) }
内容的提问来源于stack exchange,提问作者gooseshoes

