2011-12-13 14 views
14

ho qualche dubbio circa gli anni bisestili, come posso essere sicuro che utilizzando una formula del genereCome tenere conto degli anni bisestili?

add.years= function(x,y){  
if(!isTRUE(all.equal(y,round(y)))) stop("Argument \"y\" must be an integer.\n") 
x <- as.POSIXlt(x) 
x$year <- x$year+y 
as.Date(x) 
} 

si prenderà in considerazione anni bisestili, quando si aggiungono per esempio 100 anni per il mio set di dati di osservazione? Come posso controllarlo?

Ho un set di dati di serie temporali con 50 anni di osservazioni:

date obs 
1995-01-01 1.0 
1995-01-02 2.0 
1995-01-03 2.5 
... 
2045-12-30 0.2 
2045-12-31 0.1 

set di dati + 100 anni

date obs 
2095-01-01 1.0 
2095-01-02 2.0 
2095-01-03 2.5 
... 
2145-12-30 0.2 
2145-12-31 0.1 

Dopo un controllo di base, ho notato che il numero di righe è il lo stesso sia per l'originale che per 100 anni dopo il set di dati. Non sono sicuro se quello che era prima del 29 febbraio in un anno bisestile sarà ora il valore di obs per il 1 ° marzo in un anno bisestile, ecc.

Posso controllare gli anni bisestili usando dalla libreria di cronologia la funzione leap.year, tuttavia vorrei sapere se esiste un modo più semplice per eseguire questa operazione, per assicurarsi che le righe con giorni di passata del 29 febbraio che non esistono 100 anni dopo verranno eliminate e nuovi giorni del 29 febbraio sono aggiunti con valori NA.

+2

La miscelazione dei formati 'POSIXlt' e' Date' termina solo in oscuri bug e lacrime. –

+0

Confermo! Meglio passare un po 'di tempo a ripulire il mio codice. Grazie! –

risposta

13

È possibile verificare se un anno è un anno bisestile con leap_year da lubridate.

years <- 1895:2005 
years[leap_year(years)] 

Questo pacchetto gestirà anche la mancata generazione dei 29 di febbraio.

ymd("2000-2-29") + years(1) # NA 
ymd("2000-2-29") %m+% years(1) # "2001-02-28" 

L'operatore %m+% "aggiungere mesi", come ha ricordato @VitoshKa, tira il risalgono alla fine del mese precedente, se il giorno stesso non esiste.

+0

'lubridate' non sembra più in grado di gestirlo. Ottengo 'NA' quando tento di aggiungere un anno al giorno bisestile. – rrs

+1

Il comportamento in lubridate è stato modificato molto tempo fa. Otterrai NA in date non valide. Vedi il documento di [% m +%] (http://finzi.psych.upenn.edu/library/lubridate/html/mplus.html) se vuoi un comportamento a rotazione. Anche documenti per 'periodo' e' Periodo-classe'. – VitoshKa

3

Un anno è un anno bisestile se:

  • è divisibile per 4.
  • Non se è divisibile per 100.
  • Ma è se è divisibile per 400.

Ecco perché il 2000 è stato un anno bisestile (anche se è divisibile per 100, è anche divisibile per 400).

Ma generalmente, se si dispone di una libreria che può richiedere calcoli di data/ora, quindi utilizzarlo. È molto complicato fare questi calcoli e facile da fare, specialmente con date antiche (riforme del calendario) e fusi orari.

+0

Non riesco ancora a trovare alcuna funzione che mi consenta di eseguire questo tipo di modifiche a un set di dati, credo di doverne creare uno da solo. –

+0

No, non lo fai. Esistono funzionalità esistenti nella base R, così come nei pacchetti CRAN. –

+0

Toby Marthews-3 fornisce una dichiarazione 'ifelse' per la gestione degli anni bisestili qui: http://r.789695.n4.nabble.com/leap-year-and-order-function-td3248104.html –

1

I suoi sospetti sono infatti corrette:

x <- as.POSIXlt("2000-02-29") 
y <- x 
y$year <- y$year+100 
y 
#[1] "2100-03-01" 

La cosa strana è che altre parti del y rimangono invariati, quindi non è possibile utilizzare questi per il confronto:

y$mday 
#[1] 29 
y$mon 
#[1] 1 

ma è possibile utilizzare strftime :

strftime(x,"%d") 
#[1] "29" 
strftime(y,"%d") 
#[1] "01" 

Quindi che dire:

add.years <- function(x,y){ 
    if(!isTRUE(all.equal(y,round(y)))) stop("Argument \"y\" must be an integer.\n") 
    x.out <- as.POSIXlt(x) 
    x.out$year <- x.out$year+y 
    ifelse(strftime(x,"%d")==strftime(x.out,"%d"),as.Date(x.out),NA) 
    } 

È quindi possibile sottoinsieme dei dati utilizzando [ e is.na per sbarazzarsi dei altrimenti duplicare 1st date di marzo. Anche se queste date sembrano essere consecutivi, potresti prendere in considerazione una soluzione che utilizza seq.Date ed evitare di rilasciare i dati.

+2

2100 non è un anno bisestile, quindi il calcolo nel tuo primo esempio mi sembra corretto. –

Problemi correlati