使用Pandas BusinessHour重采样DataFrame时遇ValueError的原因与解决
问题分析与解决方案
异常原因
这个ValueError: Values falls after last bin的问题,本质是**BusinessHour(或频率代码BH)的工作机制和你的数据时间范围不匹配**:
- 默认的
BusinessHour严格遵循周一至周五的9:00-17:00时段划分时间区间,每个区间都是完整的工作小时。 - 你从yfinance获取的5分钟级数据,大概率包含了超出这个默认工作时段的记录(比如阿姆斯特丹交易所的ABN.AS交易时段可能到17:30,或是带有盘后数据)。当这些超出时段的时间戳出现时,
resample无法找到对应的BusinessHour区间来分配它们,就会抛出“值落在最后一个区间之后”的错误。 - 而
Hour偏移是连续的时间区间,不管是否属于工作日或工作时段,所有时间戳都能找到对应的小时区间,因此不会触发错误。
可行的解决办法
1. 先过滤出工作日工作时段的数据,再按小时重采样
这是最稳妥的方案:先把数据限制在你需要的工作日时段内,再用常规的小时重采样。
import yfinance as yf import pandas as pd # 获取原始数据 mydata = yf.Ticker('ABN.AS').history(interval='5m', period='1mo', start='2020-06-01') # 过滤条件:工作日(weekday<5,0=周一,4=周五)+ 工作时段(可根据交易所实际时间调整) mask = (mydata.index.weekday < 5) & (mydata.index.hour >= 9) & (mydata.index.hour < 18) # 若需精确到分钟(比如到17:30),可补充:& ~((mydata.index.hour ==17) & (mydata.index.minute >30)) filtered_data = mydata[mask] # 按小时重采样取均值 mydatahour = filtered_data.resample('H').mean()
2. 自定义BusinessHour的时段范围
如果你的数据确实需要覆盖默认工作时段外的时间(比如早开盘或晚收盘),可以自定义BusinessHour的start和end参数,确保所有数据的时间戳都在这个范围内:
from pandas.tseries.offsets import BusinessHour # 自定义工作时段为9:00-17:30,匹配交易所实际交易时间 custom_bh = BusinessHour(start='09:00', end='17:30') # 重采样 mydatahour = mydata.resample(custom_bh).mean()
⚠️ 注意:如果数据中仍有超出这个自定义时段的记录,还是会触发同样的错误,建议结合第一步的过滤操作。
3. 结合Grouper与过滤逻辑
如果你想用groupby+Grouper的方式,同样需要先过滤数据:
# 先过滤数据 filtered_data = mydata[(mydata.index.weekday <5) & (mydata.index.hour.between(9,17))] # 按工作日小时分组取均值 mydatahour2 = filtered_data.groupby(pd.Grouper(freq='H')).mean()
补充说明
关于你提到的Hour偏移是只读无法调整的问题:其实不需要修改Hour对象,通过先过滤数据的方式,就可以实现“仅在工作日时段重采样到小时级”的需求,效果和用BusinessHour一致,且更灵活可控。
内容的提问来源于stack exchange,提问作者BramAppel
相关产品推荐
相关产品推荐

