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

如何基于Pandas高效筛选接近00/06/12/18点的时间索引行数据

高效构建可缓存的时间窗口索引方案

针对你的百万行级有序时间序列DataFrame,我们可以利用二分查找和预计算时间窗口索引的方式,构建可重复使用的缓存索引,实现快速查询目标时间窗口内的数据。

核心思路

  1. 确保时间列是UTC格式的datetime类型,避免时区问题。
  2. 生成覆盖整个数据时间跨度的所有目标时间点(00:00z、06:00z、12:00z、18:00z)。
  3. 对每个目标时间点,计算前后15分钟的时间窗口,利用DataFrame已排序的特性,用searchsorted快速定位窗口内数据的起始和结束索引(O(log n)复杂度)。
  4. 缓存这些索引范围,后续查询直接通过索引切片获取数据,无需重复计算。

完整实现代码

import numpy as np
import pandas as pd
np.random.seed(1)

# 生成示例数据(模拟非规则间隔可以打乱部分时间点)
rows = 50000
data = np.random.rand(rows)
tidx = pd.date_range('2010-01-01', periods=rows, freq='T')
# 随机删除10%的行,模拟非规则间隔
drop_idx = np.random.choice(tidx.size, int(rows*0.1), replace=False)
tidx = tidx.delete(drop_idx)
data = np.delete(data, drop_idx)
data_frame = pd.DataFrame({"time": tidx, "value": data})
# 确保时间列是UTC datetime类型
data_frame['time'] = pd.to_datetime(data_frame['time'], utc=True)

# ---------------------- 构建缓存索引 ----------------------
def build_time_window_index(df, target_hours=[0,6,12,18], window_minutes=15):
    # 获取数据的时间范围
    min_time = df['time'].min()
    max_time = df['time'].max()
    
    # 生成第一个目标时间点(向上取整到最近的target_hours中的时间)
    first_target = min_time.floor('D')
    while first_target.hour not in target_hours:
        first_target += pd.Timedelta(hours=1)
    # 如果第一个目标时间比min_time早,就加6小时(因为target_hours间隔6小时)
    if first_target < min_time:
        first_target += pd.Timedelta(hours=6)
    
    # 生成所有目标时间点(间隔6小时,覆盖到max_time之后的最近目标点)
    last_target = max_time.ceil('D')
    while last_target.hour not in target_hours:
        last_target += pd.Timedelta(hours=1)
    target_times = pd.date_range(start=first_target, end=last_target, freq='6H', utc=True)
    
    # 预计算每个目标时间的窗口索引范围
    index_cache = []
    time_values = df['time'].values  # 提取numpy datetime数组,加速searchsorted
    window = pd.Timedelta(minutes=window_minutes)
    
    for target in target_times:
        window_start = target - window
        window_end = target + window
        
        # 用searchsorted找窗口的起始和结束索引
        start_idx = df['time'].searchsorted(window_start, side='left')
        end_idx = df['time'].searchsorted(window_end, side='right')
        
        if start_idx < end_idx:
            index_cache.append((start_idx, end_idx))
        else:
            index_cache.append(None)  # 无数据的窗口存None
    
    return index_cache, target_times

# 构建缓存索引
index_cache, target_times = build_time_window_index(data_frame)

# ---------------------- 使用缓存索引查询 ----------------------
def get_window_data(df, index_cache, idx):
    if idx < 0 or idx >= len(index_cache):
        return pd.DataFrame()  # 索引越界返回空DataFrame
    idx_range = index_cache[idx]
    if idx_range is None:
        return pd.DataFrame()
    start, end = idx_range
    return df.iloc[start:end].copy()

# 测试查询
# index[0]:2010-01-01 00:00前后15分钟的数据
print("index[0]的数据:")
print(get_window_data(data_frame, index_cache, 0))

# index[1]:2010-01-01 06:00前后15分钟的数据
print("\nindex[1]的数据:")
print(get_window_data(data_frame, index_cache, 1))

关键细节说明

  • searchsorted的高效性:因为DataFrame的时间列是已排序的,searchsorted通过二分查找定位索引,时间复杂度为O(log n),百万级数据也能瞬间完成。
  • 缓存复用:index_cache存储的是每个窗口的起始/结束索引,后续查询直接用iloc切片,无需重复计算时间窗口和索引,性能拉满。
  • 处理非规则间隔:不管原始数据是规则还是非规则时间间隔,只要时间列是有序的,该方案都能正常工作。
  • 空窗口处理:如果某个目标时间窗口内没有数据,缓存中会存None,查询时返回空DataFrame,符合需求。

性能优化点

  • 提取df['time'].values为numpy数组,能进一步加速searchsorted的执行速度。
  • 如果需要频繁查询,可将index_cache和target_times保存到本地(比如用pickle),下次直接加载使用,无需重新计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 14:00:32