Tiempo en R

Trabajar con fechas y tiempo en R es un poco complicado. En este post trato de explicar cómo trabajar con este tipo de datos y base R

Base R
Author
Published

March 14, 2018

Tiempo

La medición del tiempo es algo que puede ser particular, ya que hay meses con diferente número de días, en distintos países la manera de colocar el dato del día o del mes se cambia, en años bisiestos febrero tiene un día extra entre otros factores, hay diferentes

Por ende, hacer cálculos con fechas puede resultar algo complicado, sin embargo R tiene un sistema robusto para poder lidiar con estas situaciones.

Fechas y Horas en R:

R tiene diversas maneras de representar objetos en el sistema. Más allá de los dobles, enteros, carácteres, lógicos y complejos, R tiene una clase especial para representar las fechas y horas.

Si queremos revisar cuál es la fecha y hora que tenemos en nuestro sistema podemos hacerlo con la función Sys.time()

Sys.time()
[1] "2022-09-13 13:49:26 MDT"

Lo que nos muestra es una descripción de la fecha y hora de manera meramente jerárquica: la escala más grande (años) va primero, seguido por el mes y por último el día, separados entre sí por un guión; luego hay un espacio en blanco y bajo la misma lógica tenemos la hora, los minutos y los seugundos, separados cada uno por dos punto. Al final tenemos un dato que nos indica el sistema de tiempo utilizado, en este caso Central Standard Time.

Esta convención es buena para poder leer de manera fácil, sin embargo, para la realización de cálculos esto es un poco difícil por lo que el manejo de estas a lo “interno” de R se hace basado en segundos.

Tipo y Clase del tiempo en R:

Para revisar su tipo de dato y su clase vamos a guardar esta fecha y hora de nuestro ordenador en un objeto de la siguiente manera:

fecha_hora <- Sys.time() # Guardar en un objeto

typeof(fecha_hora) # Tipo de dato
[1] "double"
class(fecha_hora) # Clase del objeto
[1] "POSIXct" "POSIXt" 

Al momento de utilizar la funciónSys.time(), nos devuelve una respuesta que a primera instancia nos parecería un objeto de tipo character por sus comillas alrededor de esto, sin embargo, al revisar podemos notar que es un objeto de tipo double y su clase es _ “POSIXct” “POSIXt” _ (tiene dos clases)

¿Qué signifan esas dos clases?

Como mencionamos anteriormente, por convención en R se utiliza una representación numérica, basada en segundos. Esto quiere decir que cada fecha se representa por el número de segundos que han transcurrido desde las 12:00 A.M. del 1 Enero de 1970. (UTC: Coordinated Universal Time)

Esto es bastante útil si queremos generar gráficos de series de tiempo, pero qué sucede si queremos representar las medias por mes, o por día. En este caso es necesario contar con dos maneras de representar las fechas:

POSIXct el sufijo ct se refiere a continuos time y este formato es representado de manera númerica por segundos. Este es un vector que se puede usar como una variable continua en modelos de regresión.

POSIXlt el sufijo lt corresponde a list time y lo que hace es una lista de todas las descripciones categóricas del tiempo. Es muy útil como variable explicativa categórica.

¿Cómo funcionan el sistema POSIX?

Para revisar de qué manera R hace esto podemos hacer uso de la función unclass()

unclass(fecha_hora)
[1] 1663098567

El resultado que obtenemos es un elemento que R utiliza para construir un vector doble. Lo que tenemos allí es que desde las 12:00 A.M. del 1 de Enero de 1970 han transcurrido 1 514 244 708 hasta el día en que este tutorial se ha creado y este es el formato POSIXct

En el caso de caso de una lista como POSIXlt vamos a revisar los componentes del mismo objeto con el que hemos venido trabajando:

fecha_hora <- as.POSIXlt(fecha_hora) # Definimos formato
unlist(fecha_hora) # Sacamos de la lista los objetos almacenados
               sec                min               hour               mday 
"26.8818531036377"               "49"               "13"               "13" 
               mon               year               wday               yday 
               "8"              "122"                "2"              "255" 
             isdst               zone             gmtoff 
               "1"              "MDT"           "-21600" 

¿Qué es lo que tenemos? Se nos muestran los componentes de la lista, que está representada por el número de segundos, minutos, hora (en formato de 24 horas). Luego viene mday que es el día del mes (inicia en 1), mon es el mes del año (comienza en enero = 0), year que representa el año (inicia en 0 = 1900),wday el día de la semana (inicia domingo = 0), yday es el número de día del año (1 de enero = 0). Por último la variable isdst lo que hace es indicarnos si un horario de verano está siendo considerado (0 = FALSE, como en este caso)

Leer fechas desde archivos

