
本文介绍一种基于业务逻辑(跳过周末)的分组方法,用于在多产品价格时间序列中精准识别价格连续不变的自然交易日区间,并输出起止日期、价格及持续天数。
本文介绍一种基于业务逻辑(跳过周末)的分组方法,用于在多产品价格时间序列中精准识别价格连续不变的自然交易日区间,并输出起止日期、价格及持续天数。
在金融与零售分析中,识别价格“冻结期”(即价格在连续交易日中未发生变动)具有重要业务意义——例如监测调价滞后、合同锁价周期或异常静默行为。但标准时间序列分组(如 shift().cumsum())无法直接满足三大现实约束:
- 工作日连续性:需将周五与下周一视为“逻辑相邻”,跳过周六、周日;
- 产品隔离性:不同 ID 的相同价格必须独立判断,不可跨产品合并;
- 严格连续性:仅当价格在逻辑连续交易日上保持一致时才计为一段,中间任意一天变化即中断。
以下提供一个稳健、可读性强的解决方案,核心思想是手动模拟交易日推进逻辑 + 迭代式状态维护,避免依赖 Pandas 复杂窗口操作导致的边界错误。
✅ 步骤详解
首先确保日期列已转为 datetime64[ns] 类型,并定义辅助函数 get_next_day(),按中国/欧美主流市场惯例处理周末跳跃(周五 → 下周一,周六 → 周一,周日 → 周一):
import pandas as pd
def get_next_day(d):
d += pd.Timedelta("1 day")
if d.dayofweek == 4: # Friday (0=Monday → 4=Friday)
d += pd.Timedelta("2 days") # → Sunday, then +1 → Monday
elif d.dayofweek == 5: # Saturday
d += pd.Timedelta("1 day") # → Sunday, then +1 → Monday
return d接着,使用生成器函数 generate_groups() 实现逐行状态追踪:
- 维护 current_group 存储当前连续段的 (ID, Date, Price) 元组;
- 使用 expected_next_day 动态预测下一条记录应出现的日期(非简单 +1d);
- 当任一条件不满足(ID 变化 / 价格变化 / 日期不匹配预期),则提交当前组并重置。
完整实现如下:
def yield_group(g):
if len(g) > 1:
yield {
"ID": g[0][0],
"start_date": g[0][1],
"end_date": g[-1][1],
"price": g[0][2],
"repeated_days_count": len(g),
}
def generate_groups(ids, dates, prices):
current_group = []
prev_id = None
prev_price = None
expected_next_day = None
for i, d, p in zip(ids, dates, prices):
if prev_id is None:
current_group.append((i, d, p))
elif expected_next_day != d or prev_id != i or prev_price != p:
yield from yield_group(current_group)
current_group = [(i, d, p)]
else:
current_group.append((i, d, p))
prev_id = i
prev_price = p
expected_next_day = get_next_day(d)
yield from yield_group(current_group) # 提交最后一组
# 应用示例
df["Date"] = pd.to_datetime(df["Date"])
result = pd.DataFrame(generate_groups(df["ID"], df["Date"], df["Price"]))
print(result)⚠️ 注意事项与最佳实践
- 日期格式兼容性:输入 Date 列必须为 datetime 类型;若原始数据含逗号小数(如 "1,00"),建议预处理为浮点数(df["Price"] = df["Price"].str.replace(",", ".").astype(float)),避免字符串比对歧义;
-
排序前提:该算法严格要求数据按 ID 分组内、Date 升序排列。务必在调用前执行:
df = df.sort_values(["ID", "Date"]).reset_index(drop=True)
- 扩展性提示:若需支持节假日(如春节、国庆调休),可将 get_next_day() 升级为查表函数,接入自定义节假日日历;
- 性能考量:对超百万级数据,此迭代方案仍保持 O(n) 时间复杂度,优于多次 groupby().apply() 嵌套,且内存可控。
该方法绕过了 Pandas 高阶分组函数在“非均匀时间间隔”场景下的固有局限,以清晰的状态机逻辑确保业务规则零妥协,是处理真实世界交易日序列的可靠范式。

















