Jahr und Monat (Format „JJJJ-MM“) in ein Datum konvertieren?

91

Ich habe einen Datensatz, der so aussieht:

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

Ich möchte die Daten zeichnen (Monate als x-Werte und zählt als y-Werte). Da die Daten lückenhaft sind, möchte ich die Informationen für den Monat in ein Datum konvertieren. Ich habe es versucht:

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

Aber es hat nicht funktioniert. Was ist los mit dir? Es scheint, dass as.Date () auch einen Tag benötigt und keinen Standardwert für den Tag festlegen kann? Welche Funktion löst mein Problem?

R_User
quelle

Antworten:

57

Versuche dies. (Hier verwenden wir text=Lines, um das Beispiel in sich geschlossen zu halten, aber in Wirklichkeit würden wir es durch den Dateinamen ersetzen.)

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)

Die X-Achse ist mit diesen Daten nicht so hübsch, aber wenn Sie in der Realität mehr Daten haben, ist dies möglicherweise in Ordnung, oder Sie können den Code für eine ausgefallene X-Achse verwenden, die im Beispielabschnitt von gezeigt wird ?plot.zoo.

Die oben erstellte Zoo-Serie zhat einen "yearmon"Zeitindex und sieht folgendermaßen aus:

> 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" kann auch alleine verwendet werden:

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

Hinweis:

  1. "yearmon" Klassenobjekte werden in Kalenderreihenfolge sortiert.

  2. Dadurch werden die monatlichen Punkte in gleichmäßigen Abständen aufgezeichnet, was wahrscheinlich erwünscht ist. Wenn es jedoch gewünscht wird, die Punkte in ungleichmäßigen Abständen zu zeichnen, die proportional zur Anzahl der Tage in jedem Monat verteilt sind, konvertieren Sie den Index von zin "Date"Klasse : time(z) <- as.Date(time(z)).

G. Grothendieck
quelle
76

Da Datumsangaben einem numerischen Wert und einem Startdatum entsprechen, benötigen Sie tatsächlich den Tag. Wenn Ihre Daten wirklich im Datumsformat vorliegen müssen, können Sie den Tag einfach manuell auf den ersten eines jeden Monats festlegen, indem Sie ihn in das Datum einfügen:

month <- "2009-03"
as.Date(paste(month,"-01",sep=""))
Sacha Epskamp
quelle
Welche anderen Formate für Daten gibt es? Ich habe etwas mit POSIX und etwas mit ISO gesehen, bin mir aber nicht sicher, ob es sich um unterschiedliche Formate handelt. Ich dachte, das sind nur Funktionen, ...
R_User
19
Beachten Sie, dass Sie den Tag im Formatierer als gleich angeben können, damit Sie as.Date(month, format='%Y-%m-01')das gleiche Ergebnis erzielen können. Dies "fühlt" sich für mich vorzuziehen an, da die Angabe des gleichen Datums in jedem Monat mehr vom Format des Datums als von der Manipulation von Zeichenfolgen abhängt, aber vielleicht ist das Unsinn.
JBecker
21
@JBecker dein Vorschlag funktioniert bei mir nicht. > as.Date("2016-01", format="%Y-%m-01") # [1] NA. Ich benutze R 3.3.1
n8sty
26

Die prägnanteste Lösung, wenn die Daten im Datumsformat vorliegen sollen:

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

as.Date fixiert den ersten Tag eines jeden Monats für Sie auf ein jährliches Objekt.

Ben Rollert
quelle
22

Sie können dies auch mit den Funktionen parse_date_timeoder fast_strptimeaus dem lubridatePaket erreichen:

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

Der Unterschied zwischen diesen beiden besteht darin, dass parse_date_timeeine Formatspezifikation im Lubridat-Stil möglich ist, während fast_strptimedieselbe Formatspezifikation wie erforderlich ist strptime.

Zum Festlegen der Zeitzone können Sie den tzParameter -parameter verwenden:

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

Wenn Ihre Datums- / truncatedUhrzeitdaten Unregelmäßigkeiten aufweisen , können Sie mit dem Parameter -parameter angeben, wie viele Unregelmäßigkeiten zulässig sind:

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

Verwendete Daten:

