Вычислить разницу во времени Pandas DataFrame между двумя столбцами в часах и минутах

85

У меня есть два столбца fromdateи todateв кадре данных.

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)

Я добавляю новый столбец, diffчтобы найти разницу между двумя датами, используя

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

Я получаю diffстолбец, но он содержит days, когда больше 24 часов.

                   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

Как преобразовать результаты только в часы и минуты (т.е. дни преобразованы в часы)?

sbalajis
источник

Ответы:

126

Различия в отметках времени Pandas возвращают объект datetime.timedelta. Это можно легко преобразовать в часы с помощью метода * as_type *, например

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]')

уступить,

0    58
1     3
2     8
dtype: float64
нитин
источник
Обходной путь Astype работает, но он слишком медленный для больших (0,5 миллиона строк) файлов. Есть другие предложения?
student1
3
Объект timedelta имеет атрибуты для дней и секунд ... да, (df.fr-df.to) .dt.days * 24 + (df.fr-df.to) .dt.seconds / 3600
nitin
1
Спасибо! Это сработало для меня и для расчета лет (для определения возраста): df ['age'] = (df ['later_date'] - df ['Birth_date']). Astype ('timedelta64 [Y]')
Superduper
49

Это сводило меня с ума, так как .astype()решение выше не сработало для меня. Но я нашел другой способ. Не рассчитал время или что-то в этом роде, но может сработать для других:

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

... если вам нужны часы. Или же:

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

... если тебе нужны минуты.

elPastor
источник
9
У меня была такая же проблема, но с вашим решением нужно быть осторожным, так как разница во времени, превышающая день, игнорируется и должна быть включена отдельно
подкова
41
Я только что обнаружил, что это .total_seconds()делает работу для тех, кто в ней нуждается
Подкова
Любопытно (я заметил 4 года спустя), вы должны использовать parens ()для, .total_seconds()но не.seconds
elPastor
5
  • Как преобразовать результаты в часы и минуты
    • Принятый ответ только возвращается days + hours. Минуты не включены.
  • Чтобы предоставить столбец с часами и минутами, как hh:mmилиx hours y minutes , потребуются дополнительные вычисления и форматирование строки.
  • Этот ответ показывает, как получить либо общее количество часов, либо общее количество минут в виде числа с плавающей запятой, используя timedeltaматематику, и он быстрее, чем при использовании.astype('timedelta64[h]')
  • Руководство пользователя Pandas Deltas Time
  • Pandas Руководство пользователя функции временных рядов / даты
  • timedeltaобъекты python : см. поддерживаемые операции.
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

Другие методы

  • Примечательный элемент из подкаста в других ресурсах .total_seconds()был добавлен и объединен, когда основной разработчик был в отпуске, и не получил одобрения.
    • Вот почему нет других .total_xxметодов.
# 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

Другие источники

%%timeit контрольная работа

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)
Трентон МакКинни
источник