Konwersja roku i miesiąca (format „rrrr-mm”) na datę?

91

Mam zbiór danych, który wygląda następująco:

Month    count
2009-01  12
2009-02  310
2009-03  2379
2009-04  234
2009-05  14
2009-08  1
2009-09  34
2009-10  2386

Chcę wykreślić dane (miesiące jako wartości x i liczy się jako wartości y). Ponieważ w danych występują luki, chcę zamienić informacje dla miesiąca na datę. Próbowałem:

as.Date("2009-03", "%Y-%m")

Ale to nie zadziałało. Co jest nie tak? Wygląda na to, że as.Date () wymaga również dnia i nie jest w stanie ustawić standardowej wartości dnia? Która funkcja rozwiązuje mój problem?

R_User
źródło

Odpowiedzi:

57

Spróbuj tego. (Tutaj używamy, text=Linesaby zachować samowystarczalność przykładu, ale w rzeczywistości zastąpilibyśmy go nazwą pliku).

Lines <- "2009-01  12
2009-02  310
2009-03  2379
2009-04  234
2009-05  14
2009-08  1
2009-09  34
2009-10  2386"

library(zoo)
z <- read.zoo(text = Lines, FUN = as.yearmon)
plot(z)

Oś X nie jest tak ładna z tymi danymi, ale jeśli masz więcej danych w rzeczywistości, może być w porządku lub możesz użyć kodu dla fantazyjnej osi X pokazanej w sekcji przykładów ?plot.zoo.

zUtworzona powyżej seria zoo ma "yearmon"indeks czasowy i wygląda następująco:

> z
Jan 2009 Feb 2009 Mar 2009 Apr 2009 May 2009 Aug 2009 Sep 2009 Oct 2009 
      12      310     2379      234       14        1       34     2386 

"yearmon" może być również używany samodzielnie:

> as.yearmon("2000-03")
[1] "Mar 2000"

Uwaga:

  1. "yearmon" obiekty klas są sortowane w porządku kalendarza.

  2. Spowoduje to wykreślenie miesięcznych punktów w równych odstępach czasu, co jest prawdopodobnie pożądane; Jednakże, jeśli to pożądane było wykreślić punkty o nierównych odstępach rozmieszczone w stosunku do liczby dni w każdym miesiącu następnie przekształcić indeks zdo "Date"klasy: time(z) <- as.Date(time(z)).

G. Grothendieck
źródło
76

Ponieważ daty odpowiadają wartości liczbowej i dacie początkowej, rzeczywiście potrzebujesz dnia. Jeśli naprawdę potrzebujesz, aby Twoje dane były w formacie daty, możesz po prostu ustawić dzień na pierwszy dzień każdego miesiąca ręcznie, wklejając go do daty:

month <- "2009-03"
as.Date(paste(month,"-01",sep=""))
Sacha Epskamp
źródło
Jakie są inne formaty dat? Widziałem coś z POSIX i coś z ISO, ale nie jestem pewien, czy to różne formaty. Myślałem, że to tylko funkcje, ...
R_User,
19
Warto zauważyć, że możesz określić dzień jako ten sam w formaterze, dzięki czemu możesz zrobić as.Date(month, format='%Y-%m-01')i osiągnąć ten sam wynik. To „wydaje się” lepsze dla mnie, ponieważ określenie tej samej daty w każdym miesiącu jest bardziej związane z formatem daty niż manipulowaniem ciągiem znaków, ale może to nonsens.
JBecker
21
@JBecker Twoja sugestia nie działa dla mnie. > as.Date("2016-01", format="%Y-%m-01") # [1] NA. Używam R 3.3.1
n8sty
26

Najbardziej zwięzłe rozwiązanie, jeśli chcesz, aby daty były w formacie daty:

library(zoo)
month <- "2000-03"
as.Date(as.yearmon(month))
[1] "2000-03-01"

as.Date naprawi dla ciebie pierwszy dzień każdego miesiąca obiekt yearmon.

