如何用dplyr按行对R数据框的字符串执行减法运算?
问题:使用dplyr从字符串列中移除对应另一列的内容
我有一个包含x、y两列的R数据框,需要生成第三列new,实现从y列的字符串中移除x列对应的字符串。场景限制无法使用拆分/分隔方法,示例数据如下:
x <- c("FRANCE","GERMANY","RUSSIA") y <- c("Paris FRANCE", "Berlin GERMANY", "Moscow RUSSIA") cities <- data.frame(x,y)
生成的cities数据框:
> cities x y 1 FRANCE Paris FRANCE 2 GERMANY Berlin GERMANY 3 RUSSIA Moscow RUSSIA
期望得到的结果:
x y new 1 FRANCE Paris FRANCE Paris 2 GERMANY Berlin GERMANY Berlin 3 RUSSIA Moscow RUSSIA Moscow
我尝试过的方法均未成功:
- 使用
setdiff(x,y)得到的结果与需求相反,移除了城市保留了国家:
cities %>% mutate(new = setdiff(x,y))
结果:
x y new 1 FRANCE Paris FRANCE FRANCE 2 GERMANY Berlin GERMANY GERMANY 3 RUSSIA Moscow RUSSIA RUSSIA
- 反向使用
setdiff(y,x)得到的是原始数据:
cities %>% mutate(new = setdiff(y,x))
结果:
x y new 1 FRANCE Paris FRANCE Paris FRANCE 2 GERMANY Berlin GERMANY Berlin GERMANY 3 RUSSIA Moscow RUSSIA Moscow RUSSIA
- 使用
gsub(x,"",y)仅对第一行有效,且触发警告:
cities %>% mutate(new = gsub(x,"",y))
警告信息:
Warning message: In gsub(x, "", y) : argument 'pattern' has length > 1 and only the first element will be used
结果:
x y new 1 FRANCE Paris FRANCE Paris 2 GERMANY Berlin GERMANY Berlin GERMANY 3 RUSSIA Moscow RUSSIA Moscow RUSSIA
正确的解决方案
问题核心在于gsub默认是向量级别的批量处理,而非逐行匹配x和y的对应元素。我们需要让函数逐行处理每一组x和y,这里有三种常用的可行方法:
方法1:dplyr::rowwise() + gsub
rowwise()会让后续的mutate按行执行,确保每一行的x都对应当前行的y进行替换,再用trimws()清理替换后多余的空格:
library(dplyr) cities %>% rowwise() %>% mutate(new = trimws(gsub(x, "", y))) %>% ungroup() # 记得取消按行分组,避免影响后续操作
方法2:purrr::map2()逐行映射
如果习惯使用tidyverse的purrr工具包,map2可以同时遍历x和y两个向量,实现逐行的字符串替换:
library(dplyr) library(purrr) cities %>% mutate(new = trimws(map2_chr(x, y, ~gsub(.x, "", .y))))
方法3:stringr::str_remove() + rowwise()
stringr是tidyverse中专门处理字符串的工具包,语法更直观易懂:
library(dplyr) library(stringr) cities %>% rowwise() %>% mutate(new = trimws(str_remove(y, x))) %>% ungroup()
以上三种方法都能得到你期望的结果,trimws()是关键步骤,用来移除替换后字符串前后残留的空格。
内容的提问来源于stack exchange,提问作者Forge
相关产品推荐
相关产品推荐

