在 dplyr 环境 is.na(), na_if(), startsWith(), regex 中设置所有以特定字符串开头的值

set na all values that starts with certain string in dplyr environment is.na(), na_if(), startsWith(), regex

我有几个字符和数值变量的数据框。我想将所有以 0/n( 开头的值设置为 NA 。这些值可能分布在多个列中。

示例:

string <- c("asff", "1\n(", '0asfd', '0\n(asdf)')
num <- c(0,1,2,3)
df <- data.frame(string, num)
##
df
     string num
1      asff   0
2      1\n(   1
3     0asfd   2
4 0\n(asdf)   3

期望的输出:

     string num
1      asff   NA
2      1\n(   1
3        NA   2
4        NA   3

通过以下方式将数值变量快速设置为 NA:

df%>%na_if(., 0)

但是字符串在 na_if() 中似乎并不那么容易工作,因为 na_if() 似乎在正则表达式中不工作,是吗?我试过这样的事情: na_if(., "^0.") na_if(., "0.") na_if(., startsWith("0")),但错误...

也许是一个带有正则表达式的条件dplyr::mutate(.=ifelse()),但是我有这些换行符"\n)",它们或没有被正则表达式中的"."捕获。或者带有 mutate(x = str_replace_all()).

的东西

我可以逐列进行 (df%>%mutate(x = ifelse(startsWith(x, "0"), NA,x )))),但这样的硬编码太多了。我不能将它应用于所有带有 mutate(across(colnames(), ~ifelse(startsWith(., "0"), NA, .))) 的列,因为数字列会触发错误。

如果您可以使用 mutate 对一列执行此操作,则应该可以使用 mutate_at()mutate_all() 对多个列执行此操作,此处解释:https://dplyr.tidyverse.org/reference/mutate_all.html

在不知道您的数据是什么样子的情况下,我认为您希望mutate_all()修改所有包含符合您的条件的数据的列。

在这个使用 iris 数据集的示例中,我们将 5 的所有实例替换为单词 five:

iris %>%
  tibble %>%
  mutate_all(function(x) str_replace(x, '5', 'five'))

# A tibble: 150 x 5
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
   <chr>        <chr>       <chr>        <chr>       <chr>  
 1 five.1       3.five      1.4          0.2         setosa 
 2 4.9          3           1.4          0.2         setosa 
 3 4.7          3.2         1.3          0.2         setosa 
 4 4.6          3.1         1.five       0.2         setosa 
 5 five         3.6         1.4          0.2         setosa 
 6 five.4       3.9         1.7          0.4         setosa 
 7 4.6          3.4         1.4          0.3         setosa 
 8 five         3.4         1.five       0.2         setosa 
 9 4.4          2.9         1.4          0.2         setosa 
10 4.9          3.1         1.five       0.1         setosa 

或者像你的情况,只有当字符串以5开头时,我们才能做到这一点,使用^5正则表达式语言(^表示字符串的开头,5 表示字符串开头的 5).

iris %>%
  tibble %>%
  mutate_all(function(x) str_replace(x, '^5', 'five'))

# A tibble: 150 x 5
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
   <chr>        <chr>       <chr>        <chr>       <chr>  
 1 five.1       3.5         1.4          0.2         setosa 
 2 4.9          3           1.4          0.2         setosa 
 3 4.7          3.2         1.3          0.2         setosa 
 4 4.6          3.1         1.5          0.2         setosa 
 5 five         3.6         1.4          0.2         setosa 
 6 five.4       3.9         1.7          0.4         setosa 
 7 4.6          3.4         1.4          0.3         setosa 
 8 five         3.4         1.5          0.2         setosa 
 9 4.4          2.9         1.4          0.2         setosa 
10 4.9          3.1         1.5          0.1         setosa 

Update 要更改 entire 值,如果它的开头有一个 5,您只需更改str_replace 函数更改为可以更改整个值的函数。在这种情况下,我们使用 ifelse 语句

iris %>%
  tibble %>%
  mutate_all(function(x) ifelse(str_detect(x, '^5'), 'had_five', x))

# A tibble: 150 x 5
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
   <chr>              <dbl> <chr>              <dbl>   <int>
 1 had_five             3.5 1.4                  0.2       1
 2 4.9                  3   1.4                  0.2       1
 3 4.7                  3.2 1.3                  0.2       1
 4 4.6                  3.1 1.5                  0.2       1
 5 had_five             3.6 1.4                  0.2       1
 6 had_five             3.9 1.7                  0.4       1
 7 4.6                  3.4 1.4                  0.3       1
 8 had_five             3.4 1.5                  0.2       1
 9 4.4                  2.9 1.4                  0.2       1
10 4.9                  3.1 1.5                  0.1       1

另一个更新 从您的评论来看,您似乎只想将该函数应用于字符列。为此,您可以将 mutate_all(your_fun) 替换为 mutate_if(is.character, your_fun) - 如本答案开头的帮助文档中所述(同一信息页面描述了 mutate_allmutate_ifmutate_at).

以您的示例数据为例,我们可以将任何以 '0' 开头的内容设置为 NA。我对你的例子感到困惑 - 你想在字符串的开头寻找 '0''0\n(' 吗?无论哪种方式,都是这样做的:

# sample data
string <- c("asff", "1\n(", '0asfd', '0\n(asdf)')
num <- c(0,1,2,3)
df <- data.frame(string, num)


# for only a 0 at the start of the string
df %>% 
  mutate_if(is.character, function(x) ifelse(str_detect(x, '^0'), NA, x))

  string num
1   asff   0
2   1\n(   1
3   <NA>   2
4   <NA>   3


# for '0\n(' at the start of the string
df %>% 
  mutate_if(is.character, function(x) ifelse(str_detect(x, '^0\n\('), NA, x))

  string num
1   asff   0
2   1\n(   1
3  0asfd   2
4   <NA>   3