为什么dplyr的mutate()会改变时间格式?

时间:2015-09-01 16:36:23

标签: r dplyr readr

我使用readr读取包含时间格式的日期列的数据。我可以使用col_types的{​​{1}}选项正确阅读。

readr

这很好。但是,如果我想使用library(dplyr) library(readr) sample <- "time,id 2015-03-05 02:28:11,1674 2015-03-03 13:10:59,36749 2015-03-05 07:55:48,NA 2015-03-05 06:13:19,NA " mydf <- read_csv(sample, col_types="Ti") mydf time id 1 2015-03-05 02:28:11 1674 2 2015-03-03 13:10:59 36749 3 2015-03-05 07:55:48 NA 4 2015-03-05 06:13:19 NA 操作此列,则时间列会丢失其格式。

dplyr

为什么会这样?

我知道我可以通过将它转换为字符来解决这个问题,但如果不来回转换会更方便。

mydf %>% mutate(time = ifelse(is.na(id), NA, time))
        time    id
1 1425522491  1674
2 1425388259 36749
3         NA    NA
4         NA    NA

2 个答案:

答案 0 :(得分:20)

导致此问题的实际是ifelse(),而不是dplyr::mutate()help(ifelse) -

中显示了属性剥离问题的一个示例
## ifelse() strips attributes
## This is important when working with Dates and factors
x <- seq(as.Date("2000-02-29"), as.Date("2004-10-04"), by = "1 month")
## has many "yyyy-mm-29", but a few "yyyy-03-01" in the non-leap years
y <- ifelse(as.POSIXlt(x)$mday == 29, x, NA)
head(y) # not what you expected ... ==> need restore the class attribute:
class(y) <- class(x)

所以你有它。如果你想使用ifelse(),这需要额外的工作。以下两种可能的方法可以让您在没有ifelse()的情况下获得所需的结果。第一个非常简单,使用is.na<-

## mark 'time' as NA if 'id' is NA
is.na(mydf$time) <- is.na(mydf$id)

## resulting in
mydf
#                  time    id
# 1 2015-03-05 02:28:11  1674
# 2 2015-03-03 13:10:59 36749
# 3                <NA>    NA
# 4                <NA>    NA

如果您不想选择该路线,并希望继续使用dplyr方法,则可以使用replace()代替ifelse()

mydf %>% mutate(time = replace(time, is.na(id), NA))
#                  time    id
# 1 2015-03-05 02:28:11  1674
# 2 2015-03-03 13:10:59 36749
# 3                <NA>    NA
# 4                <NA>    NA

数据:

mydf <- structure(list(time = structure(c(1425551291, 1425417059, 1425570948, 
1425564799), class = c("POSIXct", "POSIXt"), tzone = ""), id = c(1674L, 
36749L, NA, NA)), .Names = c("time", "id"), class = "data.frame", row.names = c(NA, 
-4L))

答案 1 :(得分:1)

if_else中有@hadleydplyr的另一个版本。它可以正确管理时间变量。还要查看this github issue