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

优化Pandas滑动窗口均值计算:替代双层for循环的高效方案

高效优化滑动窗口均值计算方案

你的双层循环逻辑是正确的,但效率低下的核心问题在于每次切片后都重新计算窗口内的均值,这会导致大量重复计算(比如大窗口会包含小窗口的所有元素,却要重新求和)。下面给你两个更高效的实现方案,既能得到正确结果,又能大幅提升运行速度:

方案一:前缀和数组(性能最优)

前缀和是处理区间求和/均值问题的经典技巧,它能把任意区间的均值计算复杂度降到O(1),整体效率比原始循环提升几个数量级。

实现步骤:

  1. 计算col2列的前缀和数组,这样任意区间[j, j+k-1]的和可以通过prefix[j+k] - prefix[j]快速得到
  2. 遍历所有符合要求的窗口大小(从min_window到数据框总长度)
  3. 对每个窗口大小,遍历所有合法起始位置,用前缀和计算均值,同时记录窗口的起始/结束ind值

代码示例:

import numpy as np
import pandas as pd

# 你的原始DataFrame
df = pd.DataFrame({
    'col1': ['A','B','C','D','E','F','G','H','I','J','K','L'],
    'col2': [1,2,10,5,11,4,7,20,33,24,22,5],
    'ind': list(range(12))
})

min_window = len(df) // 4  # 这里计算得3
total_rows = len(df)

# 生成前缀和数组:prefix[0]=0,prefix[i]是col2前i个元素的和
prefix = np.zeros(total_rows + 1)
prefix[1:] = df['col2'].cumsum()

# 初始化结果存储列表
start_indices = []
stop_indices = []
averages = []

# 遍历所有合法窗口大小
for window_size in range(min_window, total_rows + 1):
    # 每个窗口大小对应的起始位置范围
    for start_pos in range(total_rows - window_size + 1):
        # 计算窗口均值:(区间和)/窗口大小
        window_sum = prefix[start_pos + window_size] - prefix[start_pos]
        avg = window_sum / window_size
        # 记录窗口的起始/结束ind值
        start_indices.append(df['ind'].iloc[start_pos])
        stop_indices.append(df['ind'].iloc[start_pos + window_size - 1])
        averages.append(avg)

# 找出均值最大的所有窗口
max_avg = max(averages)
max_windows = [
    (s, e, round(avg, 2)) 
    for s, e, avg in zip(start_indices, stop_indices, averages) 
    if avg == max_avg
]

print("均值最大的窗口组合:")
for win in max_windows:
    print(f"起始ind: {win[0]}, 结束ind: {win[1]}, 均值: {win[2]}")

方案二:Pandas Rolling 方法(代码更简洁)

如果你更看重代码的可读性和简洁性,可以用Pandas内置的rolling函数。它内部已经做了滑动窗口的优化计算,避免了重复求和,效率也远高于原始的双层循环。

代码示例:

import pandas as pd

# 原始DataFrame同上
df = pd.DataFrame({
    'col1': ['A','B','C','D','E','F','G','H','I','J','K','L'],
    'col2': [1,2,10,5,11,4,7,20,33,24,22,5],
    'ind': list(range(12))
})

min_window = len(df) // 4
total_rows = len(df)

start_indices = []
stop_indices = []
averages = []

# 遍历所有合法窗口大小
for window_size in range(min_window, total_rows + 1):
    # 计算滚动均值,min_periods=window_size确保只保留完整窗口的结果
    rolling_avg_series = df['col2'].rolling(window=window_size, min_periods=window_size).mean()
    # 遍历每个有效窗口的结束位置
    for end_pos in range(window_size - 1, total_rows):
        avg = rolling_avg_series.iloc[end_pos]
        # 计算窗口的起始位置
        start_pos = end_pos - window_size + 1
        # 记录ind值
        start_indices.append(df['ind'].iloc[start_pos])
        stop_indices.append(df['ind'].iloc[end_pos])
        averages.append(avg)

# 找出均值最大的窗口
max_avg = max(averages)
max_windows = [
    (s, e, round(avg, 2)) 
    for s, e, avg in zip(start_indices, stop_indices, averages) 
    if avg == max_avg
]

print("均值最大的窗口组合:")
for win in max_windows:
    print(f"起始ind: {win[0]}, 结束ind: {win[1]}, 均值: {win[2]}")

性能对比说明

  • 原始双层循环的时间复杂度是O(n² * k)(k为窗口大小),数据量越大,窗口越大,效率越低。
  • 前缀和方法的时间复杂度是O(n²),每个窗口的均值计算都是O(1),是性能最优的选择。
  • Rolling方法的时间复杂度接近O(n²),但内部有Pandas的优化,代码更简洁易维护,适合大多数场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:03:53