如何在Pandas中实现类似MATLAB的两端可伸缩窗口移动平均?
问题解答
方法名称
你说的这种两端逐步调整窗口大小的滑动平均,叫做自适应窗口大小的中心移动平均(MATLAB中smooth(signal, 9, 'moving')的核心逻辑就是中心移动平均,在首尾数据不足时自动缩小窗口,避免NaN和滞后)。
Pandas/NumPy/SciPy中的实现
Pandas没有直接内置这个功能,但可以通过自定义函数快速实现,逻辑和MATLAB完全一致:
import pandas as pd import numpy as np def matlab_style_smooth(s, window_size): n = len(s) result = np.zeros(n) half_win = (window_size - 1) // 2 # 窗口大小为9时,half_win=4 for i in range(n): # 计算当前位置的实际窗口大小:开头逐步增大,末尾逐步缩小,中间保持设定的window_size current_win_size = min(2*i + 1, window_size, 2*(n - 1 - i) + 1) # 确定窗口的起止索引 start_idx = i - (current_win_size - 1) // 2 end_idx = start_idx + current_win_size # 计算窗口内的均值 result[i] = s.iloc[start_idx:end_idx].mean() return pd.Series(result, index=s.index) # 使用示例:假设你的数据列是df['signal'] df['smoothed_signal'] = matlab_style_smooth(df['signal'], 9)
如果数据量很大,循环效率不够,可以用卷积逻辑优化:
def fast_smooth(s, window_size): n = len(s) half = (window_size - 1) // 2 # 生成每个位置的窗口大小数组 win_sizes = np.array([min(2*i+1, window_size, 2*(n-1-i)+1) for i in range(n)]) # 对原始数据补边,方便生成滑动窗口 padded = np.pad(s.values, (half, half), mode='constant', constant_values=np.nan) windowed = np.lib.stride_tricks.sliding_window_view(padded, window_size) means = [] for i in range(n): win = windowed[i] # 根据位置截取窗口内的有效数据 if i < half: valid = win[:win_sizes[i]] elif i > n - 1 - half: valid = win[-win_sizes[i]:] else: valid = win means.append(np.nanmean(valid)) return pd.Series(means, index=s.index)
SciPy中没有直接对应这个逻辑的函数,scipy.signal.savgol_filter虽能实现平滑,但它是基于多项式拟合的滤波,和你需要的简单移动平均逻辑不一致。
内容的提问来源于stack exchange,提问作者Otispunkmeyer86
相关产品推荐
相关产品推荐

