合并列时如何删除缺失值(NA)?

时间:2019-09-27 12:47:21

标签: r dplyr na

我正在尝试使用Unite函数将5列合并为一个新列。但是,所有行都包含许多NA值,创建的变量看起来像

Mother|NA|NA|NA|NA
NA|NA|Father|Mother|NA
Mother|Father|NA|Stepmother|NA

我尝试使用以下代码将它们团结在一起:

df2 <- df %>%
unite(Parent_full, Parent:Parent5, sep = "|", remove = TRUE, na.rm = TRUE) 

但这给了我以下错误: 错误:TRUE必须求出列的位置或名称,而不是逻辑向量

我也查看了论坛,发现unite的na.rm功能可能未激活?

有一些数据可以重新创建我的数据集

Name <- c('Paul', 'Edward', 'Mary')
Postalcode <- c('4732', '9045', '3476')
Parent <- c('Mother', 'NA', 'Mother')
Parent2 <- c('NA', 'NA', 'Father')
Parent3 <- c('NA', 'Father', 'NA')
Parent4 <- c('NA', 'Mother', 'Stepmother')
Parent5 <- c('NA', 'NA', 'NA')

df <- data.frame(Name, Postalcode, Parent, Parent2, Parent3, Parent4, Parent5)

很想知道没有NA的情况下如何统一我的专栏。

更新:

我现在已经更新了tidyr软件包,并在read_csv命令中添加了“ na = c(“,” NA“)”。

现在

df2 <- df %>%
unite(Parent_full, Parent:Parent5, sep = "|", remove = TRUE, na.rm = TRUE) 

命令有效,但是由于某些原因,值末尾的NA保持不变。现在我的专栏看起来像这样:

Mother|NA
Father|Mother|NA
Mother|Father|Stepmother|NA
Does anyone know what went wrong now?

4 个答案:

答案 0 :(得分:3)

您遇到了几个问题,

1) <textarea matInput id="content-textarea" placeholder="Required" [formControl]="formArray.controls[0]"></textarea> 不是真实的NA(检查NA

2)您的列是因素

在构造数据框时,请使用is.na(df$Parent2)

stringsAsFactors = FALSE

然后替换df <- data.frame(Name, Postalcode, Parent, Parent2, Parent3, Parent4, Parent5, stringsAsFactors = FALSE) 并使用NA

unite

如果数据已经加载,我们可以使用library(dplyr) df %>% na_if('NA') %>% tidyr::unite(Parent_full, Parent:Parent5, sep = "|", na.rm = TRUE) # Name Postalcode Parent_full #1 Paul 4732 Mother #2 Edward 9045 Father|Mother #3 Mary 3476 Mother|Father|Stepmother

进行更改
mutate_if

答案 1 :(得分:2)

您的主要问题是您尚未更新为tidyr 1.0。该错误消息是上一个版本最好使用输入na.rm = TRUE处理的,因为该参数以前不存在。它认为您在...中为其指定了命名参数。

具体来说,只需运行install.packages("tidyr"),它就可以工作。您可能需要先重新启动R,所以tidyr当前未加载。

如果缺少的值是"NA"字符串,那么,正如Ronak指出的那样,您首先需要在它们上使用na_if()。对我来说很奇怪,因为红色突出显示,您的初始代码块使其看起来像是适当的NA。但是,您的reprex代码具有'NA'值,这些值肯定是字符串。无论如何,您说您正在从CSV读入,因此,运行CSV读取代码以便使用na参数或类似参数正确读取NA会更加干净快捷。

对编辑的响应:这似乎是一个错误,没有正确删除联合字符串末尾的NA。好吧,无论如何,修复很容易,并且可能比我们能做的其他任何事情都要好:

df2 <- df %>%
  unite(Parent_full, Parent:Parent5, sep = "|", na.rm = TRUE) %>%
  mutate_at("Parent_full", . %>%
              str_remove("(^|\\|)NA$") %>%
              na_if(""))

这确保了两件事:1)仅由于unite()除去字符串末尾的字母“ NA”,并且在它们前面加了一个管道(如果有) ;和2)如果此处的一行上没有非缺失值,则该值将是正确的NA,而不是"NA"""或您拥有的东西,我认为这就是您想要的。

