如果找到特定字符,则用 NA 替换整个值

Replace whole value by NA if specific character is found

如果在当前值 f.e 中找到特定字符,我想用 NA 替换特定行中的值。如果值包含“<”(小于),则 f.e。 "<7.5" 我想用 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。

谁能帮帮我?

谢谢!

na_if 不会在 y 中占用一个以上的元素。我们可以在 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)))

只需将列转换为数字,非数字的组件将转换为 NA。这将生成警告,但它们可以被抑制。

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

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

第四种方法将任何以 < 开头的组件替换为 <,然后使用 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"

我也发现 na_if() 不够灵活,所以我经常使用我自己的版本 na_predicate()。它有两个参数:要编辑的向量,以及 returns 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 创建