Calcule a diferença de tempo do Pandas DataFrame entre duas colunas em horas e minutos

85

Eu tenho duas colunas fromdatee todate, em um dataframe.

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)

Eu adiciono uma nova coluna,, diffpara encontrar a diferença entre as duas datas usando

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

Recebo a diffcoluna, mas contém days, quando há mais 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

Como faço para converter meus resultados em apenas horas e minutos (ou seja, os dias são convertidos em horas)?

sbalajis
fonte

Respostas:

126

As diferenças de carimbo de data / hora do Pandas retornam um objeto datetime.timedelta. Isso pode ser facilmente convertido em horas usando o método * as_type *, assim

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
fonte
A solução alternativa de astype funciona, mas é muito lenta para arquivos grandes (0,5 milhão de linhas). Alguma outra sugestão?
aluno1
3
objeto timedelta tem atributos para dias e segundos ... você tem, (df.fr-df.to) .dt.days * 24 + (df.fr-df.to) .dt.seconds / 3600
nitin
1
Obrigado! Isso funcionou para mim para calcular anos (para obter a idade), também: df ['idade'] = (df ['data_de_alterno'] - df ['data_de_nascimento']). Astype ('timedelta64 [Y]')
Superduper
49

Isso estava me deixando maluco, pois a .astype()solução acima não funcionava para mim. Mas encontrei outro jeito. Não cronometrou nem nada, mas pode funcionar para outras pessoas:

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

... se você quiser horas. Ou:

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

... se você quiser minutos.

elPastor
fonte
9
Eu tive o mesmo problema, mas com a sua solução é preciso ter cuidado, pois as diferenças de tempo maiores que um dia são ignoradas e precisam ser incluídas separadamente
ferradura
41
Acabei de descobrir que .total_seconds()faz o trabalho para aqueles que precisam
ferradura,
Curiosamente (noto 4 anos depois), você tem que usar parênteses ()para, .total_seconds()mas não.seconds
elPastor
5
  • Como faço para converter meus resultados para apenas horas e minutos
    • A resposta aceita apenas retorna days + hours. Os minutos não estão incluídos.
  • Para fornecer uma coluna com horas e minutos, como hh:mmou x hours y minutes, seriam necessários cálculos adicionais e formatação de string.
  • Esta resposta mostra como obter o total de horas ou o total de minutos como um float, usando timedeltamatemática, e é mais rápido do que usando.astype('timedelta64[h]')
  • Guia do usuário do Pandas Time Deltas
  • Guia do usuário da funcionalidade de série / data do Pandas
  • timedeltaobjetos python : veja as operações compatíveis.
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

Outros métodos

  • Um item de observação do podcast em Outros Recursos .total_seconds()foi adicionado e mesclado quando o desenvolvedor principal estava de férias e não teria sido aprovado.
    • É também por isso que não existem outros .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

Outros recursos

%%timeit teste

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
fonte