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

Pandas优化:两个DataFrame近时间戳记录匹配与数据复制

时间戳近似匹配的高效实现方案

问题背景

有两个结构相似的DataFrame,均包含datetime格式的Timestamp列(已按时间排序),需匹配时间戳相差10秒以内的记录,并在两表间复制指定字段数据。当前暴力匹配法处理2-3k条数据时,搜索阶段耗时50-60秒,急需高效替代方案。

原暴力匹配代码

import pandas as pd
from datetime import timedelta

c = ['Timestamp','Val1', 'Val2', 'Val3', 'Val4', 'Val5']
d1 = [['2000-11-08 23:30:40', 20, '', 11, '', ''],  # 应匹配
      ['2000-11-08 23:30:42', 25, '', 22, '', ''],
      ['2000-11-08 23:31:40', 5, '', 5, '', ''],
      ['2000-11-08 23:32:35', 6, '', 3, '', ''],
      ['2000-11-08 23:34:22', 15, '', 2, '', ''],
      ['2000-11-08 23:35:30', 40, '', 22, '', ''],  # 应匹配
      ['2000-11-08 23:37:40', 32, '', 6, '', ''],
      ['2000-11-08 23:38:40', 1, '', 9, '', ''],
      ['2000-11-08 23:39:40', 0, '', 12, '', ''],  # 应匹配
      ['2000-11-08 23:43:40', 11, '', 3, '', ''],
      ['2000-11-08 23:48:40', 61, '', 2, '', ''],  # 应匹配
      ['2000-11-08 23:49:40', 55, '', 0, '', ''],  # 应匹配
      ['2000-11-08 23:52:40', 15, '', 8, '', ''],
      ['2000-11-08 23:55:40', 7, '', 17, '', '']]

d2 = [['2000-11-08 23:30:42', '', 'a', '', '', ''],  # 应匹配
      ['2000-11-08 23:30:55', '', 'b', '', '', ''],
      ['2000-11-08 23:35:25', '', 'a', '', '', ''],  # 应匹配
      ['2000-11-08 23:38:20', '', 'd', '', '', ''],
      ['2000-11-08 23:39:41', '', 'e', '', '', ''],  # 应匹配
      ['2000-11-08 23:43:19', '', 'f', '', '', ''],
      ['2000-11-08 23:48:44', '', 'g', '', '', ''],  # 应匹配
      ['2000-11-08 23:49:40', '', 'g', '', '', ''],  # 应匹配
      ['2000-11-08 23:55:29', '', 'e', '', '', '']]
df1 = pd.DataFrame(d1, columns=c)
df2 = pd.DataFrame(d2, columns=c)

# 转换时间戳格式
df1['Timestamp'] = pd.to_datetime(df1['Timestamp'])
df2['Timestamp'] = pd.to_datetime(df2['Timestamp'])

# 按时间戳排序(原数据已排序,此处为冗余操作)
df1 = df1.sort_values('Timestamp')
df2 = df2.sort_values('Timestamp')

# 设置时间差阈值
numSecondsBetweenValues = timedelta(seconds=10)

index1 = []
index2 = []

startIndex2 = 0
currIndex2 = 0

for currIndex1 in range(len(df1)):
    currIndex2 = startIndex2
    while currIndex2 < len(df2):
        if abs(df1['Timestamp'][currIndex1] - df2['Timestamp'][currIndex2]) < numSecondsBetweenValues:
            print('found 1')
            startIndex2 = currIndex2 + 1
            index1.append(currIndex1)
            index2.append(currIndex2)
            break
        currIndex2 += 1

# 复制匹配字段
for i, ii in zip(index1, index2):
    df1['Val2'].iloc[i] = df2['Val2'].iloc[ii]
    df2['Val1'].iloc[ii] = df1['Val1'].iloc[i]
    df2['Val3'].iloc[ii] = df1['Val3'].iloc[i]

高效实现方案:使用merge_asof

Pandas的merge_asof专为排序后的时间序列近似匹配设计,基于二分查找实现,时间复杂度为O(n log n),远优于暴力法的O(n*m),处理万级数据也能在毫秒级完成。

