¿Convertir año y mes (formato “aaaa-mm”) en una fecha?

91

Tengo un conjunto de datos que se parece a esto:

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

Quiero trazar los datos (meses como valores x y cuenta como valores y). Dado que existen lagunas en los datos, quiero convertir la información del mes en una fecha. Lo intenté:

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

Pero no funcionó. Que esta mal Parece que as.Date () requiere también un día y no puede establecer un valor estándar para el día. ¿Qué función resuelve mi problema?

R_User
fuente

Respuestas:

57

Prueba esto. (Aquí usamos text=Linespara mantener el ejemplo autocontenido, pero en realidad lo reemplazaríamos con el nombre del archivo).

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)

El eje X no es tan bonito con estos datos, pero si tiene más datos en realidad podría estar bien o puede usar el código para un eje X elegante que se muestra en la sección de ejemplos de ?plot.zoo.

La serie del zoológico z, que se creó arriba, tiene un "yearmon"índice de tiempo y se ve así:

> 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" también se puede utilizar solo:

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

Nota:

  1. "yearmon" los objetos de clase se clasifican en orden de calendario.

  2. Esto trazará los puntos mensuales a intervalos igualmente espaciados que es probablemente lo que se desea; sin embargo, si se deseara para trazar los puntos a intervalos espaciados desigualmente espaciadas en proporción al número de días de cada mes a continuación, convertir el índice de za "Date"clase: time(z) <- as.Date(time(z)).

G. Grothendieck
fuente
76

Dado que las fechas corresponden a un valor numérico y una fecha de inicio, de hecho necesita el día. Si realmente necesita que sus datos estén en formato de fecha, puede fijar el día al primero de cada mes manualmente pegándolo en la fecha:

month <- "2009-03"
as.Date(paste(month,"-01",sep=""))
Sacha Epskamp
fuente
¿Qué otros formatos de fechas existen? Vi algo con POSIX y algo con ISO, pero no estoy seguro si esos son formatos diferentes. Pensé que esas son solo funciones, ...
R_User
19
Vale la pena señalar que puede especificar que el día sea el mismo en el formateador, para que pueda hacerlo as.Date(month, format='%Y-%m-01')y lograr el mismo resultado. Esto me "parece" preferible, ya que especificar la misma fecha en cada mes tiene más que ver con el formato de la fecha que con la manipulación de cadenas, pero tal vez eso sea una tontería.
JBecker
21
@JBecker, tu sugerencia no funciona para mí. > as.Date("2016-01", format="%Y-%m-01") # [1] NA. Estoy usando R 3.3.1
n8sty
26

La solución más concisa si necesita que las fechas estén en formato de fecha:

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

as.Date fijará el primer día de cada mes en un objeto yearmon para usted.

Ben Rollert
fuente
23

También puede lograr esto con las funciones parse_date_timeo fast_strptimedel lubridatepaquete:

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

La diferencia entre esos dos es que parse_date_timepermite la especificación de formato de estilo lubridate, mientras que fast_strptimerequiere la misma especificación de formato que strptime.

Para especificar la zona horaria, puede utilizar el tzparámetro -parámetro:

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

Cuando tiene irregularidades en sus datos de fecha y hora, puede usar el truncatedparámetro -para especificar cuántas irregularidades están permitidas:

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

Datos usados:

dates1 <- c("2009-01","2009-02","2009-03")
dates2 <- c("2012-06-01 12:23","2012-06-01 12",'2012-06-01")
Jaap
fuente
habiendo convertido una variable de carácter a formato dateusando parse_date_time, ¿hay alguna manera de verla en un orden diferente al "2009-01-01 UTC"usando lubridatepackage? Preferiría ver el día primero en mi conjunto de datos, por ejemplo 01-01-2009.
user63230
1
@ user63230 Ver ?format; por ejemplo: format(your_date, "%d-%m-%Y"). Sin embargo, esto tiene una desventaja: obtendrás el valor de un personaje y no una fecha.
Jaap
Gracias, pero estaba tratando de evitar formatpor la razón que mencionas, pensé que podría haber una forma de incorporar esto en el lubridatepaquete, pero parece que no la hay.
user63230
12

Usando el paquete en cualquier momento :

library(anytime)

anydate("2009-01")
# [1] "2009-01-01"
zx8754
fuente
Es un poco extraño que elija "01-01", ¿hay algo en la documentación sobre la elección? Quizás más ilustrativo para mostrar también anydate("2009-03")si siempre se elige el primer día del mes.
lmo
@lmo no verificó los documentos, yo diría que esta es una práctica "común" cuando falta dd para elegir el primer día.
zx8754
2
Eso tiene sentido. Me recordaron vagamente y luego encontré lo que provocó el comentario. De la sección Nota de ?strptime: la cadena de entrada no necesita especificar la fecha completamente: se asume que los segundos, minutos u horas no especificados son cero, y un año, mes o día no especificado es el actual. (Sin embargo, si se especifica un mes, el día de ese mes tiene que ser especificado por% d o% e ya que el día actual del mes no necesita ser válido para el mes especificado). Parece que la respuesta de megatron contiene una pieza similar de documentación de as.Date.
lmo
durante años antes de 1900, no funciona. Por ejemplo, probé estoanytime('1870-01')
msh855
5

De hecho, como se mencionó anteriormente (y en otras partes de SO), para convertir la cadena en una fecha, necesita una fecha específica del mes. Desde la as.Date()página del manual:

Si la cadena de fecha no especifica la fecha completamente, la respuesta devuelta puede ser específica del sistema. El comportamiento más común es asumir que un año, mes o día faltante es el actual. Si especifica una fecha incorrectamente, las implementaciones confiables darán un error y la fecha se informa como NA. Desafortunadamente, algunas implementaciones comunes (como glibc) no son confiables y adivinan el significado deseado.

Una solución simple sería pegar la fecha "01"en cada fecha y usarla strptime()para indicarla como el primer día de ese mes.


Para aquellos que buscan un poco más de información sobre el procesamiento de fechas y horas en R:

En R, los tiempos usan POSIXcty las POSIXltclases y las fechas usan la Dateclase.

Las fechas se almacenan como el número de días desde el 1 de enero de 1970 y las horas se almacenan como el número de segundos desde el 1 de enero de 1970.

Así por ejemplo:

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

Para realizar operaciones en fechas y horas:

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

Y para procesar fechas, puede usar strptime()(tomando prestados estos ejemplos de la página del manual):

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

Creo que la solución de @ ben-rollert es una buena solución.

Solo debe tener cuidado si desea utilizar esta solución en una función dentro de un nuevo paquete.

Al desarrollar paquetes, se recomienda utilizar la sintaxis packagename::function_name()(consulte http://kbroman.org/pkg_primer/pages/depends.html ).

En este caso, debe utilizar la versión de as.Date()definida por elzoo biblioteca.

Aquí hay un ejemplo :

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

Entonces, si está desarrollando un paquete, la buena práctica es usar:

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