【问题标题】:Replace strings in variable using lookup vector使用查找向量替换变量中的字符串
【发布时间】:2019-03-12 12:23:54
【问题描述】:

我有一个带有字符变量的数据框 df 以及 fromvec 和 tovec。

df <- tibble(var = c("A", "B", "C", "a", "E", "D", "b"))

fromvec <- c("A", "B", "C")

tovec <- c("X", "Y", "Z")

在fromvec中使用字符串,在df中检查,然后用tovec中对应的字符串替换,这样df中的“A”被替换为“X”,“B”被替换为“Y”,依此类推,得到desired_df .

desired_df <- tibble(var = c("X", "Y", "Z", "X", "E", "D", "Y"))

我尝试了关注,但没有得到想要的结果!

from_vec <- paste(fromvec, collapse="|") 
to_vec <- paste(tovec, collapse="|") 

undesired_df <- df %>% 
  mutate(var = str_replace(str_to_upper(var), from_vec, to_vec))

即这个

tibble(var = c("X|Y|Z", "X|Y|Z", "X|Y|Z", "X|Y|Z", "E", "D", "X|Y|Z"))

我怎样才能得到所需的_df?

【问题讨论】:

  • 你得到了什么结果?
  • 我得到了这个 tibble(var = c("X|Y|Z", "X|Y|Z", "X|Y|Z", "X|Y|Z", “E”、“D”、“X|Y|Z”))
  • tovec 中的变量替换fromvec 中的变量将产生X, Y, Z, a E D b 的结果,除非您指定您希望结果不区分大小写。如果是这种情况(正如大多数贡献者所假设的那样),请说明。

标签: r dplyr tidyverse stringr


【解决方案1】:

你可以使用chartr

df$var <- chartr(paste(fromvec,collapse=""),
                 paste(tovec,collapse=""),
                 toupper(df$var))
# # A tibble: 7 x 1
#   var  
#   <chr>
# 1 X    
# 2 Y    
# 3 Z    
# 4 X    
# 5 E    
# 6 D    
# 7 Y    

或者我们可以使用recode

library(dplyr)
df$var <- recode(toupper(df$var), !!!setNames(tovec,fromvec))

如果你真的想使用str_replace,你可以这样做:

library(purrr)
library(stringr)
df$var <- reduce2(fromvec, tovec, str_replace, .init=toupper(df$var))

【讨论】:

  • 哇...太优雅了!这也可以使用 str_replace 来完成吗?
  • recode 解决方案中,你能解释为什么三个!!! 而不是两个吗?还是一个?刘海是一个真正的谜。
  • 是的,需要一段时间才能习惯! !!!!! 是完全不同的动物。 !!! 用于列表前面,以将其元素分配给 ... 参数。在这些情况下,基本 R do.call 是必要的。它只能用在被编程理解它的函数中,所以主要是tidyverse函数。在那里查看我的答案和 cmets,如果您需要更多解释,请回到这里:stackoverflow.com/questions/52684613/…
【解决方案2】:

我们可以使用base R

with(df, ifelse(toupper(var) %in% fromvec, 
           setNames(tovec, fromvec)[toupper(var)], var))
#[1] "X" "Y" "Z" "X" "E" "D" "Y"

也可以通过创建逻辑条件写成两行

i1 <- toupper(df$var) %in% fromvec
df$var[i1] <- setNames(tovec, fromvec)[toupper(df$var)[i1]]

或者使用data.table

library(data.table)
setDT(df)[toupper(var) %in% fromvec, var := setNames(tovec, fromvec)[toupper(var)]]

【讨论】:

  • 太好了。谢谢,阿克伦!这也可以使用 stringr 来实现吗?
  • @Geet 我猜下面有一个使用stringr 的答案。可能必须使用ifelse 添加条件
  • 确实如此。谢谢!
【解决方案3】:

使用 stringr 的正确方法是使用 str_replace_all:

mutate(df,str_replace_all(str_to_upper(var),setNames(tovec, fromvec)))

(谢谢,@Moody_Mudskipper!)

【讨论】:

  • 很好,但是让 OP 使用它:mutate(df,str_replace_all(str_to_upper(var),setNames(tovec, fromvec)))
  • 啊!这确实是一个非常有用的技巧!谢谢,@Moody_Mudskipper!
【解决方案4】:

不清楚结果是否不区分大小写。

在我看来,涉及不确定数量的更改的替换(更新)操作最好使用 JOIN 来完成。在这种情况下,它还巩固了在单独的数据框中跟踪更改的良好做法。

不幸的是,tidyverse 没有“更新数据框”功能.... 明显 遗漏。这意味着 tidyverse-ers 必须使用解决方法,coalesce

#JOIN Operation
tibble(fromvec, tovec) %>%                       #< dataframe of changes
  right_join(df, by = c("fromvec" = "var")) %>%  #< join operation
  transmute(var = coalesce(tovec, fromvec))      #< coalesce work-around

# A tibble: 7 x 1
  var  
  <chr>
1 X    
2 Y    
3 Z    
4 a    
5 E    
6 D    
7 b    

如果首选不区分大小写的操作,请考虑在管道中插入str_to_upper

tibble(fromvec, tovec) %>% 
  right_join(df %>% mutate(var = (str_to_upper(var))),  #<modify case 
             by = c("fromvec" = "var")) %>% 
  transmute(var = coalesce(tovec, fromvec))

# A tibble: 7 x 1
  var  
  <chr>
1 X    
2 Y    
3 Z    
4 X    
5 E    
6 D    
7 Y    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-28
    • 2020-07-09
    • 2015-07-17
    • 2011-09-29
    • 2017-06-21
    • 2013-02-16
    相关资源
    最近更新 更多