2014-07-25 18 views
7

In R ist es möglich, POSIXlt Datum Zeitobjekte als ein Monat zu formatieren:Format Datum-Uhrzeit als Jahreszeiten in R?

format(Sys.time(), format='%Y-%m') 

Gibt es eine Möglichkeit, die gleiche Sache mit Jahreszeit zu tun, oder 3-Monats-Gruppen (DJF, MAM, JJA, SON) Diese Spaltungen sind in der Klimaforschung und in der ökologischen Wissenschaft wirklich üblich, und es wäre großartig, sie so schnell wie in Monaten zu formatieren. Offensichtlich fällt DJF über 2 Jahre, aber für die Zwecke oder diese Frage ist das nicht wirklich wichtig - schieben Sie sie einfach konsequent in jedes Jahr (oder, im Idealfall, wäre es gut, angeben zu können, in welches Jahr sie gehen) .

Ich benutze die Ausgabe als ein Index für by(), so dass das Ausgabeformat nicht viel ausmacht, nur so lange wie jedes Jahr/Saison ist einzigartig.

Edit: Beispieldaten:

dates <- Sys.Date()+seq(1,380, by=35) 
dates <- structure(c(16277, 16312, 16347, 16382, 16417, 16452, 16487, 
        16522, 16557, 16592, 16627), class = "Date") 
dates 
#[1] "2014-07-26" "2014-08-30" "2014-10-04" "2014-11-08" "2014-12-13" 
# "2015-01-17" "2015-02-21" "2015-03-28" "2015-05-02" "2015-06-06" "2015-07-11" 

sollte in Folge:

c("2014-JJA", "2014-JJA", "2014-SON", "2014-SON", "2015-DJF", "2015-DJF", 
    "2015-DJF", "2015-MAM", "2015-MAM", "2015-JJA", "2015-JJA") 

Aber die "2015-DJF" s könnte auch "2014-DJF" sein. Auch die Form des Ausgangs keine Rolle spielt - „2104q4 oder 201.404 auch in Ordnung sein würde

+1

[hier] (http://stackoverflow.com/questions/9500114/find-which-season-a-particular-date-belongs-to/9501225#9501225) eine damit verbundene Frage und Antwort. –

+2

Wenn Q1 DJF, etc. ist, wandeln Sie es in '" yearnmon "' Klasse um, fügen Sie einen Monat hinzu und konvertieren Sie es in '" yearqtr "' class: 'library (zoo); Format (as.yearqtr (as.yearmon (Sys.time()) + 1/12)) '. Sie können eine Formatzeichenfolge verwenden, wenn Sie ein anderes Format wünschen, z. 'format (as.yearqtr (as.yearmon (Sys.time()) + 1/12),"% Y-% q ")' –

Antwort

6

as.POSIXlt gibt eine benannte Liste (die es nicht geeignet für data.frame Spalten macht). Die Listenspalten können einzeln aufgerufen werden und enthalten "Jahr" (1900, im Gegensatz zu 1970 für Standard) und "Mon" (0-basiert). Der beste Ort, diese Liste in hte Hilfesystem zu sehen ist ?DateTimeClasses:

Zuerst nur eine Berechnung Jahreszeiten, dann ein Jahr-Jahreszeiten Berechnung

c('DJF', 'MAM', 'JJA', 'SON')[ # select from character vector with numeric vector 
      1+((as.POSIXlt(dates)$mon+1) %/% 3)%%4] 

[1] "JJA" "JJA" "SON" "SON" "DJF" "DJF" "DJF" "MAM" "MAM" "JJA" 
[11] "JJA" 



    paste(1900 + # this is the base year for POSIXlt year numbering 
      as.POSIXlt(dates)$year + 
      1*(as.POSIXlt(dates)$year==12) , # offset needed for December 
      c('DJF', 'MAM', 'JJA', 'SON')[   # indexing from 0-based-mon 
          1+((as.POSIXlt(dates)$mon+1) %/% 3)%%4] 
      , sep="-") 
[1] "2014-JJA" "2014-JJA" "2014-SON" "2014-SON" "2014-DJF" 
[6] "2015-DJF" "2015-DJF" "2015-MAM" "2015-MAM" "2015-JJA" 
[11] "2015-JJA" 

Sollte nicht so schwer sein, eine Funktion zu machen, das die Formatierung konstruiert du erwartest. Dies ist nur eine Modulo-Arithmetik für die POSIX-Werte für Monat und Jahr.

+0

Cool, nette. Ich habe damit angefangen, und dann sah ich, dass die Antwort, die du gepostet hast, gelöscht wurde, also schrieb ich meine eigene in der Zwischenzeit. Deines ist besser, weil es schönere Jahreszeitnamen benutzt, aber ich denke, dass sie funktionell mehr oder weniger gleichwertig sind. Ich werde die Stimmen entscheiden lassen :) – naught101

+0

Ich denke nicht, dass meins sehr offensichtlich ist. Ich wurde mit den Modulo-Divisionen und den Resten, die immer falsch ausgingen, verknotet. –

+0

Ich auch, weil die frigging interne Darstellung von Monaten in POSIXlt 0-indiziert ist, während die externe Darstellung 1-indiziert ist. Verrückt. Wie auch immer, ich habe beschlossen, mit meinem zu gehen, aber nur, weil es dir erlaubt, die Ergebnisse als Daten zu hinterlassen, was für meine Zwecke nützlich ist. – naught101

4

Ich mag mit einem Lookup-Vektor für diese Art von Problemen, zum Beispiel:

