根据目标列中“非递减序列”的自然断点(即当前值小于前一值时),将 dataframe 划分为多个连续子组,每个子组内元素满足 a[i] ≥ a[i−1],适用于识别单调上升趋势的起止区间。
根据目标列中“非递减序列”的自然断点(即当前值小于前一值时),将 dataframe 划分为多个连续子组,每个子组内元素满足 a[i] ≥ a[i−1],适用于识别单调上升趋势的起止区间。
在数据分析中,常需按数值趋势对数据进行逻辑切片——例如识别价格持续上涨的时段、用户行为连续增强的周期等。本例的核心需求是:每当列值出现下降(即破坏非递减性),就开启一个新组;否则延续当前组。这本质上是检测“升序 streak”的边界。
关键在于构造一个能反映分组变化的辅助标识列。df['a'].diff() 计算相邻行差值(默认向前差分,即 a[i] - a[i-1]),结果为正/零表示上升或持平,为负则表示下降。我们用 .lt(0) 将其转为布尔 Series:True 表示“此处发生下降,应作为新组起点”。再通过 .cumsum() 对 True 累计求和,即可生成唯一且递增的组编号(每遇到一次下降,累加器 +1):
import pandas as pd
df = pd.DataFrame({'a': [10, 14, 20, 10, 12, 5, 3]})
group_ids = df['a'].diff().lt(0).cumsum()
print("Group IDs:", group_ids.tolist()) # [0, 0, 0, 1, 1, 2, 3]该 group_ids 序列天然满足分组要求:索引 0–2 同属第 0 组(10→14→20 未下降),索引 3 处 10 < 20 触发 True,ID 变为 1,后续同理。
最终,使用 df.groupby(group_ids) 即可完成切分:
dfs = [d for _, d in df.groupby(group_ids)]
for i, sub_df in enumerate(dfs):
print(f"\nGroup {i}:\n{sub_df}")输出:
Group 0:
a
0 10
1 14
2 20
Group 1:
a
3 10
4 12
Group 2:
a
5 5
Group 3:
a
6 3⚠️ 注意事项:
- 此方法默认首行属于第 0 组(因 diff() 首行为 NaN,.lt(0) 返回 False,不影响累加);
- 若需严格“严格升序”(排除相等情况),将 .lt(0) 改为 .le(0) 并配合额外逻辑处理相等情形;
- 对于大型 DataFrame,该方案时间复杂度为 O(n),高效且无需循环,符合 pandas 向量化最佳实践。

