Ben Rollert
źródło
23

Możesz to również osiągnąć za pomocą funkcji parse_date_timelub fast_strptimez lubridatepakietu:

> parse_date_time(dates1, "ym")
[1] "2009-01-01 UTC" "2009-02-01 UTC" "2009-03-01 UTC"

> fast_strptime(dates1, "%Y-%m")
[1] "2009-01-01 UTC" "2009-02-01 UTC" "2009-03-01 UTC"

Różnica między tymi dwoma polega na tym, że parse_date_timepozwala na specyfikację formatu w stylu lubridate, podczas gdy fast_strptimewymaga takiej samej specyfikacji formatu, jak strptime.

Aby określić strefę czasową, możesz użyć tzparametru -parameter:

> parse_date_time(dates1, "ym", tz = "CET")
[1] "2009-01-01 CET" "2009-02-01 CET" "2009-03-01 CET"

Jeśli masz nieprawidłowości w swoich danych data-czas, możesz użyć truncatedparametru -parametr, aby określić, ile nieprawidłowości jest dozwolonych:

> parse_date_time(dates2, "ymdHMS", truncated = 3)
[1] "2012-06-01 12:23:00 UTC" "2012-06-01 12:00:00 UTC" "2012-06-01 00:00:00 UTC"

Wykorzystane dane:

