如何基于多条件及关联日期规则过滤pandas DataFrame
原代码错误点
- 代码里的引号是中文全角符号,
yf.download的start和end参数之间缺少逗号,会直接触发语法报错 - 普通的布尔索引
data[cond1 & cond2]只能做同一行内的条件匹配,无法实现「先找符合条件的基准日,再匹配基准日后n天范围内记录」的跨行时间关联逻辑 - yfinance接口返回的行情数据,日期默认是DataFrame的索引,不是名为
Date的普通列,直接访问data['Date']会报KeyError
正确实现方案
先修正基础的数据加载代码,确保时间格式正确:
import yfinance as yf import pandas as pd # 替换全角引号为半角,补全参数间逗号 data = yf.download('spy', start='1990-01-01', end='2000-01-01') # 强制把索引转为datetime类型,避免后续时间计算报错 data.index = pd.to_datetime(data.index)
以下以查找基准日后7天内符合条件记录为例,n可以按需修改:
方法1:逻辑最直观,适合中小数据量
先提取所有基准日,再生成基准日后n天的日期范围,最后做匹配过滤:
n = 7 # 1. 定位所有满足Open>10的基准日期 base_dates = data.index[data['Open'] > 10] # 2. 生成所有基准日后n天覆盖的日期集合 date_ranges = [pd.date_range(start=d, end=d + pd.Timedelta(days=n)) for d in base_dates] valid_window_dates = set().union(*date_ranges) # 3. 最终过滤:日期在窗口范围内,同时满足Open>10、Close<50 result = data[ data.index.isin(valid_window_dates) & (data['Open'] > 10) & (data['Close'] < 50) ]
如果不需要包含基准日当天的记录,只看基准日之后的n天,把
pd.date_range的start参数改为d + pd.Timedelta(days=1)即可。
方法2:滚动窗口实现,适合大数据量性能优化
用pandas的时间窗口滚动功能,不用预先生成全部日期集合,内存占用更低:
n = 7 # 标记每行自身是否符合Open>10、Close<50的条件 data['self_pass'] = (data['Open'] > 10) & (data['Close'] < 50) # 滚动7天时间窗口,判断当前日期往前7天内是否存在Open>10的基准日 data['in_valid_window'] = data['Open'].rolling(f'{n}d').apply(lambda x: (x > 10).any()).astype(bool) # 过滤得到结果,删除临时辅助列 result = data[data['self_pass'] & data['in_valid_window']].drop(columns=['self_pass', 'in_valid_window'])
注意事项
- 如果你的数据重置过索引,日期变成了名为
Date的普通列,把代码里的data.index替换成data['Date']即可 - 如果只需要匹配交易日,不需要考虑周末、节假日等非交易日,可以把自然日窗口替换为交易日窗口,比如后续5个交易日可以用
rolling(5)实现 - 所有时间偏移计算统一用
pd.Timedelta,不要直接给日期类型加整数,会触发类型错误
内容的提问来源于stack exchange,提问作者ang
相关产品推荐
相关产品推荐

