如何在Pandas中获取含上下单元格的滚动窗口最小值?
在Pandas中识别连续三单元格的局部最小值(含当前、上、下单元格)
我需要在Pandas中实现逻辑:对每一行的Close值,判断它是否是当前行、上一行、下一行这三个连续单元格中的最小值。尝试过scipy的arglextrema,但它无法实现这种滚动窗口的计算逻辑。
尝试过以下自定义函数,但效果不符合预期:
def pivot_swing_low(df): data = df.copy() data['d1'] = data.Close.shift(-1) data['d3'] = data.Close.shift(0) data['d4'] = data.Close.shift(1) data['minPL'] = data[['d1', 'd3', 'd4']].min(axis=1) data['PL'] = np.where(data['minPL'] == data['d3'], data['d3'], "NaN") data['recentPL'] = data.PL.shift(2).astype(float).fillna(method='ffill') data = data.drop(columns=['d1', 'd3', 'd4']) return data
这个函数仅能捕获到第33行的最小值,但实际上第31行也应该被识别为局部最小值。
相关数据示例(仅展示关键行):
38.78 1671068699999 2022-12-15 01:44:59.999 NaN NaN -0.37 0.00 0.37 0.023571 0.054286 0.023125 0.057698 0.400805 28.612474 NaN NaN 38.78 38.78 39.15 30 38.79 1671068999999 2022-12-15 01:49:59.999 NaN NaN 0.01 0.01 0.00 0.022857 0.054286 0.022188 0.053576 0.414137 29.285496 NaN NaN 38.48 NaN 39.15 31 38.48 1671069299999 2022-12-15 01:54:59.999 NaN NaN -0.31 0.00 0.31 0.021429 0.076429 0.020603 0.071892 0.286583 22.274722 22.274722 NaN 38.48 38.48 38.78 32 38.67 1671069599999 2022-12-15 01:59:59.999 NaN NaN 0.19 0.19 0.00 0.035000 0.074286 0.032703 0.066757 0.489878 32.880419 NaN NaN 38.37 NaN 38.78 33 38.37 1671069899999 2022-12-15 02:04:59.999 38.37000000 NaN -0.30 0.00 0.30 0.035000 0.093571 0.030367 0.083417 0.364036 26.688174 NaN NaN 38.37 38.37 38.48 34 38.58 1671070199999 2022-12-15 02:09:59.999 NaN NaN 0.21 0.21 0.00 0.050000 0.090000 0.043198 0.077459 0.557687 35.802263 NaN NaN 38.37 NaN 38.48 35 38.70 1671070499999 2022-12-15 02:14:59.999 NaN NaN 0.12 0.12 0.00 0.058571 0.090000 0.048684 0.071926 0.676857 40.364625 NaN 40.364625 38.58 NaN 38.37
问题原因分析
原函数的核心逻辑没问题,但存在一个关键错误:将非最小值的情况赋值为字符串"NaN",而非NumPy的np.nan。后续执行astype(float)时,字符串"NaN"会被转为np.nan,但同时可能导致原本有效的值被错误转换,最终造成第31行的最小值未被正确保留。
修正后的解决方案
使用Pandas的滚动窗口rolling方法,更简洁且准确地实现需求:
import pandas as pd import numpy as np def pivot_swing_low(df): data = df.copy() # 以当前行为中心,取上、中、下三行的最小值 data['window_min'] = data['Close'].rolling(window=3, center=True).min() # 判断当前Close是否为窗口最小值,是则保留值,否则为np.nan data['PL'] = np.where(data['Close'] == data['window_min'], data['Close'], np.nan) # 处理recentPL字段,保持原逻辑 data['recentPL'] = data['PL'].shift(2).fillna(method='ffill') # 可选择删除中间字段window_min # data = data.drop(columns=['window_min']) return data
说明
rolling(window=3, center=True):指定窗口大小为3,且以当前行为中心,正好覆盖上一行、当前行、下一行三个连续单元格。- 替换字符串
"NaN"为np.nan,保证数据类型统一,避免转换错误。 - 修正后,第31行的
Close=38.48会被正确识别为窗口最小值(对应窗口值:38.79、38.48、38.67),第33行的38.37也会被正常捕获。
内容的提问来源于stack exchange,提问作者tryc0d3
相关产品推荐
相关产品推荐

