计算两个 Pandas 列之间的时间差(以小时和分钟为单位)
- 2024-12-12 08:40:00
- admin 原创
- 247
问题描述:
我在数据框中有两列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
如何将结果转换为小时和分钟(即将天转换为小时)?
解决方案 1:
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
解决方案 2:
这让我很抓狂,因为.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
...如果您需要几分钟。
更新:这里曾经有一个有用的评论,提到使用.total_seconds()
跨越多天的时间段。由于它消失了,我更新了答案。
解决方案 3:
如何将结果转换为小时和分钟?
被接受的答案仅返回
days + hours
。不包括分钟数。
要提供一个包含小时和分钟的列
hh:mm
,或x hours y minutes
,需要额外的计算和字符串格式化。这个答案显示了如何使用数学运算以浮点数获取总小时数或总分钟数
timedelta
,并且比使用更快.astype('timedelta64[h]')
。按照
pandas v2.0.0
,.astype('timedelta64[h]')
是不允许的。
Pandas 时间增量用户指南
Pandas 时间序列/日期功能用户指南
python
timedelta
对象:查看支持的操作。以下示例数据已经是
datetime64[ns] dtype
。要求所有相关列都使用 进行转换pandas.to_datetime()
。已在
python 3.11.2
、pandas 2.0.1
、进行测试numpy 1.24.3
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
其他资源
跟我聊 Python:第 271 集:解开时间的奥秘,也就是 Python 的日期时间!
Timedelta 从 31 分钟开始
根据 Python 核心开发人员Paul Ganssle和Python
dateutil
维护者的说法:使用
(df.from_date - df.to_date) / pd.Timedelta(hours=1)
不要使用
(df.from_date - df.to_date).dt.total_seconds() / 3600
pandas.Series.dt.total_seconds
.dt
访问器
真正的 Python:使用 Python datetime 处理日期和时间
该
dateutil
模块为标准datetime
模块提供了强大的扩展。
%%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]:
24.2 ms ± 2.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit (df.from_date - df.to_date).astype('timedelta64[h]')
[out]:
ValueError: Cannot convert from timedelta64[ns] to timedelta64[D]. Supported resolutions are 's', 'ms', 'us', 'ns'
解决方案 4:
默认情况下,pandas 中的时间差以纳秒为单位,即timedelta64[ns]
,因此将其转换为秒/分钟/小时/等的一种方法是将其纳秒表示形式除以 以10**9
转换为秒,除以 以转换60*10**9
为分钟等。此方法比本页建议的其他方法至少快 3 倍。1
df['diff_in_seconds'] = df['from_date'].sub(df['to_date']).view('int64') // 10**9
df['diff_in_minutes'] = df['from_date'].sub(df['to_date']).view('int64') // (60*10**9)
df['diff_in_hours'] = df['from_date'].sub(df['to_date']).view('int64') // (3600*10**9)
PS:上面的代码假设您想要整秒、分、小时等的差值,因此它使用整数除法 ( //
),但如果您也想要小数,则使用真除法 ( /
)。也就是说,如果您想要精确的差值,那么请考虑将差值转换为更高精度(毫秒/微秒/等),而不是小数秒/分/小时。
1使用Trenton McKinney 设置的一些基准:
data = {'to_date': [pd.Timestamp('2014-01-24 13:03:12.050000'), pd.Timestamp('2014-01-27 11:57:18.240000')]*1000000,
'from_date': [pd.Timestamp('2014-01-26 23:41:21.870000'), pd.Timestamp('2014-01-27 15:38:22.540000')]*1000000}
df = pd.DataFrame(data)
df['Diff'] = df['from_date'] - df['to_date']
%timeit df['Diff'].view('int64') // (3600*10**9)
# 11 ms ± 271 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df['Diff'] // pd.Timedelta(hours=1)
# 36.7 ms ± 2.99 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df['Diff'].astype('timedelta64[h]')
# 46.5 ms ± 865 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df['Diff'].dt.total_seconds() // 3600
# 169 ms ± 7.71 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
扫码咨询,免费领取项目管理大礼包!