实现步骤

  1. 确保两DataFrame的Timestamp列已转换为datetime类型且按时间排序(merge_asof强制要求)
  2. 调用merge_asof,设置匹配的时间差阈值tolerance
  3. 根据匹配结果,将需要的字段映射回原DataFrame

代码示例

import pandas as pd
from datetime import timedelta

c = ['Timestamp','Val1', 'Val2', 'Val3', 'Val4', 'Val5']
d1 = [['2000-11-08 23:30:40', 20, '', 11, '', ''],
      ['2000-11-08 23:30:42', 25, '', 22, '', ''],
      ['2000-11-08 23:31:40', 5, '', 5, '', ''],
      ['2000-11-08 23:32:35', 6, '', 3, '', ''],
      ['2000-11-08 23:34:22', 15, '', 2, '', ''],
      ['2000-11-08 23:35:30', 40, '', 22, '', ''],
      ['2000-11-08 23:37:40', 32, '', 6, '', ''],
      ['2000-11-08 23:38:40', 1, '', 9, '', ''],
      ['2000-11-08 23:39:40', 0, '', 12, '', ''],
      ['2000-11-08 23:43:40', 11, '', 3, '', ''],
      ['2000-11-08 23:48:40', 61, '', 2, '', ''],
      ['2000-11-08 23:49:40', 55, '', 0, '', ''],
      ['2000-11-08 23:52:40', 15, '', 8, '', ''],
      ['2000-11-08 23:55:40', 7, '', 17, '', '']]

d2 = [['2000-11-08 23:30:42', '', 'a', '', '', ''],
      ['2000-11-08 23:30:55', '', 'b', '', '', ''],
      ['2000-11-08 23:35:25', '', 'a', '', '', ''],
      ['2000-11-08 23:38:20', '', 'd', '', '', ''],
      ['2000-11-08 23:39:41', '', 'e', '', '', ''],
      ['2000-11-08 23:43:19', '', 'f', '', '', ''],
      ['2000-11-08 23:48:44', '', 'g', '', '', ''],
      ['2000-11-08 23:49:40', '', 'g', '', '', ''],
      ['2000-11-08 23:55:29', '', 'e', '', '', '']]

df1 = pd.DataFrame(d1, columns=c)
df2 = pd.DataFrame(d2, columns=c)

# 转换时间戳格式并排序(merge_asof要求必须排序)
df1['Timestamp'] = pd.to_datetime(df1['Timestamp'])
df2['Timestamp'] = pd.to_datetime(df2['Timestamp'])
df1 = df1.sort_values('Timestamp').reset_index(drop=True)
df2 = df2.sort_values('Timestamp').reset_index(drop=True)

# 设置时间差阈值
tolerance = timedelta(seconds=10)

# 执行近似匹配:以df2为左表,匹配df1中最近的、时间差在阈值内的记录
# direction='nearest'表示找最近的时间戳,也可根据需求选'backward'或'forward'
merged = pd.merge_asof(
    df2, df1,
    on='Timestamp',
    tolerance=tolerance,
    direction='nearest',
    suffixes=('_df2', '_df1')
)

# 将匹配到的df1字段复制到df2
df2.loc[merged['Val1_df1'].notna(), 'Val1'] = merged['Val1_df1']
df2.loc[merged['Val3_df1'].notna(), 'Val3'] = merged['Val3_df1']

# 将匹配到的df2字段复制到df1
# 先构建df1到merged的映射
merged_df1 = merged.dropna(subset=['Val2_df2']).set_index('Timestamp')['Val2_df2']
df1['Val2'] = df1['Timestamp'].map(merged_df1).fillna(df1['Val2'])

处理后df2示例输出

Timestamp Val1 Val2 Val3 Val4 Val5
0 2000-11-08 23:30:42   20    a   11          
1 2000-11-08 23:30:55         b               
2 2000-11-08 23:35:25   40    a   22          
3 2000-11-08 23:38:20         d               
4 2000-11-08 23:39:41    0    e   12          
5 2000-11-08 23:43:19         f               
6 2000-11-08 23:48:44   61    g    2          
7 2000-11-08 23:49:40   55    g    0          
8 2000-11-08 23:55:29         e     

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 14:10:32