2012-09-07 2 views
26

Si un vecteur de date a des années à deux chiffres, mdy() transforme les années entre 00 et 68 en années et années du 21e siècle entre 69 et 99 ans et jusqu'au 20e siècle. Par exemple:Existe-t-il un moyen plus élégant de convertir les années à deux chiffres en années à quatre chiffres avec lubridate?

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

donne le résultat suivant:

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" 

Je peux résoudre ce problème après le fait en soustrayant 100 des dates incorrectes pour transformer 2054 et 2068 en 1954 et 1968. Mais est-il Méthode plus élégante et moins sujette aux erreurs pour analyser les dates à deux chiffres afin qu'elles soient traitées correctement dans le processus d'analyse lui-même?

Mise à jour: Après @JoshuaUlrich me montra strptime je trouve this question, qui traite d'une question similaire à la mienne, mais en utilisant la base R.

Il semble comme une belle addition à la gestion des dates en R serait un moyen de gérer les seuils de sélection de siècle pour les dates à deux chiffres dans les fonctions d'analyse de date.

+4

Techniquement, les dates sont analysées correctement, puisque la documentation ('?strptime') indique que: "En entrée, les valeurs 00 à 68 sont préfixées par 20 et 69 à 99 par 19 - c'est le comportement spécifié par les normes POSIX 2004 et 2008". '? parse_date' vous indique brièvement'? strptime' pour les formats. –

+1

J'aurais dû être plus précis. Je ne voulais pas laisser entendre que «lubridate» a un bug, mais simplement qu'en raison de l'ambiguïté des années à deux chiffres, le comportement naturel du paquet résulte en des années à quatre chiffres incorrectes («incorrect» dans le sens de «pas le résultat souhaité ») dans certaines situations relativement courantes. J'espérais qu'il y avait un moyen au sein de 'lubridate' de spécifier une valeur de« switch »ou de« cutoff »qui donnerait le siècle désiré pour des plages données de dates à deux chiffres. – eipi10

+2

Suggère que vous soumettiez une demande de fonctionnalité à la page github de lubridate. – Spacedman

Répondre

22

Voici une fonction qui vous permet de le faire:

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 
} 

Essayez-:

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" 

Le peu de magie ici est d'utiliser l'opérateur de module %% pour revenir la partie fraction d'une division. Donc, 1968 %% 100 donne 68.

+0

Bien! Juste remarqué votre réponse. Merci de votre aide. – eipi10

2

Je viens d'éprouver exactement ce même bug/caractéristique.

J'ai fini par écrire les deux fonctions rapides suivantes pour aider à convertir des dates de type Excel (ce qui est l'endroit où je reçois le plus) à quelque chose que R peut utiliser.

Il n'y a rien de mal à la réponse acceptée - c'est juste que je préfère ne pas trop charger sur les paquets.

D'abord, une aide pour diviser et remplacer les années ...

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) 
} 

qui est utilisé par une fonction que vos dates de Excel 'Ret, selon le type:

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

Espoir CA aide.

0

Une autre option serait:

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

Bien qu'aucune solution ne soit élégante ou courte. Je pense que ce serait mieux si lubrifier juste ajouté une option pour spécifier la date limite.

Questions connexes