首页 > 解决方案 > Pandas/Numpy - 向量化日期时间计算

问题描述

tl;博士

  1. 我需要以最快的方式df.dates[iter]-df.dates[initial_fixed]索引数据帧的每个切片item_id(为了学习和提高技能......和截止日期)。

  2. 如何计算这些相同日期之间的营业时间,而不仅仅是直接时间。而且我需要部分天数(例如 4.763 天)而不仅仅是一个整数.days

你好,

首先,我有一个数据框df

item_id      dates               new_column   ...   other_irrelevant_columns

101          2020-09-10-08-...   FUNCTION           -neglected-
101          2020-09-18-17-...   FUNCTION           -neglected-
101          2020-10-03-11-...   FUNCTION           -neglected-

107          2017-08-dd-hh-...   FUNCTION           -neglected-
107          2017-09-dd-hh-...   FUNCTION           -neglected-

209          2019-01-dd-hh-...   FUNCTION           -neglected
209          2019-01-dd-hh-...   FUNCTION           -neglected-
209          2019-01-dd-hh-...   FUNCTION           -neglected-
209          2019-01-dd-hh-...   FUNCTION           -neglected-

其中日期列(类型 = datetime 对象)按 item_id 的时间顺序排列,因此第一个实例是最早的日期。

我有超过 400,000 行,我需要通过每个 item_id 获取每个日期时间和原始日期时间之间的距离来计算经过的时间。然后有一个序列

item_id      dates               [new_column        = elapsed_time]   ...   other_irrelevant_columns

101          2020-09-10-08-...   [dates[0]-dates[0] = 0       days]         -neglected- for plotting
101          2020-09-18-17-...   [dates[1]-dates[0] = 8.323   days]         -neglected-
101          2020-10-03-11-...   [dates[2]-dates[0] = 23.56   days]         -neglected-

目前,我被困在一个for我认为是矢量化的循环中,它计算 a 的总秒数timedelta并将天数转换为浮点数:

for id in df.item_id:
    df.elapsed_days[df.item_id == id] = ((df.dates[df.item_id == id] - min(df.dates[df.boot_id == id])).dt.total_seconds()/86400).astype(float)

这是永远的。不是数据科学精神。我想知道的是,无论是使用带有 lambda 的 apply() 还是执行此操作的更好方法,并且我尝试使用这篇文章中的 digitize 和 isin()但无法理解如何将 item_id 装箱让它起作用。

其次,我也对类似的持续时间感兴趣,但仅限于工作时间(上午 8 点至下午 6 点,加拿大没有周末或节假日),因此item可以测量活动的实时时间。

谢谢你的帮助。

标签: pythonpandasnumpydatetimeoptimization

解决方案


您可以使用join更快地做到这一点。

首先,您需要像在当前代码中一样执行 min :

tmp = df.loc[df['item_id'] == df['boot_id']] # row filtering
tmp = df[['item_id','date']] # column filtering
dateMin = tmp.groupby('item_id', as_index=False).min() # Find the minimal date for each item_id

然后你可以进行合并:

# Actual merge
indexed_df = df.set_index('item_id')
indexed_dateMin = dateMin.set_index('item_id')
merged = indexed_df.join(indexed_dateMin, lsuffix='_df', rsuffix='_dateMin')

# Vectorized computation
df['elapsed_days'] = (merged['date_df'] - merged['date_dateMin']).dt.total_seconds()/86400).astype(float)

推荐阅读