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

如何用Pandas高效构建DateTime值的累计统计?

优化Pandas分钟级事件累计统计的向量化方案

问题背景

现有包含事件起始(Start)和结束(Finish)时间的Pandas DataFrame,需要统计每个分钟级时间点落在事件区间内的累计次数。原代码通过双重循环实现,虽能运行但在千行级数据下性能极差,需替换为向量化方案。

原性能低下的代码

数据初始化与时间范围生成

import pandas as pd
from datetime import date

data = {
    "Date": [date(2024,1,5), date(2024,1,6), date(2024,1,7)],
    "Start": [pd.Timestamp("2024-01-05 10:05"), pd.Timestamp("2024-01-06 09:05"), pd.Timestamp("2024-01-07 11:12")],
    "Finish": [pd.Timestamp("2024-01-05 10:35"), pd.Timestamp("2024-01-06 09:55"), pd.Timestamp("2024-01-07 11:58")]
}
df = pd.DataFrame(data)

# 生成全量分钟级时间范围
dates = pd.date_range(start=df["Date"].min(), end=df["Date"].max(), freq="1min")

# 初始化存储累计次数的字典
d_data = {x: 0 for x in dates}

待优化的双重循环(性能瓶颈)

# 双重循环遍历事件与时间点,时间复杂度O(n*m),数据量大时极慢
for index, row in df.iterrows():
    for d in dates:
        if (d >= row[1]) & (d <= row[2]):
            d_data[d] += 1

后续结果处理

# 转换为DataFrame并按时间分组求和
df_data = pd.DataFrame(index=d_data.keys(), data=d_data.values(), columns=["Count"])
df_data.reset_index(names="Date", inplace=True)

# 提取时间部分(去除日期)并格式化
df_data["Date"] = df_data["Date"].dt.time.astype(str).str[:-3]

# 按时间分组求和
df_data = df_data.groupby("Date").sum().reset_index()

向量化优化方案

利用Pandas的date_range和value_counts实现无循环统计,性能提升显著:

import pandas as pd
from datetime import date

# 1. 数据初始化(同原代码)
data = {
    "Date": [date(2024,1,5), date(2024,1,6), date(2024,1,7)],
    "Start": [pd.Timestamp("2024-01-05 10:05"), pd.Timestamp("2024-01-06 09:05"), pd.Timestamp("2024-01-07 11:12")],
    "Finish": [pd.Timestamp("2024-01-05 10:35"), pd.Timestamp("2024-01-06 09:55"), pd.Timestamp("2024-01-07 11:58")]
}
df = pd.DataFrame(data)

# 2. 生成每个事件覆盖的所有分钟时间点,合并后统计次数
all_minutes = pd.concat([
    pd.date_range(start=row["Start"], end=row["Finish"], freq="1min")
    for _, row in df.iterrows()
]).value_counts().sort_index()

# 3. 对齐全量时间范围,填充未覆盖时间点的0值
full_dates = pd.date_range(start=df["Date"].min(), end=df["Date"].max(), freq="1min")
df_data = all_minutes.reindex(full_dates, fill_value=0).rename("Count").reset_index(names="Date")

# 4. 后续处理(同原代码)
df_data["Date"] = df_data["Date"].dt.time.astype(str).str[:-3]
df_data = df_data.groupby("Date").sum().reset_index()

优化原理

  • 直接生成每个事件覆盖的分钟序列,避免逐时间点的区间判断
  • 用value_counts一次性统计所有分钟的出现次数,替代双重循环
  • 用reindex对齐全量时间范围,自动填充未覆盖时间点的0值

该方案在千行级数据下性能提升可达数十倍,完全规避原循环的性能瓶颈。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 14:23:24