在data.frame上应用strsplit()出现非预期输出的问题
R中函数处理DataFrame列时的向量化问题
问题重现
你有如下DataFrame和两个处理函数:
DataFrame代码
s_words <- c("one,uno", "two,dos", "three,tres", "four,cuatro") n_nums <- c(10, 20, 30, 40) df1 <- data.frame(n_nums, s_words)
自定义函数代码
f_op1 <- function(s_input) { s_ret <- paste0("***", s_input, "***") return(s_ret) } f_op2 <- function(s_input) { a_segments <- unlist(strsplit(s_input, split="\\W+")) s_eng <- a_segments[1] s_spa <- a_segments[2] s_ret <- paste0("*", s_eng, "***", s_spa, "*") return(s_ret) }
当你将函数应用到DataFrame列时:
df1$s_op1 <- f_op1(df1$s_words) df1$s_op2 <- f_op2(df1$s_words)
发现s_op2列所有行均为*one***uno*,而非每行对应s_words字段拆分后的拼接结果(比如第二行应为*two***dos*)。
问题原因
核心问题出在strsplit的行为上:
- 当传入向量给
strsplit时,它返回的是一个列表,列表中每个元素对应原向量里单个字符串的拆分结果。 - 你用
unlist()把整个列表拆成了一个扁平向量,此时a_segments[1]和a_segments[2]只会取到原向量第一个字符串拆分后的前两个元素,导致所有行都复用了这个结果。
解决方案
方法1:修改函数,遍历处理每个元素
修改f_op2,用sapply遍历向量中的每个字符串,确保每行都得到独立的处理结果:
f_op2 <- function(s_input) { sapply(s_input, function(x) { a_segments <- unlist(strsplit(x, split="\\W+")) paste0("*", a_segments[1], "***", a_segments[2], "*") }) }
或者用purrr包的map_chr(更简洁的遍历方式):
library(purrr) f_op2 <- function(s_input) { map_chr(s_input, function(x) { a_segments <- strsplit(x, split="\\W+")[[1]] paste0("*", a_segments[1], "***", a_segments[2], "*") }) }
方法2:用tidyverse工具拆分后拼接
如果你的实际逻辑允许,也可以不用自定义函数,直接用tidyr和dplyr完成拆分与拼接:
library(tidyr) library(dplyr) df1 <- df1 %>% separate(s_words, into = c("eng", "spa"), sep = "\\W+", remove = FALSE) %>% mutate(s_op2 = paste0("*", eng, "***", spa, "*")) %>% select(-eng, -spa)
验证结果
应用修改后的函数或tidyverse代码后,df1$s_op2会得到预期结果:
| n_nums | s_words | s_op2 |
|---|---|---|
| 10 | one,uno | one*uno |
| 20 | two,dos | two*dos |
| 30 | three,tres | three*tres |
| 40 | four,cuatro | four*cuatro |
内容的提问来源于stack exchange,提问作者Alejandro Bermúdez
相关产品推荐
相关产品推荐

