使用dplyr :: group_by()查找具有NA的最小日期

wib*_*ley 5 r date na dplyr

我找到了一个组内的最小日期.很多时候,该组仅包括缺少日期(在这种情况下,我更喜欢NA分配的东西).

NA小号似乎正确分配,但他们没有回应is.na(),因为我期望的那样. 当单元格显示为时NA,is.na()输出意外为FALSE.

library(magrittr)
ds_visit <- tibble::tribble(
  ~subject_id,                   ~date,
           1L,  as.Date("2017-01-01" ),
           1L,  as.Date("2017-02-01" ), 

           2L,  as.Date(NA_character_),        
           2L,  as.Date("2017-01-02" ),

           3L,  as.Date(NA_character_),        
           3L,  as.Date(NA_character_),   

           4L,  as.Date(NA_character_),        
           4L,  as.Date(NA_character_)       
)

ds_subject <- ds_visit %>% 
  # as.data.frame() %>% 
  dplyr::group_by(subject_id) %>% 
  dplyr::mutate(
    date_na     = is.na(date),          # Works as expected
    date_min    = min(date, na.rm=T),   # Works as expected

    date_min_na = is.na(date_min)       # Does NOT work as expected.
  ) %>% 
  dplyr::ungroup() # %>% as.data.frame() 
Run Code Online (Sandbox Code Playgroud)

ds_visit看起来不错. ds_subject看起来对我来说是正确的,除了最后一栏.

ds_subject(最后一列的最后四行是意外的.)

# A tibble: 8 x 5
  subject_id date       date_na date_min   date_min_na
       <int> <date>     <lgl>   <date>     <lgl>      
1          1 2017-01-01 F       2017-01-01 F          
2          1 2017-02-01 F       2017-01-01 F          
3          2 NA         T       2017-01-02 F          
4          2 2017-01-02 F       2017-01-02 F          
5          3 NA         T       NA         F         # Should be 'T'?
6          3 NA         T       NA         F         # Should be 'T'?
7          4 NA         T       NA         F         # Should be 'T'?
8          4 NA         T       NA         F         # Should be 'T'?
Run Code Online (Sandbox Code Playgroud)

我没有成功地忽略了几个维度,包括:(a)操作系统,(b)R版本(包括3.4.3补丁),(c)dplyr&rlang版本(包括CRAN和GitHub版本),以及(d)tibblevs. data.frame.作为临时工作(此处未显示),我在找到分钟之前将日期转换为字符,然后转换回日期.

警告消息(从主题3和4生成):即使Inf返回警告消息,也会NA在打印数据集时显示.(这种行为是一致的min(as.Date(NA), na.rm=T)).

1: In min.default(c(NA_real_, NA_real_), na.rm = TRUE) :
  no non-missing arguments to min; returning Inf
2: In min.default(c(NA_real_, NA_real_), na.rm = TRUE) :
  no non-missing arguments to min; returning Inf
Run Code Online (Sandbox Code Playgroud)

对日期列的进一步检查似乎与上面的数据集视图一致.类型是日期,最后四个单元格NA不是无穷大.

> str(ds_subject$date_min)
 Date[1:8], format: "2017-01-01" "2017-01-01" "2017-01-02" "2017-01-02" NA NA NA NA
Run Code Online (Sandbox Code Playgroud)

这是一个错误,还是我滥用了什么?这是相关NA的产生而不是无限?

编辑1

@ eipi10和@mtoto下面的链接帮助我更好地理解.谢谢.我不是很高兴'NA'打印而不是'Inf',但我会试着记住它.

为了解决这个特定的情况,是否有更好的功能base::min()

我想要一个我可以包含在dplyr::mutate()/ dplyr::summarize()子句中的函数,它的行为与SQL类似.(最初的dplyr示例is.na()summarize()替换时仍然存在问题mutate()).

例如:

"
  SELECT 
    subject_id,
    MIN(date) AS date_min
    --MIN(date) OVER (PARTITION BY subject_id) AS date_min --`OVER` not supported by sqlite
  FROM ds_visit
  GROUP BY subject_id
" %>% 
  sqldf::sqldf() %>% 
  tibble::as_tibble() %>% 
  dplyr::mutate(
    # date_min_na_1 = is.na(date_min), #Before conversion back to date (from numeric); same result as below.
    date_min      = as.Date(date_min, "1970-01-01"),
    date_min_na   = is.na(date_min)
  )
Run Code Online (Sandbox Code Playgroud)

丢失的组具有良好的NA值,可以按预期响应is.na():

# A tibble: 4 x 3
  subject_id date_min   date_min_na
       <int> <date>     <lgl>      
1          1 2017-01-01 F          
2          2 2017-01-02 F          
3          3 NA         T          
4          4 NA         T          
Run Code Online (Sandbox Code Playgroud)

编辑2

我看到这个问题在打印类时被标记为RInfDateNA的副本.我看到了很多重叠(我从这个问题中学到了很多,以及我的初始代码是如何产生问题的),但我相信它们是不同的问题.

此问题涉及分组,并NA在没有非缺失值时返回.我完全不感兴趣base::min().如上所述,理想base::min()情况下完全避免使用行为更像SQL的已建立和经过测试的功能/方法.

(虽然我很感激@ alistaire的包装base:min(),如果不存在已建立的功能/方法,我会使用它.)

ali*_*ire 5

问题是minwith na.rm = TRUE和all- NAvalues返回Infmax等效地返回-Inf),但是print.Date没有显示这些值的方法,因此NA即使它不是存储的值,也将其打印为。

min(NA, na.rm = TRUE)
#> Warning in min(NA, na.rm = TRUE): no non-missing arguments to min;
#> returning Inf
#> [1] Inf

x <- min(as.Date(NA), na.rm = TRUE)
#> Warning in min.default(structure(NA_real_, class = "Date"), na.rm = TRUE):
#> no non-missing arguments to min; returning Inf

x
#> [1] NA

is.na(x)
#> [1] FALSE

x == Inf
#> [1] TRUE
Run Code Online (Sandbox Code Playgroud)

如果愿意,可以重新定义打印方法,以便按自己喜欢的方式打印,例如

print.Date <- function(x, ...){
    if(x == Inf | x == -Inf) {
        print(as.numeric(x))
    } else {
        base::print.Date(x, ...)
    }
}

x
#> [1] Inf
Run Code Online (Sandbox Code Playgroud)

要真正获得所需的结果,请指定所有值均应返回的值NA

library(tidyverse)

ds_visit <- data_frame(subject_id = c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L), 
                       date = as.Date(c("2017-01-01", "2017-02-01", NA, "2017-01-02", NA, NA, NA, NA)))

ds_visit %>% 
    group_by(subject_id) %>% 
    summarise(date_min = if(all(is.na(date))) NA else min(date, na.rm = TRUE), 
              date_min_na = is.na(date_min))
#> # A tibble: 4 x 3
#>   subject_id date_min   date_min_na
#>        <int> <date>     <lgl>      
#> 1          1 2017-01-01 FALSE      
#> 2          2 2017-01-02 FALSE      
#> 3          3 NA         TRUE       
#> 4          4 NA         TRUE
Run Code Online (Sandbox Code Playgroud)

它不是那么简洁,但是在行为上是完全可以预见的。

  • 为什么这被否决?它实现了我的目标(而且,不发出警告是奖励)。有我没有意识到的危险吗? (2认同)