dplyr mutate ifelse 语句中的 gsub 返回第一个项目而不是选定的项目

gsub in dplyr mutate ifelse statement returning first item rather than selected items

我想 运行 有选择地进行变异,给定可变输入。然后 mutate 需要 运行 chr 列上的 gsub。例如:

thing <- "yes"

starwars %>% mutate(homeworld = 
                    ifelse(thing == "yes", 
                           gsub("oo", "_", homeworld), 
                           homeworld)) %>%
            select(name, homeworld)

上面代码中的 gsub 似乎对 homeworld 的第一项执行替换,并将所有 homeworld 值替换为:

   name               homeworld
   <chr>              <chr>    
 1 Luke Skywalker     Tat_ine  
 2 C-3PO              Tat_ine  
 3 R2-D2              Tat_ine  
 4 Darth Vader        Tat_ine 

我期望的时间:

   name               homeworld
   <chr>              <chr>    
 1 Luke Skywalker     Tat_ine  
 2 C-3PO              Tat_ine  
 3 R2-D2              Nab_
 4 Darth Vader        Tat_ine 

如果我不包含 ifelse 语句,这会起作用:

starwars %>% mutate(homeworld = gsub("oo", "_", homeworld))

使用rowwise

thing <- "yes"

starwars %>%
  rowwise() %>% 
  mutate(homeworld =
           ifelse(thing == "yes",
                  gsub("oo", "_", homeworld),
                  homeworld)) %>%
  select(name, homeworld) %>%
  ungroup()


# A tibble: 87 x 2
   name               homeworld
   <chr>              <chr>    
 1 Luke Skywalker     Tat_ine  
 2 C-3PO              Tat_ine  
 3 R2-D2              Nab_     
 4 Darth Vader        Tat_ine  
 5 Leia Organa        Alderaan 
 6 Owen Lars          Tat_ine  
 7 Beru Whitesun lars Tat_ine  

备注

这个问题已经被诊断出来

问题

根据 R documentation

ifelse() returns a value with the same shape as test.

因为 test 是 (logical) 标量 thing == "yes"

thing == "yes"

# [1] TRUE

那么你的 ifelse() returns 只有 (character) 标量 "Tat_ine"

ifelse(thing == "yes", gsub("oo", "_", starwars$homeworld), starwars$homeworld)

# [1] "Tat_ine" 

它在整个 homeworld 列中作为常量循环使用。

解决方案

可以执行rowwise()操作(使用dplyr),如 by Yuriy Saraykin所述,或者您可以使用[=]有效地矢量化您的条件25=]:

thing <- "yes"

starwars %>% mutate(homeworld = case_when(thing == "yes" ~ gsub("oo", "_", homeworld),
                                          TRUE ~ homeworld)) %>%
  select(name, homeworld)

结果(如下所示)应符合您的预期:

# A tibble: 87 x 2
   name               homeworld
   <chr>              <chr>    
 1 Luke Skywalker     Tat_ine  
 2 C-3PO              Tat_ine  
 3 R2-D2              Nab_     
 4 Darth Vader        Tat_ine  
 5 Leia Organa        Alderaan 
 6 Owen Lars          Tat_ine  
 7 Beru Whitesun lars Tat_ine  
 8 R5-D4              Tat_ine  
 9 Biggs Darklighter  Tat_ine  
10 Obi-Wan Kenobi     Stewjon  
# ... with 77 more rows