2012-09-07 18 views
26

Si un vector de fecha tiene años de dos dígitos, mdy() convierte años entre 00 y 68 en años del siglo XXI y años entre 69 y 99 en años del siglo XX. Por ejemplo:¿Existe alguna manera más elegante de convertir años de dos dígitos a años de cuatro dígitos con lubridate?

library(lubridate)  
mdy(c("1/2/54","1/2/68","1/2/69","1/2/99","1/2/04")) 

da el siguiente resultado:

Multiple format matches with 5 successes: %m/%d/%y, %m/%d/%Y. 
Using date format %m/%d/%y. 
[1] "2054-01-02 UTC" "2068-01-02 UTC" "1969-01-02 UTC" "1999-01-02 UTC" "2004-01-02 UTC" 

puedo solucionar esto después del hecho restando 100 de las fechas incorrectas para convertir 2054 y 2068 en 1954 y 1968. Pero, ¿existe una ¿Es un método más elegante y menos propenso a errores de analizar las fechas de dos dígitos para que se manejen correctamente en el proceso de análisis?

Actualización: Después de @JoshuaUlrich me señaló a strptime He encontrado this question, que trata de un problema similar a la mía, pero utilizando R. base de

Parece una buena adición a la manipulación de la fecha en I sería alguna forma de manejar los cortes de selección del siglo para fechas de dos dígitos dentro de las funciones de análisis de fecha.

+4

Técnicamente, las fechas se están analizando correctamente, ya que la documentación ('?strptime') establece que: "En la entrada, los valores 00 a 68 están prefijados por 20 y 69 por 99 por 19, ese es el comportamiento especificado por los estándares POSIX de 2004 y 2008". '? parse_date' le dice brevemente que vea'? strptime' para los formatos. –

+1

Debería haber sido más preciso. No quise dar a entender que 'lubridate' tiene un error, sino simplemente que debido a la ambigüedad de los años de dos dígitos, el comportamiento natural del paquete resulta en años incorrectos de cuatro dígitos (" incorrecto "en el sentido de" no el resultado deseado ") bajo algunas situaciones relativamente comunes. Esperaba que hubiera alguna forma dentro de 'lubridate' para especificar un valor de" cambio "o" límite "que dará el siglo deseado para intervalos dados de fechas de dos dígitos. – eipi10

+2

Sugiere que envíe una solicitud de función a la página de lubithtete github. – Spacedman

Respuesta

22

Aquí es una función que le permite hacer esto:

library(lubridate) 
x <- mdy(c("1/2/54","1/2/68","1/2/69","1/2/99","1/2/04")) 


foo <- function(x, year=1968){ 
    m <- year(x) %% 100 
    year(x) <- ifelse(m > year %% 100, 1900+m, 2000+m) 
    x 
} 

Pruébelo:

x 
[1] "2054-01-02 UTC" "2068-01-02 UTC" "1969-01-02 UTC" "1999-01-02 UTC" 
[5] "2004-01-02 UTC" 

foo(x) 
[1] "2054-01-02 UTC" "2068-01-02 UTC" "1969-01-02 UTC" "1999-01-02 UTC" 
[5] "2004-01-02 UTC" 

foo(x, 1950) 
[1] "1954-01-02 UTC" "1968-01-02 UTC" "1969-01-02 UTC" "1999-01-02 UTC" 
[5] "2004-01-02 UTC" 

El poco de magia aquí es utilizar el operador módulo %% para volver la fracción de una división Entonces 1968 %% 100 produce 68.

+0

¡Agradable! Acabo de notar tu respuesta. Gracias por tu ayuda. – eipi10

2

Acabo de experimentar exactamente este mismo error/función.

Terminé escribiendo las siguientes dos funciones rápidas para ayudar a convertir las fechas de tipo excel (que es donde obtengo más) a algo que R puede usar.

No hay nada de malo con la respuesta aceptada, es solo que prefiero no cargar demasiado los paquetes.

En primer lugar, un ayudante para dividir y reemplazar los años ...

year1900 <- function(dd_y, yrFlip = 50) 
{ 
    dd_y <- as.numeric(dd_y) 
    dd_y[dd_y > yrFlip] <- dd_y[dd_y > yrFlip] + 1900 
    dd_y[dd_y < yrFlip] <- dd_y[dd_y < yrFlip] + 2000 
    return(dd_y) 
} 

que es utilizado por una función que 'fija' las fechas de Excel, dependiendo del tipo de:

XLdate <- function(Xd, type = 'b-Y') 
{ 
    switch(type, 
     'b-Y' = as.Date(paste0(substr(Xd, 5, 9), "-", substr(Xd, 1, 3), "-01"), format = "%Y-%b-%d"), 
     'b-y' = as.Date(paste0(year1900(substr(Xd, 5, 6)), "-", substr(Xd, 1, 3), "-01"), 
         format = "%Y-%b-%d"), 
     'Y-b' = as.Date(paste0(substr(Xd, 1, 3), "-", substr(Xd, 5, 9), "-01"), format =  "%Y-%b-%d") 
     ) 
} 

Esperanza esto ayuda.

0

Otra opción sería:

xxx <- c("01-Jan-54","01-Feb-68","01-Aug-69","01-May-99","01-Jun-04", " 
     31-Dec-68","01-Jan-69", "31-Dec-99") 

.

dmy(paste0(sub("\\d\\d$","",xxx) , ifelse((tt <- 
    sub("\\d\\d-\\D\\D\\D-","",xxx) ) > 20 ,paste0("19",tt),paste0("20",tt)))) 

Aunque ninguna solución es elegante ni corta. Creo que sería mejor si Lubridate acaba de agregar una opción para especificar la fecha de corte.

Cuestiones relacionadas