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

如何遍历两个异构Pandas DataFrame并按条件修改其中一个?

问题:将df2的标记匹配到df1对应时间区间行

需求说明

现有两个DataFrame:

  • df1的start_times列存储升序排列的事件开始时间,flag和flag_times列初始全为NaN
  • df2包含flag(左l/右r标记)和对应的flag_times时间点

需要将每个df2的flag_times匹配到df1的对应行,满足条件:
df1.loc[row, 'start_times'] ≤ df2.loc[key_count, 'flag_times'] < df1.loc[row+1, 'start_times']
匹配成功后,将df2的flag和flag_times填入df1对应行,其余行保留NaN。

df1初始示例

start_timesflagflag_times
235NaNNaN
457NaNNaN
950NaNNaN
1902NaNNaN

df2示例

flagflag_times
l390
r1000

期望结果df1

start_timesflagflag_times
235l390
457NaNNaN
950r1000
1902NaNNaN

原代码问题

用户编写的循环代码存在以下问题:

  1. 条件判断错误:原代码用<= df1.at[row+1, 'start_times'],不符合需求中小于下一行start_times的要求
  2. 循环逻辑漏洞:若df2的flag_times不在任何df1区间内,或两者顺序不匹配,会导致循环陷入死循环或匹配失败
  3. 效率低下:at逐行操作在大数据量下性能极差,无法处理大规模数据集

解决方案

方法1:用pandascut函数(高效处理大数据)

利用df1start_times的有序性,通过pd.cut快速给df2的时间分配对应区间,再批量合并数据:

import pandas as pd
import numpy as np
import random

# 修正测试数据生成代码的错误
times = random.sample(range(1, 10000), 10)
times.sort()
flag_times = random.sample(range(times[0], times[-1]), 2)
flag_times.sort()
flags = ['l', 'r']  # 生成对应长度的标记列表

df1 = pd.DataFrame({
    'start_times': times,
    'flag': np.nan,
    'flag_times': np.nan
})

df2 = pd.DataFrame({
    'flag': flags,
    'flag_times': flag_times
})

# 生成区间边界:df1的start_times + 无穷大作为最后区间上限
bins = df1['start_times'].tolist() + [np.inf]
# 给df2的每个flag_times分配对应的df1行索引
df2['row_idx'] = pd.cut(df2['flag_times'], bins=bins, labels=df1.index[:-1], include_lowest=True)

# 批量将df2数据映射到df1
df1.loc[df2['row_idx'], ['flag', 'flag_times']] = df2[['flag', 'flag_times']].values

print(df1)

方法2:双指针优化(适合理解逻辑,大数据量也高效)

基于两个序列的有序性,用双指针只遍历一次,避免嵌套循环的冗余操作:

row = 0
key_count = 0
len_df1 = len(df1)
len_df2 = len(df2)

while row < len_df1 - 1 and key_count < len_df2:
    current_start = df1.iloc[row]['start_times']
    next_start = df1.iloc[row+1]['start_times']
    flag_time = df2.iloc[key_count]['flag_times']
    
    if current_start <= flag_time < next_start:
        # 匹配成功,批量填充数据
        df1.loc[row, ['flag', 'flag_times']] = df2.iloc[key_count][['flag', 'flag_times']]
        key_count += 1
        row += 1
    elif flag_time < current_start:
        # 时间早于当前区间,跳过该标记
        key_count += 1
    else:
        # 时间晚于当前区间,移动到下一个区间
        row += 1

# 处理大于df1最后一个start_time的标记(可选逻辑)
while key_count < len_df2:
    if df2.iloc[key_count]['flag_times'] >= df1.iloc[-1]['start_times']:
        df1.loc[len_df1-1, ['flag', 'flag_times']] = df2.iloc[key_count][['flag', 'flag_times']]
    key_count += 1

print(df1)

关键优化点

  • 双指针遍历时间复杂度为O(n+m),远优于嵌套循环
  • 使用loc/iloc批量赋值,避免逐行at操作的性能损耗
  • pd.cut是pandas向量化操作,处理大规模数据时性能最优

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 19:43:22