Cuando traemos datos a R, en ocasiones hay que hacerle explícito a R el tipo de datos que tenemos. En el caso de las fechas es necesario, ya que de esta forma determinamos qué dato corresponde a cuál componente de lo que se considera una fecha u hora.

Vamos a utilizar el set de datos Flights that Depart NYC in 2013 que tiene como nombre nycflights13. Este se encuentra en el paquete con el mismo nombre. (Si no lo tienen, pueden instalarlo con la función install.packages("nycflights13"))

data <- nycflights13::flights # Guardar en objeto datos seleccionados
head(data)
# A tibble: 6 × 19
   year month   day dep_time sched_dep…¹ dep_d…² arr_t…³ sched…⁴ arr_d…⁵ carrier
  <int> <int> <int>    <int>       <int>   <dbl>   <int>   <int>   <dbl> <chr>  
1  2013     1     1      517         515       2     830     819      11 UA     
2  2013     1     1      533         529       4     850     830      20 UA     
3  2013     1     1      542         540       2     923     850      33 AA     
4  2013     1     1      544         545      -1    1004    1022     -18 B6     
5  2013     1     1      554         600      -6     812     837     -25 DL     
6  2013     1     1      554         558      -4     740     728      12 UA     
# … with 9 more variables: flight <int>, tailnum <chr>, origin <chr>,
#   dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
#   time_hour <dttm>, and abbreviated variable names ¹​sched_dep_time,
#   ²​dep_delay, ³​arr_time, ⁴​sched_arr_time, ⁵​arr_delay

El conjunto de datos trae 3 columnas con el año, el mes y el día, los cuales vamos a unir y darle format de fecha:

library(tidyr) # Paquete del cual vamos a utilizar función
data <- unite(data, Date, year, month,day, sep = "/")
head(data)
# A tibble: 6 × 17
  Date    dep_t…¹ sched…² dep_d…³ arr_t…⁴ sched…⁵ arr_d…⁶ carrier flight tailnum
  <chr>     <int>   <int>   <dbl>   <int>   <int>   <dbl> <chr>    <int> <chr>  
1 2013/1…     517     515       2     830     819      11 UA        1545 N14228 
2 2013/1…     533     529       4     850     830      20 UA        1714 N24211 
3 2013/1…     542     540       2     923     850      33 AA        1141 N619AA 
4 2013/1…     544     545      -1    1004    1022     -18 B6         725 N804JB 
5 2013/1…     554     600      -6     812     837     -25 DL         461 N668DN 
6 2013/1…     554     558      -4     740     728      12 UA        1696 N39463 
# … with 7 more variables: origin <chr>, dest <chr>, air_time <dbl>,
#   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>, and abbreviated
#   variable names ¹​dep_time, ²​sched_dep_time, ³​dep_delay, ⁴​arr_time,
#   ⁵​sched_arr_time, ⁶​arr_delay

Función strptime

Ya que tenemos dicha column creada, vamos a indicarle R qué de esos datos pertenece al año, al mes y al día:

Rdate <- strptime(as.character(data$Date), "%Y/%m/%d")
class(Rdate)
[1] "POSIXlt" "POSIXt" 

Ya tenemos el objeto creado con las fechas por lo que ahora podemos unirlo al set de datos:

data <- data.frame(Rdate,data)
head(data)
       Rdate     Date dep_time sched_dep_time dep_delay arr_time sched_arr_time
1 2013-01-01 2013/1/1      517            515         2      830            819
2 2013-01-01 2013/1/1      533            529         4      850            830
3 2013-01-01 2013/1/1      542            540         2      923            850
4 2013-01-01 2013/1/1      544            545        -1     1004           1022
5 2013-01-01 2013/1/1      554            600        -6      812            837
6 2013-01-01 2013/1/1      554            558        -4      740            728
  arr_delay carrier flight tailnum origin dest air_time distance hour minute
1        11      UA   1545  N14228    EWR  IAH      227     1400    5     15
2        20      UA   1714  N24211    LGA  IAH      227     1416    5     29
3        33      AA   1141  N619AA    JFK  MIA      160     1089    5     40
4       -18      B6    725  N804JB    JFK  BQN      183     1576    5     45
5       -25      DL    461  N668DN    LGA  ATL      116      762    6      0
6        12      UA   1696  N39463    EWR  ORD      150      719    5     58
            time_hour
1 2013-01-01 05:00:00
2 2013-01-01 05:00:00
3 2013-01-01 05:00:00
4 2013-01-01 05:00:00
5 2013-01-01 06:00:00
6 2013-01-01 05:00:00

¿Qué fué lo que hicimos?

