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

基于复杂条件为Pandas DataFrame添加列的高效实现问询

高效匹配df1与df2的F值方案

原始数据

df1的部分数据:

In [500]: df1.iloc[67:100]
Out[500]:
          Expiry      K Type      close
107  2018-01-26  123.00    C  0.406250
108  2018-01-26  124.00    C  0.062500
109  2018-01-26  125.00    C  0.015625
112  2018-01-26  121.50    C  1.640625
121  2018-02-23  123.50    C  0.406250
124  2018-02-23  127.50    C  0.015625
127  2018-02-23  124.50    C  0.140625
130  2018-02-23  125.50    C  0.046875
144  2018-05-25  120.00    C  3.156250
145  2018-05-25  121.00    C  2.203125
146  2018-05-25  122.00    C  1.328125
147  2018-02-23  123.00    C  0.640625
148  2018-02-23  124.00    C  0.234375
152  2018-06-22  121.50    C  1.750000
156  2018-06-22  126.50    C  0.015625
158  2018-02-23  122.50    C  0.953125
160  2018-03-23  123.25    P  0.484375
161  2018-03-23  123.50    P  0.625000
162  2018-03-23  123.75    P  0.796875
163  2018-03-23  127.25    P  4.125000
164  2018-03-23  127.50    P  4.375000

df2数据:

In [501]: df2
Out[501]:
                            F Symbol    Expiry
2018-03-20 12:00:00  123.125000    ZN  MAR 18
2018-06-20 12:00:00  122.734375    ZN  JUN 18
2018-09-19 12:00:00  122.265625    ZN  SEP 18

首先,你的需求是为df1每一行,根据Expiry在(Expiry+MonthEnd(1), Expiry+MonthEnd(4))区间内匹配df2的F值。当前用apply的方法虽然能实现,但当df1数据量较大时效率会极低——因为apply本质是逐行执行Python循环,每次都要对df2做切片查询,属于O(n*m)的时间复杂度。

下面给你两种更高效的向量化方案,基于Pandas/Numpy批量操作,彻底避免逐行循环:

方案一:Numpy广播匹配(推荐,适合df2行数少的场景)

你的df2只有3行数据,用广播可以一次性完成所有匹配,速度极快:

步骤1:预处理df2,将索引转为列

df2_reset = df2.reset_index().rename(columns={'index': 'df2_date'})

步骤2:计算df1每行的区间边界

from pandas.tseries.offsets import MonthEnd

df1['lower'] = df1['Expiry'] + MonthEnd(1)
df1['upper'] = df1['Expiry'] + MonthEnd(4)

步骤3:用Numpy广播实现批量匹配

import numpy as np

# 转换数组形状,实现广播匹配
lower = df1['lower'].values[:, np.newaxis]
upper = df1['upper'].values[:, np.newaxis]
df2_dates = df2_reset['df2_date'].values[np.newaxis, :]
df2_F_values = df2_reset['F'].values[np.newaxis, :]

# 生成匹配掩码:每个df1行对应符合区间条件的df2日期
match_mask = (df2_dates > lower) & (df2_dates < upper)

# 提取匹配到的F值并赋值
df1['F'] = df2_F_values[match_mask].reshape(-1)

# 清理临时列
df1.drop(['lower', 'upper'], axis=1, inplace=True)

方案二:区间分箱匹配

如果df2行数较多,可通过区间分箱的方式,先给df2的每个日期定义对应的df1 Expiry区间,再匹配F值:

步骤1:预处理df2,计算对应的Expiry区间

df2_reset = df2.reset_index().rename(columns={'index': 'df2_date'})
df2_reset['expiry_low'] = df2_reset['df2_date'] - MonthEnd(4)
df2_reset['expiry_high'] = df2_reset['df2_date'] - MonthEnd(1)

步骤2:用pd.cut给df1的Expiry分配对应的F值

# 创建区间索引(左开右开,匹配你的条件)
interval_index = pd.IntervalIndex.from_arrays(df2_reset['expiry_low'], df2_reset['expiry_high'], closed='neither')

# 匹配并转换为数值类型
df1['F'] = pd.cut(df1['Expiry'], bins=interval_index, labels=df2_reset['F']).astype(float)

效率对比

  • 你的apply方法:10万行df1需执行10万次df2查询,耗时秒级甚至更长;
  • 向量化方案:同样10万行数据,耗时仅几十毫秒,效率提升几十到上百倍。

两种方案都能得到你预期的输出结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:10:08