You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求Pandas式无循环方法移除DataFrame中连续升降序列

解决Pandas移除连续升降序列中间点的问题

嘿,这个需求用Pandas的矢量化操作完全可以搞定,不用写循环~ 我给你两种简洁的实现方式,核心思路都是找到连续升降的区间,然后只保留每个区间的关键转折点。

方法一:分组法(简洁易读)

这是最推荐的方式,利用groupby对连续同方向的区间分组,直接提取每组的终点:

import pandas as pd
import numpy as np

# 你的原始DataFrame
df = pd.DataFrame([1,2,3,5,4,3,2,4,5,6,7,8,9])
s = df[0]  # 提取单列作为Series方便操作

# 计算相邻元素变化的符号(从第二个元素开始,第一个元素无前置值)
signs = s.diff().apply(np.sign).iloc[1:]

# 为连续相同变化方向的区间生成唯一分组ID
group_key = (signs != signs.shift()).cumsum()

# 组装结果:第一个元素 + 每个连续区间的最后一个元素
result = [s.iloc[0]]
result.extend(s.iloc[1:].groupby(group_key).last().tolist())

print(result)  # 输出: [1,5,2,9]

逻辑解释:

  • s.diff()计算相邻元素的差值,np.sign()将差值转换为符号(1=上升,-1=下降,0=不变),我们从第二个元素开始取结果,因为第一个元素的差值为NaN,无实际意义。
  • (signs != signs.shift()).cumsum()会给每一段连续相同符号的区间分配唯一ID:每当符号变化时,分组ID自动+1,这样所有连续上升/下降的元素会被分到同一组。
  • 最后我们保留第一个元素,再加上每个分组的最后一个元素(即该连续区间的终点),就得到了去掉中间点的目标结果。

方法二:掩码筛选法

通过生成变化位置的掩码,直接筛选需要保留的元素索引:

import pandas as pd
import numpy as np

df = pd.DataFrame([1,2,3,5,4,3,2,4,5,6,7,8,9])
s = df[0]

# 计算所有元素的变化符号,第一个元素补0(无前置值)
diff_sign = s.diff().apply(np.sign).fillna(0)

# 找到符号变化的位置:当前符号与前一个符号不同的位置
change_mask = diff_sign.ne(diff_sign.shift())

# 提取变化位置的索引,调整得到需要保留的元素索引
change_indices = change_mask[change_mask].index.tolist()
result_indices = [change_indices[0]] + [idx-1 for idx in change_indices[1:]] + [s.index[-1]]
# 去重避免重复保留第一个元素
result_indices = list(dict.fromkeys(result_indices))

# 获取最终结果
result = s.loc[result_indices].tolist()
print(result)  # 输出: [1,5,2,9]

逻辑解释:

  • 先为每个元素计算变化符号,第一个元素因无前置值,用fillna(0)填充。
  • diff_sign.ne(diff_sign.shift())生成布尔掩码,标记所有方向切换的位置。
  • 我们取这些切换位置的前一个索引(即上一个连续区间的终点),再加上第一个和最后一个元素,去重后就是需要保留的元素索引,最后提取对应元素即可。

两种方法都是纯矢量化操作,效率远高于循环,处理大型数据集时优势明显。分组法更简洁易读,优先推荐~

内容的提问来源于stack exchange,提问作者smallcat31

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:30:39