x <- as.POSIXlt(
    seq.Date(as.Date("2000-01-01"),as.Date("2002-01-01"),by="2 months") 
) 

ZB wenn Sie. wollen Südhalbkugel Jahreszeiten geben, könnten Sie tun:

src <- rep(c("su","au","wi","sp"),each=3)[c(2:12,1)] 

paste(format(x,"%Y-%m"),src[x$mon+1]) 
# [1] "2000-01 su" "2000-03 au" "2000-05 au" "2000-07 wi" "2000-09 sp" 
# [6] "2000-11 sp" "2001-01 su" "2001-03 au" "2001-05 au" "2001-07 wi" 
#[11] "2001-09 sp" "2001-11 sp" "2002-01 su" 

ändern Sie die src Namen wie Sie sehen, passen die Kategorien relabel

2

Let Q1 sein DJF; Q2, MAM, usw. dann.:

seasonal.quarters <- function(x) { 
    x <- as.POSIXlt(x) 
    x$mon <- (x$mon + 1) %% 12 
    quarters(x) 
} 

options(stringsAsFactors=FALSE) 

nonleap.year <- seq(from=as.POSIXct('2013-1-1'), to=as.POSIXct('2014-1-1'), by='day') 
d <- data.frame(ms=months(nonleap.year), qs=seasonal.quarters(nonleap.year)) 
by(d, INDICES=list(d$qs), FUN=function(x) unique(x$ms)) 
# : Q1 
# [1] "January" "February" "December" 
# ------------------------------------- 
# : Q2 
# [1] "March" "April" "May" 
# ------------------------------------- 
# : Q3 
# [1] "June" "July" "August" 
# ------------------------------------- 
# : Q4 
# [1] "September" "October" "November" 

leap.year <- seq(from=as.POSIXct('2016-1-1'), to=as.POSIXct('2017-1-1'), by='day') 
d <- data.frame(ms=months(leap.year), qs=seasonal.quarters(leap.year)) 
by(d, INDICES=list(d$qs), FUN=function(x) unique(x$ms)) 
# : Q1 
# [1] "January" "February" "December" 
# ------------------------------------- 
# : Q2 
# [1] "March" "April" "May" 
# ------------------------------------- 
# : Q3 
# [1] "June" "July" "August" 
# ------------------------------------- 
# : Q4 
# [1] "September" "October" "November" 
+0

Die Difftime verwandelt den Dezember im Grunde in Januar, oder? Aber das wird nicht genau funktionieren, weil jedes Quartal eine andere Länge hat und das erste Viertel eine andere Länge in Schaltjahren hat. – naught101

+0

Ja, das habe ich gerade erkannt. Dies ist nicht zuverlässig. Wird in Kürze entfernt. –

+0

@ naught101, aktualisiert. –

2

Dies ist eine Alternative zu 42-'s answer oben. Sehen Sie meinen Kommentar dort, aus dem Grund, warum ich ihn gepostet habe.

dates_orig <- as.POSIXlt(c("2013-01-01", "2013-02-01", "2013-03-01", "2013-04-01", "2013-05-01", "2013-06-01", "2013-07-01", "2013-08-01", "2013-09-01", "2013-10-01", "2013-11-01", "2013-12-01", "2014-01-01", "2014-02-01", "2014-03-01", "2014-04-01", "2014-05-01", "2014-06-01", "2014-07-01", "2014-08-01", "2014-09-01", "2014-10-01", "2014-11-01", "2014-12-01")) 

format(dates_orig, format='%Y%b') 
[1] "2013Jan" "2013Feb" "2013Mar" "2013Apr" "2013May" "2013Jun" "2013Jul" "2013Aug" "2013Sep" "2013Oct" "2013Nov" "2013Dec" "2014Jan" "2014Feb" "2014Mar" 
[16] "2014Apr" "2014May" "2014Jun" "2014Jul" "2014Aug" "2014Sep" "2014Oct" "2014Nov" "2014Dec" 

dates <- as.POSIXlt(dates_orig) 
# shift Jan and Feb to the previous year 
dates$year[dates$mon < 2] <- dates$year[dates$mon < 2] - 1 
# convert months to seasons (named by first month of season) 
dates$mon <- (((dates$mon - 2) %/% 3) %% 4) * 3 + 2 

format(dates, format='%Y%b') 
[1] "2012Dec" "2012Dec" "2013Mar" "2013Mar" "2013Mar" "2013Jun" "2013Jun" "2013Jun" "2013Sep" "2013Sep" "2013Sep" "2013Dec" "2013Dec" "2013Dec" "2014Mar" 
[16] "2014Mar" "2014Mar" "2014Jun" "2014Jun" "2014Jun" "2014Sep" "2014Sep" "2014Sep" "2014Dec" 
+1

Es verwendet eine destruktive Änderung an das Original und dann beantwortet es nicht wirklich die Frage, weil Sie noch Monate bekommen. –

+0

@ 42-: Es ergibt sich der erste Monat der Saison - es ist nicht schwer, die Monate für "DJF", "MMA", etc. bei Bedarf zu ersetzen. Es war nicht für mich. Was den Datenverlust angeht, wird das Konvertieren von Daten in Jahreszeiten * immer * verlustreich sein. Wenn es Ihnen etwas ausmacht, verwerfen Sie nicht die Originaldaten. Ihre Lösung ist gleichermaßen verlustreich. – naught101

+0

Sie sollten diese Erklärung in die Antwort bearbeiten, anstatt Leute auf Kommentare zu verweisen, denke ich. – Frank