La columna date contenía datos separados por un guión, en donde el primer dato pertenecía al año, el segundo al mes y el tercero al día, por ende le dijimos a R que leyera esos datos como año, mes y día separados por un /: ("%Y/%m/%d")

Estas son abreviaciones que dan a entender diferentes formas de leer el dato en R. La siguiente es una lista de todas las abreviaciones:

Símbolo Significado
%a Nombre de la semana abreviado
%A Nombre de la semana completo
%b Nombre del mes abreviado
%B Nombre del mes completo
%c Hora y Fecha específica a la localidad
%d Día del mes como un número decimal (01-31)
%H Horas como decimales en reloj de 24 horas
%I Horas como decimales en reloj de 12 horas
%j Día del año como número decimal (0 - 366)
%m Mes como un número decimal (0-11)
%M Minutos como un número decimal (00 - 59)
%p AM/PM indicador en la localidad
%S Segundos como número decimal (00 - 61)
%U Semana del año (00 - 53) usando el primer domingo como el día 1 de la semana 1
%w Día de la semana como un número decimal (0 - 6, Domingo es 0)
%W Semana del año (00 - 53) usando el primer lunes como día 1 de la semana 1
%x Fecha, específica de la localidad
%X Hora, específica de la localidad
%Y Año con centenario
%y Año sin centenario
%Z Zona horaria como un vector de tipo caracter

Nombre completo del día:

Ahora bien, hay ocasiones en que por ejemplo, tenemos el día como un número, pero nos serviría más tener el nombre del día. Para esto existe la función weekdays()

ejemplo <- data[1,1]
ejemplo
[1] "2013-01-01 MST"

Tenemos el 1ero de enero del 2013, ahora queremos ver qué día es este con su nombre:

weekdays(ejemplo)
[1] "martes"

Otros formatos

Fechas pueden venir en diversas formas, tenemos que aprender cómo lidiar con estas y cómo hacerle explícito a R qué es qué. Para esto tenemos como ayuda la tabla presentada anteriormente.

Un ejemplo podría ser el siguiente:

otras_fechas <- c("2feb2016","18jun1990","7nov1995")
strptime(otras_fechas,"%d%b%Y")
[1] "2016-02-02 MST" "1990-06-18 MDT" "1995-11-07 MST"

¿Qué hicimos?

Leímos un conjunto de fechas que tenían un formato de día, seguido del nombre del mes y por último el año completo y se lo hicimos saber a R indicándole %día, luego %mes y por último %año.

Ahora cada vez que tengamos fechas, sabremos que debemos indicarle a R qué contienen esos datos y qué es qué guiándonos con la tabla provista.

Cálculos con el tiempo:

Para tener la diferencia entre dos fechas, podemos echar mano de la función difftime(). Hay que tomar en cuenta que esta función nos devuelve un objeto de clase difftime

Diferencias entre fechas en un vector

# Primero hacemos un objeto a clase difftime:
as.difftime(otras_fechas, "%d%b%Y")
Time differences in days
[1]  -2415 -11775  -9807

Cálculos con dos objetos:

Hay cálculos que se pueden generar con fechas y horas, ya sea sumando a una fecha o a una hora un número (que representará segundos), también entre fechas/horas e inclusive la utilización de operadores lógicos.

# vamos a generar dos fechas:

fecha_1 <- as.POSIXlt("2018-01-01")
fecha_2 <- as.POSIXlt("2017-01-02")
  • Y podemos sumar una fecha con un número:
fecha_1 + 100000
[1] "2018-01-02 03:46:40 MST"

Esto nos suma cien mil segundos, lo cual agrega 3 horas, 46 minutos y 40 segundos a la fecha que habíamos creado.

  • Podemos resta esa misma cantidad de segundos:
fecha_1 - 100000
[1] "2017-12-30 20:13:20 MST"

Vemos que nos devuelve al 30 de diciembre del 2017 a las 20 con 13 minutos y 20 segundos.

  • Restarle a la fecha 1 la fecha 2:
fecha_1 - fecha_2
Time difference of 364 days

Nos dice que entre las fechas hay 364 días.

  • Hacer una operación lógica:
fecha_1 <= fecha_2
[1] FALSE

Si decimos que fecha_1 es menor o igual que fecha_2 R nos dice que eso es falso.

Diferencia de días:

Si tenemos una pregunta como: ¿Cuántos días han transcurrido desde el 1 de diciembre del 2017 al 2 de enero del 2018?

difftime("2018-01-02","2017-12-01")
Time difference of 32 days

La respuesta es que han transcurrido 32 días.

Diferencia de horas:

En este caso, si tenemos horas en lugar de fechas, podemos hacer uso de la función as.difftime()