更新:我发现该错误适用于除NA之外不包含任何列的任何列,即na.rm = TRUE仅从具有至少一个非缺失值的列中删除NA。我已提交了错误报告:https://github.com/tidyverse/tidyr/issues/765

但是,鉴于此,最佳解决方案可能只是删除所有事先都为NA的列。但是,如果这是生产代码,那么这将变得非常棘手,因为您必须指定unite(),以便在之前的步骤中删除任何甚至所有要合并的列时都不会中断。 >

更新2 :作为对错误报告的回应,问题实际上是,所有缺失的列都是逻辑。因此,这是最佳的解决方案:读取字符列,或在合并之前将其强制为字符。完整说明:

library(tidyverse)

Name <- c('Paul', 'Edward', 'Mary')
Postalcode <- c('4732', '9045', '3476')
Parent <- c('Mother', NA, 'Mother')
Parent2 <- c(NA, NA, 'Father')
Parent3 <- c(NA, 'Father', NA)
Parent4 <- c(NA, 'Mother', 'Stepmother')
Parent5 <- c(NA, NA, NA)

(df <- data.frame(Name, Postalcode, Parent, Parent2, Parent3, Parent4, Parent5))
#>     Name Postalcode Parent Parent2 Parent3    Parent4 Parent5
#> 1   Paul       4732 Mother    <NA>    <NA>       <NA>      NA
#> 2 Edward       9045   <NA>    <NA>  Father     Mother      NA
#> 3   Mary       3476 Mother  Father    <NA> Stepmother      NA

(df2 <- df %>%
    mutate_at(vars(Parent:Parent5), as.character) %>% 
    unite(Parent_full, Parent:Parent5, sep = "|", na.rm = TRUE))
#>     Name Postalcode              Parent_full
#> 1   Paul       4732                   Mother
#> 2 Edward       9045            Father|Mother
#> 3   Mary       3476 Mother|Father|Stepmother

reprex package(v0.3.0)于2019-09-27创建

答案 2 :(得分:1)

unite()(和na.rm = TRUE)仅适用于字符列(据我所知)。帮助文档中并未明确指出这一点。

对于因子,它还会返回整数代码而不是因子级别-需要注意的事情。


数字:不会删除NA:

df <- data.frame("to.combine1" = c(NA, 1, 3),
                 "to.combine2" = c(2, NA, 3))

sapply(df, class) #not functional, just illustrative
#> to.combine1 to.combine2 
#>  "numeric"   "numeric"           

unite(df, "combined", to.combine1:to.combine2, sep="_", na.rm = TRUE)
#>   combined
#> 1     NA_2
#> 2     1_NA
#> 3      3_3

因子:不会删除NA,而是使用整数代码而不是级别:

df <- data.frame("to.combine1" = as.character(c(NA, 1, "a")),
           "to.combine2" = as.character(c(2, NA, "a")),
           stringsAsFactors = TRUE)

sapply(df, class) #not functional, just illustrative
#> to.combine1 to.combine2 
#>    "factor"    "factor" 

unite(df, "combined", to.combine1:to.combine2, sep="_", na.rm = TRUE)
#>   combined
#>1     NA_1
#>2     1_NA
#>3      2_2

字符:预期的行为

df <- data.frame("to.combine1" = as.character(c(NA, 1, "a")),
                 "to.combine2" = as.character(c(2, NA, "a")),
                 stringsAsFactors = FALSE)

sapply(df, class) #not functional, just illustrative
#>to.combine1 to.combine2 
#>"character" "character" 

unite(df, "combined", to.combine1:to.combine2, sep="_", na.rm = TRUE)
#>   combined
#> 1        2
#> 2        1
#> 3      a_a

答案 3 :(得分:0)

您可以稍后使用类似的内容删除NA

df %>%
  unite(Parent_full, Parent:Parent5, sep = "|", remove = TRUE) %>% 
  mutate(Parent_full = gsub("(?<![a-zA-Z])NA\\||\\|NA(?![a-zA-Z])|\\|NA$", '', Parent_full, perl = T))
    Name Postalcode              Parent_full
1   Paul       4732                   Mother
2 Edward       9045            Father|Mother
3   Mary       3476 Mother|Father|Stepmother

它以空字符串替换字符串末尾的NA|(不带字母)或|NA(不带字母或|NA