【问题标题】:set na all values that starts with certain string in dplyr environment is.na(), na_if(), startsWith(), regex在 dplyr 环境中设置 na 所有以某个字符串开头的值 is.na()、na_if()、startsWith()、regex
【发布时间】:2021-10-24 00:34:41
【问题描述】:

我有几个字符和数字变量的数据框。我想将所有以 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%&gt;%mutate(x = ifelse(startsWith(x, "0"), NA,x )))) 完成,但这样编码太难了。我无法将其应用于所有带有 mutate(across(colnames(), ~ifelse(startsWith(., "0"), NA, .))) 的列,因为数字列会触发错误。

【问题讨论】:

  • 你能用across吗?例如,df %&gt;% mutate(across(colnames, ~ifelse(startsWith(. "0"), NA, .)))
  • 请提供一个可重现的例子
  • @mikebader:这个解决方案似乎适用于字符列,但由于我的数据框中有数字列,我得到non-character object(s)。所以我只需要将它应用于所有字符列,我需要以自动方式选择

标签: r dplyr na


【解决方案1】:

如果您能够使用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 

更新要更改整个的值,如果它的开头有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

另一个更新从您的 cmets 看来,您似乎只想将该函数应用于字符列。为此,您可以将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

【讨论】:

  • 但我不想只替换字符串开头的 5,而是将所有以 5 开头的记录设置为 NA。所以用 NA 替换整个字符串,如果它以 5
  • 已经用解决方案更新了答案
猜你喜欢
  • 2022-07-15
  • 1970-01-01
  • 2010-09-08
  • 2014-12-02
  • 2010-09-05
  • 2023-03-19
  • 1970-01-01
  • 2020-01-07
  • 1970-01-01
相关资源
最近更新 更多