如何用Pythonic方式计算列表的正值滚动均值?
优雅实现带正值过滤的滚动均值计算
这是个很实用的数据分析需求,我来给你分享两种Pythonic的解决方案,完美解决你遇到的位置丢失和nan干扰问题:
核心思路
首先把原列表中的负值替换为nan(保留原位置信息),然后对每个滚动窗口计算仅非nan值的均值——也就是窗口内正值的和除以正值的数量,同时处理窗口内有效元素不足的情况(比如首末窗口)。
方法一:向量化计算(推荐,高效简洁)
利用Pandas的滚动求和与滚动计数功能,避免逐窗口循环,性能更优:
import pandas as pd import numpy as np def rolling_positive_average(data, window_size, min_valid_elements=2): # 1. 转换为Series,将负值替换为nan,保留原位置 series = pd.Series(data).where(lambda x: x > 0, np.nan) # 2. 计算滚动窗口内的正值总和、正值数量 rolling_sum = series.rolling(window=window_size).sum(skipna=True) rolling_valid_count = series.rolling(window=window_size).count() # 3. 计算均值,有效元素不足时设为nan rolling_avg = rolling_sum / rolling_valid_count rolling_avg = rolling_avg.where(rolling_valid_count >= min_valid_elements, np.nan) # 转换为列表返回,保持与输入格式一致 return rolling_avg.tolist() # 测试你的示例数据 sample_data = [1,2,3,4,5,-1,4,2,3] result = rolling_positive_average(sample_data, window_size=3) print(result) # 输出: [nan, nan, 2.0, 3.0, 4.0, 4.5, 4.5, 3.0, nan]
方法二:自定义窗口函数(灵活通用)
如果需要更复杂的窗口逻辑,可以用rolling().apply()自定义计算逻辑:
import pandas as pd import numpy as np def rolling_positive_average_apply(data, window_size, min_valid_elements=2): series = pd.Series(data).where(lambda x: x > 0, np.nan) def window_mean(window): # 统计窗口内有效元素数量 valid_count = window.notna().sum() if valid_count >= min_valid_elements: return window.mean(skipna=True) return np.nan rolling_avg = series.rolling(window=window_size).apply(window_mean, raw=False) return rolling_avg.tolist() # 测试 sample_data = [1,2,3,4,5,-1,4,2,3] result = rolling_positive_average_apply(sample_data, window_size=3) print(result) # 输出与方法一一致
解决你之前的问题
- 你之前的代码直接过滤掉负值,导致原位置信息丢失,滚动窗口的对齐完全错误;
- 替换为nan后用默认
rolling.mean()会因为窗口内存在nan直接返回nan,而我们的方法通过sum(skipna=True)和count(),或者自定义函数跳过nan,只计算有效正值的均值。
说明
min_valid_elements参数可以控制窗口内至少需要多少个正值才计算均值,你可以根据需求调整(比如设为1的话,单个正值也会返回自身);- 输出结果的长度和输入列表一致,首末的nan是因为窗口内有效元素不足导致的,符合你的示例逻辑。
内容的提问来源于stack exchange,提问作者Pietro Speroni
相关产品推荐
相关产品推荐

