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

基于Pandas统计时间点活跃进程数(优化双重循环方案)

问题描述

我有一个包含start_time和end_time列的数据集,使用以下示例测试数据:

import pandas as pd
d = {'start_time': ["2023-05-03 10:30:00", "2023-05-03 10:02:00", "2023-05-03 10:10:00", "2023-05-03 11:00:00", "2023-05-03 11:05:00"], 'end_time': ["2023-05-03 10:35:00", "2023-05-03 10:20:00", "2023-05-03 10:32:00", "2023-05-03 11:10:00", "2023-05-03 11:09:00"]}
df = pd.DataFrame(data=d)

df["start_time"] = pd.to_datetime(df["start_time"])
df["end_time"] = pd.to_datetime(df["end_time"])

需求是:生成一个新的DataFrame,提取原数据中的最小时间和最大时间,生成30分钟间隔的时间序列,统计每个时间点处于活跃状态(时间点落在对应行的start_time和end_time之间)的记录数。预期结果示例:

timecount
2023-05-03 10:02:001
2023-05-03 10:32:003
2023-05-03 11:02:001

我已通过以下代码生成时间序列:

idx = pd.date_range(df["start_time"].min(), df["end_time"].max(), freq="30T").to_frame(index=False, name='time')

但目前使用双重循环统计活跃数,效率极低:

count = 0
for ind, row in idx.iterrows():
  for ind1, row1 in df.iterrows():
    if(row["time"] >= row1["start_time"] and row["time"] <= row1["end_time"]):
      print("Entering here...")
      count += 1

请问如何优化实现该需求?

优化方案

方法1:向量化广播(中小型数据集适用)

利用pandas/numpy的广播特性,直接进行批量比较,避免显式循环,代码简洁且效率远高于双重循环:

# 生成目标时间序列
idx = pd.date_range(df["start_time"].min(), df["end_time"].max(), freq="30T").to_frame(index=False, name='time')

# 向量化计算每个时间点的活跃记录数
idx['count'] = (
    (idx['time'].values[:, None] >= df['start_time'].values) & 
    (idx['time'].values[:, None] <= df['end_time'].values)
).sum(axis=1)

原理:将时间点数组转为二维结构,与start_time/end_time的一维数组进行广播比较,得到布尔型矩阵后,对每行求和即可得到对应时间点的活跃数。

方法2:事件计数法(大型数据集适用)

通过转换事件类型并计算累积活跃数,再匹配目标时间点,时间复杂度为O(n log n),适合数据量较大的场景:

# 创建事件数据集:开始事件记为+1,结束事件(结束时间+1秒)记为-1
events = pd.concat([
    df['start_time'].to_frame(name='time').assign(type=1),
    (df['end_time'] + pd.Timedelta(seconds=1)).to_frame(name='time').assign(type=-1)
])

# 按时间排序事件
events = events.sort_values('time')

# 计算累积活跃数
events['active'] = events['type'].cumsum()

# 生成目标时间序列
idx = pd.date_range(df["start_time"].min(), df["end_time"].max(), freq="30T").to_frame(index=False, name='time')

# 用merge_asof匹配每个时间点最近的前置事件,获取当前活跃数
result = pd.merge_asof(idx.sort_values('time'), events.sort_values('time'), on='time', direction='backward')

# 处理空值并整理结果
result['count'] = result['active'].fillna(0).astype(int)
result = result[['time', 'count']].sort_values('time').reset_index(drop=True)

原理:将每个时间区间的开始和结束转化为增减事件,通过累积求和得到任意时间点的活跃数,再用merge_asof快速匹配目标时间点对应的活跃状态,避免了逐行比较的低效操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 09:17:08