字符串清洗步骤单独运行正常,封装为函数后失效求助
一、双空格问题修复
你遇到的函数执行后出现双空格的问题,根源在于stri_replace_all_regex中多余的空格替换步骤,以及参数设置带来的意外行为:
冗余的空格替换逻辑
你在stri_replace_all_regex中加入了" "替换为" "的规则,但后续的gsub("\\s+", " ", x)已经可以将所有连续空白(包括2个及以上空格)统一替换为单个空格,这一步完全多余。更关键的是,当vectorize=F时,规则按顺序执行,若中间步骤出现多空格(比如替换-为空格后产生双空格)," "替换仅能处理非重叠的双空格,若出现三个空格会变成两个,后续gsub虽能处理,但如果某个环节出错就会遗留双空格。修复后的函数代码
移除stri_replace_all_regex中的" "替换规则,保留核心符号替换即可:preprocess_string <- function(x) { x <- stri_trans_general(x, "upper; latin-ascii") # 转大写+去除重音 # 移除多余的" "替换规则,保留核心符号替换 x <- stri_replace_all_regex(x, c("-", "[.]", "[/]", "[']", "\\bSAINT\\b", "\\bSAINTE\\b"), c(" ", " ", " SUR ", " ", "ST", "STE"), case_insensitive = TRUE, vectorize = FALSE) x <- gsub("\\s+", " ", x) # 统一所有连续空白为单个空格 x <- trimws(x) # 去除首尾空格 return(x) }测试单个字符串:
x <- "le touquet - paris plage" preprocess_string(x) # 输出:"LE TOUQUET PARIS PLAGE"
二、70万行数据性能优化
用mutate+sapply处理70万行耗时超5分钟,核心原因是逐行处理效率极低,且函数中stri_replace_all_regex的vectorize=F参数强制单字符串处理,无法利用stringi的向量化优势。优化方案如下:
改用向量化处理,移除sapply
stringi的所有函数天生支持向量化操作,不需要用sapply逐行调用。直接在mutate中传入整列数据即可:library(dplyr) library(stringi) # 假设数据框为df,待处理列为raw_str df <- df %>% mutate(clean_str = preprocess_string(raw_str))优化替换规则为向量化模式
将vectorize=F改为默认的vectorize=TRUE,并改用命名向量定义替换规则,写法更简洁且效率更高(可使用stringr的str_replace_all简化代码):library(stringr) preprocess_string <- function(x) { x <- stri_trans_general(x, "upper; latin-ascii") # 用命名向量定义替换规则,自动向量化处理 replace_rules <- c( "-" = " ", "[.]" = " ", "[/]" = " SUR ", "[']" = " ", "\\bSAINT\\b" = "ST", "\\bSAINTE\\b" = "STE" ) x <- str_replace_all(x, replace_rules, ignore_case = TRUE) x <- str_squish(x) # 一步完成:去除首尾空格+统一中间连续空格 return(x) }str_squish等价于trimws(gsub("\\s+", " ", x)),代码更简洁且性能相当。
额外性能提升建议
- 确保待处理列为字符类型:若为因子,先转换为字符
df$raw_str <- as.character(df$raw_str),避免因子处理的额外开销。 - 用data.table替代dplyr:百万级数据处理中,
data.table的向量化操作效率更高:library(data.table) setDT(df) df[, clean_str := preprocess_string(raw_str)]
- 确保待处理列为字符类型:若为因子,先转换为字符
内容的提问来源于stack exchange,提问作者Bernard Forgues