tiempo_1 <- as.difftime("12:00:00")
tiempo_2 <- as.difftime("17:20:00")
tiempo_2 - tiempo_1
Time difference of 5.333333 hours

Nos dice cuál es la diferencia en horas. (Si te preguntas porqué 5.33 en lugar de 5 horas y 20 minutos, recuerde que la respuesta está dada en horas y 20 minutos corresponden a 0.333 horas)

Generación de secuencias con tiempo:

Si queremos generar secuencias de fechas, años, meses, semanas etc, en R lo podemos realizar sin mucho problema:

Secuencia en aumento por día:

seq(as.POSIXlt("2018-01-01"), as.POSIXlt("2018-01-10"), "1 day")
 [1] "2018-01-01 MST" "2018-01-02 MST" "2018-01-03 MST" "2018-01-04 MST"
 [5] "2018-01-05 MST" "2018-01-06 MST" "2018-01-07 MST" "2018-01-08 MST"
 [9] "2018-01-09 MST" "2018-01-10 MST"

¿Qué hicimos? La función seq() nos genera un vector con una serie de valores de una secuencia, en este caso le indicamos dos elementos de tipo POSIXlt que corresponden a fechas y un último argumento que indica 1 día. Es decir, que del 1ero de enero del 2018 al 10 de enero del 2018 queremos una secuencia entre esas fechas que aumente de 1 día en 1 día.

Secuencia en aumento por semanas:

seq(as.POSIXlt("2018-01-01"), as.POSIXlt("2018-02-01"), "1 weeks")
[1] "2018-01-01 MST" "2018-01-08 MST" "2018-01-15 MST" "2018-01-22 MST"
[5] "2018-01-29 MST"

¿Qué hicimos? Nuevamente indicamos un par de fechas que delimitan el inicio y el final de la secuencia y por último le decimos que la secuencia aumente de semana en semana.

Esto lo podemos hacer de igual manera si queremos que la secuencia aumente por meses months o por años year

Secuencia en aumento por tiempo en segundos:

seq(as.POSIXlt("2018-01-01"),as.POSIXlt("2018-01-02"),8000)
 [1] "2018-01-01 00:00:00 MST" "2018-01-01 02:13:20 MST"
 [3] "2018-01-01 04:26:40 MST" "2018-01-01 06:40:00 MST"
 [5] "2018-01-01 08:53:20 MST" "2018-01-01 11:06:40 MST"
 [7] "2018-01-01 13:20:00 MST" "2018-01-01 15:33:20 MST"
 [9] "2018-01-01 17:46:40 MST" "2018-01-01 20:00:00 MST"
[11] "2018-01-01 22:13:20 MST"

En este caso 8000 segundos nos genera un aumento de 2 horas, 13 minutos y 20 segundos en cada elemento de la secuencia.

Secuencia sin especificación de final:

seq(as.POSIXlt("2018-01-01"), by = "weeks", length = 7)
[1] "2018-01-01 MST" "2018-01-08 MST" "2018-01-15 MST" "2018-01-22 MST"
[5] "2018-01-29 MST" "2018-02-05 MST" "2018-02-12 MST"

¿Qué hicimos? Generamos nuevamente una secuencia en donde sólo le indicamos la fecha en la que debe de iniciar, seguido del argumento semanas y por último la cantidad de objetos que debería de crear. Es decir, el final está generado por la cantidad (length) de elementos que queremos en esa secuencia.

Recuento.

¡Listo! Si has llegado hasta este punto, felicidades. Espero que haya comprendido mejor cómo trabajar y manejar este tipo de dato para sus propios análisis.

Hasta acá hemos visto cuáles son los tipos y la clase de las fechas y horas en R, la diferencia entre las dos manera de POSIX de representar las fechas u horas. También revisamos la manera en que se pueden leer archivos o conjuntos de datos que contengan elementos que corresponden a fechas y cómo indicarle a R el formato de fecha y hora que se está trabajando. Así mismo vimos cómo hacer algunos cálculos con datos de tiempo y por último la generación de secuencias.

Pero esto no es todo. Hay una segunda parte, en donde veremos cómo hacer un análisis de datos utilizando fechas y horas, tal como una regresión o un ANOVA.

Reuse

Citation

BibTeX citation:
@online{a. hernandez mora2018,
  author = {A. Hernandez Mora, Ronny},
  title = {Tiempo En {R}},
  date = {2018-03-14},
  url = {https://profound-caramel-d8abb6.netlify.app/posts/2021-12-11-tiempo-en-r},
  langid = {en}
}
For attribution, please cite this work as:
A. Hernandez Mora, Ronny. 2018. “Tiempo En R.” March 14, 2018. https://profound-caramel-d8abb6.netlify.app/posts/2021-12-11-tiempo-en-r.