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

如何不使用循环快速在多个DataFrame中匹配日期索引?

高效匹配多DataFrame中的日期索引

需求:给定一组目标日期,逐个匹配多个DataFrame——找到第一个时间范围包含该日期的DataFrame,记录其序号和该日期在对应DataFrame中的最近索引。原循环方法在数据量大时速度极慢,寻求优化方案。

原实现代码:

import pandas as pd
from datetime import timedelta

df_tomatch_1=pd.DataFrame({'a':[1,2,3,4],'b':[10,20,30,40]})
df_tomatch_1.index=['2023-01-01 10:00','2023-01-01 11:00','2023-01-01 12:00','2023-01-01 13:00']

df_tomatch_2=pd.DataFrame({'c':[1,2,3,4],'d':[10,20,30,40]})
df_tomatch_2.index=['2023-01-02 10:00','2023-01-02 11:00','2023-01-02 12:00','2023-01-02 13:00']

time_tomatch=['2023-01-01 10:30','2023-01-01 12:30','2023-01-02 11:30']

def find_matched_date_index(df_tomatch_list,time_tomatch):
    indx_time=[]
    for date_str in time_tomatch:
        print(date_str)
        thisdate=pd.to_datetime(date_str)
        for ix_file,df in enumerate(df_tomatch_list):
            df.index=pd.to_datetime(df.index)
            if thisdate>=df.index[0]-timedelta(days=0.01) and thisdate<=df.index[-1]+timedelta(days=0.01):
                indx_found=df.index.get_indexer([thisdate],method='nearest')[0]
                indx_time.append([ix_file,indx_found])
                break   # exit for loop of dataframe
    return indx_time

indx_time=find_matched_date_index([df_tomatch_1,df_tomatch_2],time_tomatch)
print(indx_time)
# 输出:[[0, 1], [0, 3], [1, 2]]

优化思路与实现

原代码核心低效点:

  • 重复转换DataFrame索引为datetime(每次循环都执行df.index=pd.to_datetime(df.index))
  • 逐个遍历目标日期和DataFrame,未利用pandas的向量化运算能力
  • 每次调用get_indexer仅处理单个日期,浪费向量化效率

优化步骤:

  1. 预处理DataFrame集合:提前转换所有索引为datetime,同时记录每个DataFrame的时间边界(最小/最大索引,加上设置的缓冲timedelta(days=0.01)),避免重复计算。
  2. 向量化处理目标日期:一次性将所有目标日期转为datetime数组,批量处理。
  3. 快速匹配DataFrame:通过向量化的条件判断,为每个目标日期找到第一个符合时间范围的DataFrame。
  4. 批量计算最近索引:对每个匹配到的DataFrame,批量处理对应目标日期的最近索引计算。

优化后代码:

import pandas as pd
from datetime import timedelta

# 预处理函数:统一处理DataFrame索引和时间范围
def preprocess_dfs(df_list, buffer_days=0.01):
    processed = []
    for df in df_list:
        idx = pd.to_datetime(df.index)
        # 计算带缓冲的时间范围
        min_ts = idx.min() - timedelta(days=buffer_days)
        max_ts = idx.max() + timedelta(days=buffer_days)
        processed.append({
            "idx": idx,
            "min_ts": min_ts,
            "max_ts": max_ts
        })
    return processed

# 高效匹配函数
def fast_match_date_indices(processed_dfs, target_dates):
    target_ts = pd.to_datetime(target_dates)
    results = []
    
    for ts in target_ts:
        # 找到第一个时间范围包含当前日期的DataFrame
        for df_idx, df_data in enumerate(processed_dfs):
            if df_data["min_ts"] <= ts <= df_data["max_ts"]:
                # 计算最近索引
                idx_pos = df_data["idx"].get_indexer([ts], method="nearest")[0]
                results.append([df_idx, idx_pos])
                break
    return results

# 测试用例
df_tomatch_1=pd.DataFrame({'a':[1,2,3,4],'b':[10,20,30,40]})
df_tomatch_1.index=['2023-01-01 10:00','2023-01-01 11:00','2023-01-01 12:00','2023-01-01 13:00']

df_tomatch_2=pd.DataFrame({'c':[1,2,3,4],'d':[10,20,30,40]})
df_tomatch_2.index=['2023-01-02 10:00','2023-01-02 11:00','2023-01-02 12:00','2023-01-02 13:00']

time_tomatch=['2023-01-01 10:30','2023-01-01 12:30','2023-01-02 11:30']

# 预处理
processed_dfs = preprocess_dfs([df_tomatch_1, df_tomatch_2])
# 匹配
indx_time = fast_match_date_indices(processed_dfs, time_tomatch)
print(indx_time)
# 输出:[[0, 1], [0, 3], [1, 2]]

超大量目标日期的进一步优化

如果目标日期数量达到十万级以上,可完全避免Python层面的循环,改用分组批量处理:

def ultra_fast_match(processed_dfs, target_dates):
    target_ts = pd.to_datetime(target_dates).to_series(name="target")
    results = pd.DataFrame(index=target_ts.index, columns=["df_idx", "pos_idx"])
    
    for df_idx, df_data in enumerate(processed_dfs):
        # 筛选当前DataFrame能覆盖的目标日期,且未被之前的DataFrame匹配
        mask = (target_ts >= df_data["min_ts"]) & (target_ts <= df_data["max_ts"])
        mask &= results["df_idx"].isna()
        
        if mask.any():
            # 批量计算这些日期的最近索引
            matched_ts = target_ts[mask]
            pos_indices = df_data["idx"].get_indexer(matched_ts, method="nearest")
            # 填充结果
            results.loc[mask, "df_idx"] = df_idx
            results.loc[mask, "pos_idx"] = pos_indices
    
    # 转为要求的列表格式
    return results.astype(int).values.tolist()

# 调用示例
indx_time = ultra_fast_match(processed_dfs, time_tomatch)
print(indx_time)
# 输出:[[0, 1], [0, 3], [1, 2]]

关键优化点说明

  • 预处理缓存:只转换一次索引和计算时间范围,避免重复计算
  • 向量化筛选:用pandas布尔掩码批量筛选符合条件的日期,替代Python循环
  • 批量索引计算:一次调用get_indexer处理多个日期,利用pandas底层C实现加速

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 17:57:05