3

根据标题,我做一个简单的例子来测试drop_na {tidyr}

library(tidyr)
library(dplyr)

# (1.) produce a dataset with two POSIX type "ct" and "lt"

data <- data.frame(n = 1:5)
data$ct <- as.POSIXct(Sys.time() + rnorm(5) * 1000)
data$lt <- as.POSIXlt(Sys.time() + rnorm(5) * 1000)
str(data)

# $ n : int  1 2 3 4 5
# $ ct: POSIXct, format: "2018-10-07 03:02:28" ...
# $ lt: POSIXlt, format: "2018-10-07 02:37:26" ...


# (2.) assign the third values of "ct" and "lt" to NA

data[3, c("ct", "lt")] <- NA


# (3.) use different function to remove rows with NA

data %>% is.na()               # identify NAs in both "ct" and "lt"
data %>% drop_na('ct')         # drop NA from "ct"
data %>% drop_na('lt')         # NOT drop NA from "lt"
data[c(1, 2)] %>% na.omit()    # drop NA from "ct"
data[c(1, 3)] %>% na.omit()    # NOT drop NA from "lt"

从上面的结论来看,如果 POSIX-lt 变量中有 NA,则只能is.na()用于删除有 NA 的行。

我大致知道POSIX“ct”和“lt”之间的区别。

  • POSIXct将自 1970 年初以来的秒数表示为数值向量。
  • POSIXlt是表示向量的命名列表。

所以有人可以解释为什么POSIXlt不能用drop_na()and来识别缺失值na.omit()吗?

4

1 回答 1

5

简短的回答:除非你真的需要 POSIXlt,否则使用 POSIXct

更长的答案:

POSIXlt 是一种困难且反复无常的数据结构。看:

> str(c(as.POSIXlt(Sys.time()), NA))
 POSIXlt[1:2], format: "2018-10-07 00:43:06" NA
> unclass(c(as.POSIXlt(Sys.time()), NA))
$sec
[1] 15.78872       NA

$min
[1] 43 NA

$hour
[1]  0 NA
# skipped a few rows

$isdst
[1]  1 -1

$zone
[1] "EEST" ""   
# skipped a few rows 

简而言之,POSIXlt 是一个向量列表,每个向量代表一个日期/时间单位:秒、分钟、小时、天等,还有时区等na.omit。POSIXlt 没有方法,所以na.omit.default使用,它不知道POSIXlt类的细节并将其视为普通列表。

> na.omit(list(NA,NA,NA))
[[1]]
[1] NA

[[2]]
[1] NA

[[3]]
[1] NA

如果你需要一个na.omit方法POSIXlt,你可以写一个。但如果不是真的,它更容易使用POSIXct

一个推论:na.omit也不适用于列表(即,它可以使用但什么都不做)。您可以sapplylapplyna.omit 到列表中,但这也会产生奇怪的结果(NA组件将被替换 logical(0))。它看起来na.omit适用于原子向量或因子以及数据帧。(帮助页面说,它对数据框最有用)。这意味着这na.omit不适用于列表,包括POSIXlt.

最后,为什么要使用 POSIXlt?这个想法(据我所知)是您可以轻松地操纵日期的组件 - 但即使这样也会产生意想不到的结果:

> foo <- as.POSIXlt(Sys.time())
> foo
[1] "2018-10-07 01:06:22 EEST"
> foo$year
[1] 118
> foo$mon
[1] 9
> foo$mon <- 10
> foo
[1] "2018-11-07 01:06:22 EEST"
> foo$year <- 2018
> foo
[1] "3918-11-07 01:06:22 EEST"

因此,如果您需要单独操作日期的组成部分,使用 lubridate 的惊喜会更少。

> library(lubridate)
> year(foo)
[1] 3918
> year(foo) <- 2018
> foo
[1] "2018-11-07 01:06:22 EET"
> month(foo)
[1] 11
> month(foo)<-10
> foo
[1] "2018-10-07 01:06:22 EEST"
于 2018-10-06T21:59:23.297 回答