You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pandas如何基于起止日期创建逐小时值映射的日历DataFrame

问题背景

现有存储业务记录的DataFrame,结构如下:

Name             First_date        End_date            Value
1   AAA         2022-06-18 00:00:00 2022-06-18 20:00:00      20
2   BBB         2022-06-19 14:00:00 2022-06-19 16:00:00      40
87  CCC         2022-06-18 04:00:00 2022-06-20 04:00:00      60
0   DDD         2022-06-18 00:00:00 2022-06-20 23:00:00      60
93  EEE         2022-06-26 05:30:00 2022-06-26 15:30:00      35
91  FFF         2022-06-18 00:00:00 2022-06-26 23:00:00      32
230 GGG         2022-06-18 00:00:00 2022-07-02 00:00:00      36
4265    HHH         2022-06-18 00:00:00 2022-07-02 18:00:00  40

另有预生成的空DataFrame,列是2022-06-18 00:00:00到2023-01-01的全部小时级时间点,共4705列。
需要实现的逻辑:

  • 结果表行索引使用源数据的Name字段
  • 对每一列(对应一个小时级时间点),若时间点落在某条记录的First_date和End_date区间内,将对应Value填入单元格,未命中则填0
    预期输出样例:
Index            2022-06-18 00:00:00 2022-06-18 01:00:00 2022-06-18 02:00:00    ...
AAA              20                  20                  20
BBB              0                   0                   0
CCC              0                   0                   0
DDD              60                  60                  60
EEE              0                   0                   0
FFF              32                  32                  32
GGG              36                  36                  36
HHH              40                  40                  40

此前尝试使用groupby搭配agg(sum)实现,未得到正确结果。

解决方案

直接用NumPy广播做批量区间判断即可,不需要逐行循环、也不需要先把区间展开成长表再聚合,在4700列的场景下运行效率远高于apply或groupby方案,且边界判断准确。
首先确保源数据的时间列已转换为datetime类型,避免字符串比较出错:

import pandas as pd
import numpy as np

# 源数据时间列格式转换
df["First_date"] = pd.to_datetime(df["First_date"])
df["End_date"] = pd.to_datetime(df["End_date"])

# 若已经预生成了空的小时级DataFrame,直接取其columns即可,无需重复生成
time_columns = pd.date_range(start="2022-06-18 00:00:00", end="2023-01-01", freq="H")

# 批量生成布尔判断矩阵:形状为(源数据行数, 时间点数量),值为True代表该时间点落在对应记录的时间区间内
in_range_mask = (time_columns.values >= df["First_date"].values[:, np.newaxis]) & \
                (time_columns.values <= df["End_date"].values[:, np.newaxis])

# 命中区间的位置填充对应Value,未命中填0
result_values = np.where(in_range_mask, df["Value"].values[:, np.newaxis], 0)

# 组装为最终结果表
result_df = pd.DataFrame(
    data=result_values,
    index=df["Name"],
    columns=time_columns
)

关于之前groupby+agg(sum)方案失效的说明

这类方案的常规思路是先把每条记录的时间区间拆成对应的小时级时间点,构造成长表后按Name+时间点聚合求和。失效通常是两个原因:

  • 拆分时间区间时没有对齐整点规则,非整点的起止时间(比如EEE的05:30起始、HHH的18:00结束)处理错误,把不在区间内的小时点算入了范围
  • 拆分长表后没有去重,出现同一条记录对应同一个时间点多次计数的问题
    上面的广播方案直接做时间值的大小比较,不需要做区间拆分,天然规避了这两个问题。如果需要调整区间规则(比如改成左闭右开),直接修改判断条件里的比较运算符即可。

内容的提问来源于stack exchange,提问作者nicolax9777

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 09:27:15