
本文介绍如何使用 pandas 高效完成按日期区间匹配电价的查询任务,适用于能源账单、分时计价等场景,兼顾代码简洁性与运行效率。
本文介绍如何使用 pandas 高效完成按日期区间匹配电价的查询任务,适用于能源账单、分时计价等场景,兼顾代码简洁性与运行效率。
在处理能源消费数据时,电价往往随时间分段变化(如季度调价),需将每日用电量乘以对应时段的单价。核心挑战在于:给定一个日期,快速定位其所属的价格区间。虽然可遍历所有区间做 date >= start and date
推荐方案:使用 pandas 的向量化布尔索引 + 日期解析
pandas 天然支持高效的时间范围筛选,只需三步即可完成端到端映射:
- 加载并解析价格表:用 pd.read_fwf() 或 pd.read_csv() 读取结构化价格数据,通过 parse_dates 自动转换为 datetime64 类型;
- 构建向量化查询逻辑:利用布尔索引一次性判断所有日期是否落在某区间内;
- 关联消费数据:对每日消费 DataFrame 添加 price 列,通过 apply 或 merge_asof(更优)实现高效匹配。
以下为完整示例(含生产级优化建议):
import pandas as pd
from datetime import datetime
# 步骤1:加载价格表(跳过表头分隔行)
df_prices = pd.read_fwf(
'prices.txt',
widths=[15, 15, 10],
names=['start_date', 'end_date', 'unit_cost'],
skiprows=2,
parse_dates=['start_date', 'end_date']
)
# 步骤2:构建消费数据(示例:2023年1月-12月每日用量)
dates = pd.date_range('2023-01-01', '2023-12-31', freq='D')
df_consumption = pd.DataFrame({'date': dates, 'kwh': [12.5, 13.2, 11.8, ...]}) # 实际中替换为真实数据
# ✅ 推荐方式:使用 merge_asof(要求区间左闭右开且已排序)
# 先将价格表转为“起始日→单价”映射(因区间连续,仅需 start_date 即可)
df_prices_sorted = df_prices.sort_values('start_date').drop('end_date', axis=1)
df_consumption_sorted = df_consumption.sort_values('date')
# 关键:merge_asof 实现 O(n+m) 时间复杂度的区间查找(比布尔索引快一个数量级)
df_result = pd.merge_asof(
df_consumption_sorted,
df_prices_sorted,
left_on='date',
right_on='start_date',
allow_exact_matches=True, # 匹配 start_date 当日
direction='backward' # 找最后一个 ≤ date 的 start_date
)
# 此时 df_result 包含 date, kwh, start_date, unit_cost —— 可直接计算费用
df_result['cost'] = df_result['kwh'] * df_result['unit_cost']
⚠️ 注意事项:
- merge_asof 要求左右表均按连接键升序排列,且价格表 start_date 必须覆盖所有消费日期(或提前填充边界);
- 若价格区间非严格连续(存在空隙或重叠),应先校验:df_prices['start_date'].shift(-1) == df_prices['end_date'] + pd.Timedelta(days=1);
- 对于小规模数据(
- 如需支持任意时间点(含未来日期),建议将 end_date 也纳入 merge_asof 的辅助判断,或改用 pandas.IntervalIndex 构建区间索引。
总结:面对日期区间匹配问题,优先考虑 pandas.merge_asof —— 它专为“查找最近左侧锚点”而设计,语义清晰、性能卓越,是处理电价、费率、税率等分段规则的首选工具。











