Redondear la hora en Python para agrupar datos

Publicado el 26 octubre 2020 por Daniel Rodríguez @analyticslane

Un problema con el que nos podemos encontrar: tenemos un conjunto de datos que se captura con la hora y queremos calcular el total o la media cada 10 o 15 minutos. Por ejemplo, para crear un informe de las ventas de una tienda on-line. Este problema es fácil de resolver si sabemos redondear los datos de horas y crear tablas dinámicas. Para redondear la hora el Python se puede utilizar los métodos round(), floor() y ceil() de los objetos Timestamp de Pandas.

Redondear la hora con Pandas

Las propiedad round(), floor() y ceil() funciona de manera similar a cómo lo hacen las versiones que existen para números. La función round() redondea a la hora más cercana que cumple el criterio, floor() devuelve a la hora inferior a la indicada que cumple el criterio y ceil() devuelve la hora superior. Lo que se puede ver en el siguiente ejemplo:

import pandas as pd

dt = pd.Timestamp('2020-09-01 12:44:12')

dt.round('min') # 2020-09-01 12:44:00
dt.floor('min') # 2020-09-01 12:44:00
dt.ceil('min')  # 2020-09-01 12:45:00

dt.round('5 min') # 2020-09-01 12:45:00
dt.floor('5 min') # 2020-09-01 12:40:00
dt.ceil('5 min')  # 2020-09-01 12:45:00

En este ejemplo se ha creado una objeto Timestamp de Pandas y se ha redondeado las fechas a minutos y a grupos de cinco minutos. En este ejemplo vemos que round(), como era de esperar, devuelve la hora más cercana mientras que floor() devuelve la hora anterior y ceil() la superior.

Por otro lado, se puede indicar mediante una cadena de texto el intervalo de tiempo al que se desea redondear. Pudiendo ser cualquier unidad como un minuto ( min), 5 minutos ( 5 min) o 12 minutos ( 12 min). Algo que se puede hacer con las horas utilizando H.

Agrupar datos

Una vez que sabemos cómo redondear los datos no podemos la agrupación es trivial, algo que ya hemos vistos cuando explicamos las tablas dinámicas de Pandas. Por ejemplo, se puede crear un registro de datos en el que cada dos minutos se contabilizan las unidades vendidas.

df = pd.DataFrame({'time': pd.date_range('2020-09-01', periods=15, freq='2 min'),
                   'units':range(15)})
                  time  units
0  2020-09-01 00:00:00      0
1  2020-09-01 00:02:00      1
2  2020-09-01 00:04:00      2
3  2020-09-01 00:06:00      3
4  2020-09-01 00:08:00      4
5  2020-09-01 00:10:00      5
6  2020-09-01 00:12:00      6
7  2020-09-01 00:14:00      7
8  2020-09-01 00:16:00      8
9  2020-09-01 00:18:00      9
10 2020-09-01 00:20:00     10
11 2020-09-01 00:22:00     11
12 2020-09-01 00:24:00     12
13 2020-09-01 00:26:00     13
14 2020-09-01 00:28:00     14

Si queremos agrupar estos valores en unidades de 10 minutos, solamente se tiene que aplicar una de las propiedades anteriores con la opción 10 min. De este modo se puede actualizar los valores del DataFrame para ver los datos con la hora redondeada.

df['time'] = df['time'].apply(lambda x: x.floor('10 min'))
                  time  units
0  2020-09-01 00:00:00      0
1  2020-09-01 00:00:00      1
2  2020-09-01 00:00:00      2
3  2020-09-01 00:00:00      3
4  2020-09-01 00:00:00      4
5  2020-09-01 00:10:00      5
6  2020-09-01 00:10:00      6
7  2020-09-01 00:10:00      7
8  2020-09-01 00:10:00      8
9  2020-09-01 00:10:00      9
10 2020-09-01 00:20:00     10
11 2020-09-01 00:20:00     11
12 2020-09-01 00:20:00     12
13 2020-09-01 00:20:00     13
14 2020-09-01 00:20:00     14

En este punto ya solo nos queda agrupar, para lo que usaremos la propiedad pivot_table() disponible en todos los DataFrames de Pandas.

import numpy as np

df = df.pivot_table('units', 'time', aggfunc=np.sum)
                     units
time                      
2020-09-01 00:00:00     10
2020-09-01 00:10:00     35
2020-09-01 00:20:00     60

Conclusiones

En esta entrada hemos visto cómo redondear la hora en Python con las funciones que nos proporciona Pandas. Unas funciones con las que realizar cálculos que de otra forma podría ser bastante tediosas.

Imagen de Michal Jarmoluk en Pixabay