Calcular la diferencia de tiempo de Pandas DataFrame entre dos columnas en horas y minutos

85

Tengo dos columnas fromdatey todate, en un marco de datos.

import pandas as pd

data = {'todate': [pd.Timestamp('2014-01-24 13:03:12.050000'), pd.Timestamp('2014-01-27 11:57:18.240000'), pd.Timestamp('2014-01-23 10:07:47.660000')],
        'fromdate': [pd.Timestamp('2014-01-26 23:41:21.870000'), pd.Timestamp('2014-01-27 15:38:22.540000'), pd.Timestamp('2014-01-23 18:50:41.420000')]}

df = pd.DataFrame(data)

Agrego una nueva columna, diffpara encontrar la diferencia entre las dos fechas usando

df['diff'] = df['fromdate'] - df['todate']

Recibo la diffcolumna, pero contiene days, cuando hay más de 24 horas.

                   todate                fromdate                   diff
0 2014-01-24 13:03:12.050 2014-01-26 23:41:21.870 2 days 10:38:09.820000
1 2014-01-27 11:57:18.240 2014-01-27 15:38:22.540 0 days 03:41:04.300000
2 2014-01-23 10:07:47.660 2014-01-23 18:50:41.420 0 days 08:42:53.760000

¿Cómo convierto mis resultados a solo horas y minutos (es decir, los días se convierten en horas)?

sbalajis
fuente

Respuestas:

123

Las diferencias de marca de tiempo de Pandas devuelven un objeto datetime.timedelta. Esto se puede convertir fácilmente en horas usando el método * as_type *, así

import pandas
df = pandas.DataFrame(columns=['to','fr','ans'])
df.to = [pandas.Timestamp('2014-01-24 13:03:12.050000'), pandas.Timestamp('2014-01-27 11:57:18.240000'), pandas.Timestamp('2014-01-23 10:07:47.660000')]
df.fr = [pandas.Timestamp('2014-01-26 23:41:21.870000'), pandas.Timestamp('2014-01-27 15:38:22.540000'), pandas.Timestamp('2014-01-23 18:50:41.420000')]
(df.fr-df.to).astype('timedelta64[h]')

ceder,

0    58
1     3
2     8
dtype: float64
nitin
fuente
La solución alternativa de un tipo funciona, pero es demasiado lenta para archivos grandes (0,5 millones de filas). ¿Cualquier otra sugerencia?
estudiante1
3
El objeto timedelta tiene atributos para días y segundos ... usted lo hace, (df.fr-df.to) .dt.days * 24 + (df.fr-df.to) .dt.seconds / 3600
nitin
1
¡Gracias! Esto también me funcionó para calcular los años (para obtener la edad): df ['age'] = (df ['later_date'] - df ['birth_date']). Astype ('timedelta64 [Y]')
Superduper
47

Esto me estaba volviendo loco ya que la .astype()solución anterior no funcionó para mí. Pero encontré otra forma. No lo he cronometrado ni nada, pero podría funcionar para otros:

t1 = pd.to_datetime('1/1/2015 01:00')
t2 = pd.to_datetime('1/1/2015 03:30')

print pd.Timedelta(t2 - t1).seconds / 3600.0

... si quieres horas. O:

print pd.Timedelta(t2 - t1).seconds / 60.0

... si quieres minutos.

elPastor
fuente
9
Yo tenía el mismo problema, pero con su solución Uno tiene que tener cuidado ya que las diferencias de tiempo de más de un día son ignorados y necesidad de ser incluidos por separado
herradura
39
Acabo de descubrir que .total_seconds()hace el trabajo para aquellos que lo necesitan
Herradura
Curiosamente (me doy cuenta 4 años después), tienes que usar parens ()para .total_seconds()pero no.seconds
elPastor
5
import pandas as pd

# test data from OP, with values already in a datetime format
data = {'to_date': [pd.Timestamp('2014-01-24 13:03:12.050000'), pd.Timestamp('2014-01-27 11:57:18.240000'), pd.Timestamp('2014-01-23 10:07:47.660000')],
        'from_date': [pd.Timestamp('2014-01-26 23:41:21.870000'), pd.Timestamp('2014-01-27 15:38:22.540000'), pd.Timestamp('2014-01-23 18:50:41.420000')]}

# test dataframe; the columns must be in a datetime format; use pandas.to_datetime if needed
df = pd.DataFrame(data)

# add a timedelta column if wanted. It's added here for information only
# df['time_delta_with_sub'] = df.from_date.sub(df.to_date)  # also works
df['time_delta'] = (df.from_date - df.to_date)

# create a column with timedelta as total hours, as a float type
df['tot_hour_diff'] = (df.from_date - df.to_date) / pd.Timedelta(hours=1)

# create a colume with timedelta as total minutes, as a float type
df['tot_mins_diff'] = (df.from_date - df.to_date) / pd.Timedelta(minutes=1)

# display(df)
                  to_date               from_date             time_delta  tot_hour_diff  tot_mins_diff
0 2014-01-24 13:03:12.050 2014-01-26 23:41:21.870 2 days 10:38:09.820000      58.636061    3518.163667
1 2014-01-27 11:57:18.240 2014-01-27 15:38:22.540 0 days 03:41:04.300000       3.684528     221.071667
2 2014-01-23 10:07:47.660 2014-01-23 18:50:41.420 0 days 08:42:53.760000       8.714933     522.896000

Otros metodos

  • Se .total_seconds()agregó un elemento destacado del podcast en Otros recursos y se fusionó cuando el desarrollador principal estaba de vacaciones y no se habría aprobado.
    • Por eso también no existen otros .total_xxmétodos.
# convert the entire timedelta to seconds
# this is the same as td / timedelta(seconds=1)
(df.from_date - df.to_date).dt.total_seconds()
[out]:
0    211089.82
1     13264.30
2     31373.76
dtype: float64

# get the number of days
(df.from_date - df.to_date).dt.days
[out]:
0    2
1    0
2    0
dtype: int64

# get the seconds for hours + minutes + seconds, but not days
# note the difference from total_seconds
(df.from_date - df.to_date).dt.seconds
[out]:
0    38289
1    13264
2    31373
dtype: int64

Otros recursos

%%timeit prueba

import pandas as pd

# dataframe with 2M rows
data = {'to_date': [pd.Timestamp('2014-01-24 13:03:12.050000'), pd.Timestamp('2014-01-27 11:57:18.240000')], 'from_date': [pd.Timestamp('2014-01-26 23:41:21.870000'), pd.Timestamp('2014-01-27 15:38:22.540000')]}
df = pd.DataFrame(data)
df = pd.concat([df] * 1000000).reset_index(drop=True)

%%timeit
(df.from_date - df.to_date) / pd.Timedelta(hours=1)
[out]:
43.1 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
(df.from_date - df.to_date).astype('timedelta64[h]')
[out]:
59.8 ms ± 1.29 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Trenton McKinney
fuente