dates1 <- c("2009-01","2009-02","2009-03")
dates2 <- c("2012-06-01 12:23","2012-06-01 12",'2012-06-01")
Jaap
quelle
Gibt es eine Möglichkeit, eine Zeichenvariable nach der Konvertierung in ein Format datemit parse_date_timeeiner anderen Reihenfolge als "2009-01-01 UTC"mit dem lubridatePaket anzuzeigen ? Ich würde es vorziehen, den Tag zuerst in meinem Datensatz zu sehen, z 01-01-2009.
user63230
1
@ user63230 Siehe ?format; zB : format(your_date, "%d-%m-%Y"). Dies hat jedoch einen Nachteil: Sie erhalten einen Zeichenwert zurück und kein Datum.
Jaap
Vielen Dank, aber ich habe versucht, dies formataus dem von Ihnen genannten Grund zu vermeiden. Ich dachte, es könnte eine Möglichkeit geben, dies in das lubridatePaket aufzunehmen, aber es scheint, dass dies nicht der Fall ist.
user63230
12

Verwenden Sie jederzeit Paket:

library(anytime)

anydate("2009-01")
# [1] "2009-01-01"
zx8754
quelle
Das ist ein bisschen komisch, dass es "01-01" wählt. Gibt es irgendetwas in der Dokumentation über die Wahl? Vielleicht illustrativer, um auch zu zeigen, anydate("2009-03")ob immer der erste Tag des Monats gewählt wird.
lmo
@lmo hat die Dokumente nicht überprüft. Ich würde sagen, dass dies "übliche" Praxis ist, wenn dd fehlt, um den 1. Tag zu wählen.
zx8754
2
Das macht Sinn. Ich wurde vage erinnert und fand dann heraus, was den Kommentar auslöste. Im Abschnitt "Hinweis" von ?strptime: Die Eingabezeichenfolge muss das Datum nicht vollständig angeben: Es wird angenommen, dass nicht angegebene Sekunden, Minuten oder Stunden Null sind und ein nicht angegebenes Jahr, Monat oder Tag das aktuelle ist. (Wenn jedoch ein Monat angegeben wird, muss der Tag dieses Monats mit% d oder% e angegeben werden, da der aktuelle Tag des Monats für den angegebenen Monat nicht gültig sein muss.) Die Antwort von Megatron enthält anscheinend ein ähnliches Stück der Dokumentation aus as.Date.
lmo
seit Jahren vor 1900 funktioniert es nicht. Zum Beispiel habe ich dies versuchtanytime('1870-01')
msh855
5

Wie oben (und an anderer Stelle in SO) erwähnt, benötigen Sie zum Konvertieren der Zeichenfolge in ein Datum ein bestimmtes Datum des Monats. Von der as.Date()Handbuchseite:

Wenn die Datumszeichenfolge das Datum nicht vollständig angibt, ist die zurückgegebene Antwort möglicherweise systemspezifisch. Das häufigste Verhalten ist die Annahme, dass ein fehlendes Jahr, ein fehlender Monat oder ein fehlender Tag das aktuelle ist. Wenn ein Datum falsch angegeben wird, geben zuverlässige Implementierungen einen Fehler aus und das Datum wird als NA gemeldet. Leider sind einige gängige Implementierungen (z. B. glibc) unzuverlässig und erraten die beabsichtigte Bedeutung.

Eine einfache Lösung wäre, das Datum "01"in jedes Datum einzufügen und strptime()es als ersten Tag dieses Monats anzugeben.


Für diejenigen, die etwas mehr Hintergrundinformationen zur Verarbeitung von Datum und Uhrzeit in R suchen:

In R verwenden Zeiten POSIXctund POSIXltKlassen und Daten die DateKlasse.

Daten werden als Anzahl der Tage seit dem 1. Januar 1970 und Zeiten als Anzahl der Sekunden seit dem 1. Januar 1970 gespeichert.

Also zum Beispiel:

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

So führen Sie Operationen an Datum und Uhrzeit durch:

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

Und um Daten zu verarbeiten, können Sie Folgendes verwenden strptime()(Ausleihen dieser Beispiele von der Handbuchseite):

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
quelle
1

Ich denke, die Lösung von @ ben-rollert ist eine gute Lösung.

Sie müssen nur vorsichtig sein, wenn Sie diese Lösung in einer Funktion in einem neuen Paket verwenden möchten.

Bei der Entwicklung von Paketen wird empfohlen, die Syntax zu verwenden packagename::function_name()(siehe http://kbroman.org/pkg_primer/pages/depends.html ).

In diesem Fall müssen Sie die von der as.Date()definierte Version von verwendenzoo Bibliothek verwenden.

Hier ist ein Beispiel :

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

Wenn Sie also ein Paket entwickeln, sollten Sie Folgendes verwenden:

zoo::as.Date(zoo::as.yearmon("1989-10", "%Y-%m"))
PAC
quelle