【问题标题】:Replace whole value by NA if specific character is found如果找到特定字符,则用 NA 替换整个值
【发布时间】:2021-12-22 07:22:28
【问题描述】:

如果在当前值 f.e. 中找到特定字符,我想将特定行中的值替换为 NA如果一个值包含“

例子:

Column A: 3, 4, 8, <5.6, 1, 3
Column B: 7, 4, <6, 1, <2.2, 8

应转换为:

Column A: 3, 4, 8, NA, 1, 3
Column B: 7, 4, NA, 1, NA, 8

我在这里 (https://dplyr.tidyverse.org/reference/na_if.html) 找到了这个带有 mutate 和 na_if() 的示例,但它需要匹配整个字符串 f.e.

y <- c("abc", "def", "", "ghi")
na_if(y, "def")

所以“def”将被 NA 替换。但是如果我使用

y <- c("abc", "def", "", "ghi")
na_if(y, "ef")

什么都没有被替换。还有一个例子与

library(dplyr)
data <- starwars
data %>%
  select(name, eye_color) %>%
  mutate(name = na_if(name, "Luke Skywalker")) %>% 
  mutate(eye_color = na_if(eye_color, "unknown")) -> dataedited

这段代码非常适合我,但也需要完全匹配而不是字符串的一部分。 这样我可以手动编辑每一列,也许有一种方法可以跨多列执行此操作。如果 name 包含“sky”或 eye 包含“unkn”,我想将值转换为 NA。

谁能帮帮我?

谢谢!

【问题讨论】:

    标签: r na


    【解决方案1】:

    na_ify 中不会占用一个以上的元素。我们可以在replace 中创建一个逻辑向量来将值替换为NA。对于多列,使用across

    library(dplyr)
    data <- data %>%
       mutate(across(c(name, eye_color),
           ~ replace(.,  . %in% c("Luke Skywalker", "unknown"), NA)))
    

    对于部分匹配,在str_detectgrepl 中使用regex

    library(stringr)
    data <- data %>%
        mutate(across(c(name, eye_color),
           ~ replace(.,   str_detect(., "sky|unkn"), NA)))
    

    【讨论】:

      【解决方案2】:

      我也发现na_if()不够灵活,所以我经常使用自己的版本na_predicate()。它有两个参数:要编辑的向量和返回 TRUEFALSE 的谓词函数。

      根据你的情况,你可以结合dplyr的across(),编辑多列。

      library(dplyr)
      library(stringr)
      
      na_predicate <- function(x, fn) {
        predicate <- rlang::as_function(fn)
        
        x[predicate(x)] <- NA
        
        x
      }
      
      # Example of a simple predicate function. By default, it's applied to the vector
      # to change
      is_even <- function(x) x %% 2 == 0
      
      na_predicate(1:10, is_even)
      #>  [1]  1 NA  3 NA  5 NA  7 NA  9 NA
      
      
      # But you can use the formula notation to make it apply to something else
      # instead
      na_predicate(c("a", "b", "c", "d"), ~ is_even(1:4))
      #> [1] "a" NA  "c" NA
      
      
      
      # Applying it to starwars data. Here's the original:
      original_data <- starwars %>%
        select(name, eye_color, skin_color) %>% 
        head() %>% 
        print()
      #> # A tibble: 6 x 3
      #>   name           eye_color skin_color 
      #>   <chr>          <chr>     <chr>      
      #> 1 Luke Skywalker blue      fair       
      #> 2 C-3PO          yellow    gold       
      #> 3 R2-D2          red       white, blue
      #> 4 Darth Vader    yellow    white      
      #> 5 Leia Organa    brown     light      
      #> 6 Owen Lars      blue      light
         
      
      # And here I'm using na_predicate() to turn any value in the name/eye_color
      # columns that contains an "l" into NA:
      original_data %>% 
        mutate(across(c(name, eye_color),
                      na_predicate, ~ str_detect(., "l")))
      #> # A tibble: 6 x 3
      #>   name        eye_color skin_color 
      #>   <chr>       <chr>     <chr>      
      #> 1 <NA>        <NA>      fair       
      #> 2 C-3PO       <NA>      gold       
      #> 3 R2-D2       red       white, blue
      #> 4 Darth Vader <NA>      white      
      #> 5 Leia Organa brown     light      
      #> 6 Owen Lars   <NA>      light
      

      reprex package (v2.0.1) 于 2021-11-09 创建

      【讨论】:

        【解决方案3】:

        只需将列转换为数字,非数字的组件将转换为 NA。这会产生警告,但可以禁止它们。

        或者在下面的第二种方法中检查是否有非数字非点并使用 NA 为那些,然后转换为数字,在这种情况下,首先不会有警告。

        第三种方法是相同的,只是它假设要转换为 NA 的值都包含&lt;

        第四种方法是用 na_if。

        x <- c(7, 4, "<6", 1, "<2.2", 8)
        
        # 1
        suppressWarnings(as.numeric(x))  
        ## [1]  7  4 NA  1 NA  8
        
        # 2
        as.numeric(ifelse(grepl("[^0-9.]", x), NA, x))
        ## [1]  7  4 NA  1 NA  8
        
        # 3
        as.numeric(ifelse(grepl("<", x), NA, x))
        ## [1]  7  4 NA  1 NA  8
        
        # 4
        library(dplyr)
        as.numeric(na_if(sub("<.*", "<", x), "<"))
        ## [1]  7  4 NA  1 NA  8
        

        如果我们希望将多个值映射到 NA 或正则表达式模式,则使用如下替换:

        y <- head(letters)
        
        # 5
        replace(y, y %in% c("a", "c"), NA)
        ## [1] NA  "b" NA  "d" "e" "f"
        
        # 6
        replace(y, grepl("a|c", y), NA)
        ## [1] NA  "b" NA  "d" "e" "f"
        

        【讨论】:

          猜你喜欢
          • 2013-02-18
          • 2018-12-17
          • 1970-01-01
          • 2019-10-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-11
          • 1970-01-01
          相关资源
          最近更新 更多