dates1 <- c("2009-01","2009-02","2009-03")
dates2 <- c("2012-06-01 12:23","2012-06-01 12",'2012-06-01")
Jaap
źródło
po przekonwertowaniu zmiennej znakowej na format dateprzy użyciu parse_date_time, czy istnieje sposób na wyświetlenie jej w innej kolejności niż "2009-01-01 UTC"przy użyciu lubridatepakietu? Wolałbym zobaczyć dzień jako pierwszy w moim zbiorze danych, np 01-01-2009.
user63230
1
@ user63230 Zobacz ?format; np format(your_date, "%d-%m-%Y"). : . Ma to jednak wadę: odzyskasz wartość znaku, a nie datę.
Jaap
Dzięki, ale starałem się tego uniknąć formatz powodu, o którym wspominasz, pomyślałem, że może być sposób na włączenie tego do lubridatepakietu, ale wydaje się, że nie ma.
user63230
12

Korzystanie z pakietu w dowolnym momencie :

library(anytime)

anydate("2009-01")
# [1] "2009-01-01"
zx8754
źródło
To trochę dziwne, że wybiera „01-01”. Czy w dokumentacji jest coś na temat tego wyboru? Może bardziej ilustracyjny, aby pokazać również, anydate("2009-03")czy zawsze wybiera pierwszy dzień miesiąca.
lmo
@lmo nie sprawdził dokumentów, powiedziałbym, że jest to „powszechna” praktyka, gdy brakuje dd do wybrania pierwszego dnia.
zx8754
2
To ma sens. Zostałem niewyraźnie zapamiętany, a potem odkryłem, co wywołało komentarz. Z sekcji Uwaga w ?strptime: ciąg wejściowy nie musi określać całkowicie daty: zakłada się, że nieokreślone sekundy, minuty lub godziny wynoszą zero, a nieokreślony rok, miesiąc lub dzień jest bieżący. (Jeśli jednak podano miesiąc, dzień tego miesiąca musi być określony przez% d lub% e, ponieważ bieżący dzień miesiąca nie musi być ważny dla określonego miesiąca.) Wygląda na to, że odpowiedź megatrona zawiera podobny fragment dokumentacji z as.Date.
lmo
przez lata przed 1900 r. nie działa. Na przykład próbowałem tegoanytime('1870-01')
msh855
5

Rzeczywiście, jak wspomniano powyżej (i gdzie indziej w SO), aby przekonwertować ciąg na datę, potrzebujesz określonej daty miesiąca. Ze strony as.Date()podręcznika:

Jeśli ciąg daty nie określa całkowicie daty, zwrócona odpowiedź może być specyficzna dla systemu. Najczęstszym zachowaniem jest założenie, że brakujący rok, miesiąc lub dzień jest bieżącym. Jeśli poda nieprawidłową datę, niezawodne implementacje spowodują błąd, a data zostanie zgłoszona jako NA. Niestety, niektóre typowe implementacje (takie jak glibc) są zawodne i odgadują zamierzone znaczenie.

Prostym rozwiązaniem byłoby wklejenie daty "01"do każdej daty i strptime()wskazanie jej jako pierwszego dnia danego miesiąca.


Dla tych, którzy szukają trochę więcej informacji na temat dat i godzin przetwarzania w R:

W języku R czasy POSIXcti POSIXltklasy oraz daty używają Dateklasy.

Daty są przechowywane jako liczba dni od 1 stycznia 1970 r., A czasy są przechowywane jako liczba sekund od 1 stycznia 1970 r.

Na przykład:

d <- as.Date("1971-01-01")
unclass(d)  # one year after 1970-01-01
# [1] 365

pct <- Sys.time()  # in POSIXct
unclass(pct)  # number of seconds since 1970-01-01
# [1] 1450276559
plt <- as.POSIXlt(pct)
up <- unclass(plt)  # up is now a list containing the components of time
names(up)
# [1] "sec"    "min"    "hour"   "mday"   "mon"    "year"   "wday"   "yday"   "isdst"  "zone"  
# [11] "gmtoff"
up$hour
# [1] 9

Aby wykonać operacje na datach i godzinach:

plt - as.POSIXlt(d)
# Time difference of 16420.61 days

Aby przetwarzać daty, możesz użyć strptime()(zapożyczając te przykłady ze strony podręcznika):

strptime("20/2/06 11:16:16.683", "%d/%m/%y %H:%M:%OS")
# [1] "2006-02-20 11:16:16 EST"

# And in vectorized form:
dates <- c("1jan1960", "2jan1960", "31mar1960", "30jul1960")
strptime(dates, "%d%b%Y")
# [1] "1960-01-01 EST" "1960-01-02 EST" "1960-03-31 EST" "1960-07-30 EDT"
Megatron
źródło
1

Myślę, że rozwiązanie @ ben-rollerta jest dobrym rozwiązaniem.

Musisz tylko uważać, jeśli chcesz użyć tego rozwiązania w funkcji wewnątrz nowego pakietu.

Podczas tworzenia pakietów zaleca się używanie składni packagename::function_name()(patrz http://kbroman.org/pkg_primer/pages/depends.html ).

W takim przypadku musisz użyć wersji as.Date()zdefiniowanej przez zoobibliotekę.

Oto przykład :

> devtools::session_info()
Session info ----------------------------------------------------------------------------------------------------------------------------------------------------
 setting  value                       
 version  R version 3.3.1 (2016-06-21)
 system   x86_64, linux-gnu           
 ui       RStudio (1.0.35)            
 language (EN)                        
 collate  C                           
 tz       <NA>                        
 date     2016-11-09                  

Packages --------------------------------------------------------------------------------------------------------------------------------------------------------

 package  * version date       source        
 devtools   1.12.0  2016-06-24 CRAN (R 3.3.1)
 digest     0.6.10  2016-08-02 CRAN (R 3.2.3)
 memoise    1.0.0   2016-01-29 CRAN (R 3.2.3)
 withr      1.0.2   2016-06-20 CRAN (R 3.2.3)

> as.Date(zoo::as.yearmon("1989-10", "%Y-%m")) 
Error in as.Date.default(zoo::as.yearmon("1989-10", "%Y-%m")) : 
  do not know how to convert 'zoo::as.yearmon("1989-10", "%Y-%m")' to class “Date”

> zoo::as.Date(zoo::as.yearmon("1989-10", "%Y-%m"))
[1] "1989-10-01"

Więc jeśli tworzysz pakiet, dobrą praktyką jest użycie:

zoo::as.Date(zoo::as.yearmon("1989-10", "%Y-%m"))
PAC
źródło