2015-09-01 11 views
8

Ich benutze readr, um Daten einzulesen, die eine Datumsspalte im Zeitformat enthält. Ich kann es richtig mit der col_types Option von readr lesen.Warum verändert dplyrs muate() das Zeitformat?

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 

Das ist schön. Wenn ich diese Spalte jedoch mit dplyr bearbeiten möchte, verliert die Zeitspalte ihr Format.

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

Warum passiert das?

Ich weiß, dass ich dieses Problem umgehen kann, indem ich es vorher in Zeichen umwandelte, aber es wäre bequemer, ohne hin und her zu transformieren.

mydf %>% mutate(time = as.character(time)) %>% 
    mutate(time = ifelse(is.na(id), NA, time)) 

Antwort

18

Es ist eigentlich ifelse(), die dieses Problem verursacht, nicht dplyr::mutate(). Ein Beispiel für das Problem der Attribut Strippen in help(ifelse) gezeigt -

## 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) 

So dort haben Sie es. Es ist ein bisschen mehr Arbeit, wenn Sie ifelse() verwenden möchten. Hier sind zwei mögliche Methoden, die Sie ohne ifelse() zu Ihrem gewünschten Ergebnis bringen. Der erste ist wirklich einfach und verwendet 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 

Wenn Sie nicht, diesen Weg wählen wollen, und mit dem dplyr Verfahren fortsetzen möchten, können Sie replace() statt ifelse() verwenden.

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 

Daten:

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))