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

Scipy平滑含零值数据问题:保留零值并分段平滑非零段

问题:分段平滑非零数据段并保留零值

原始DataFrame数据

1960-09-01  24027064    4503904.333
1960-10-01  18020298    3377928.25
1960-11-01  12013532    2251952.167
1960-12-01  6006766     1125976.083
1961-01-01  0   0
1961-02-01  0   0
1961-03-01  0   0
1961-04-01  0   0
1961-05-01  0   0
1961-06-01  0   0
1961-07-01  0   0
1961-08-01  0   0
1961-09-01  0   0
1961-10-01  0   0
1961-11-01  0   0
1961-12-01  0   0
1969-01-01  0   0
1969-02-01  6173432.667 1150976.083
1969-03-01  12346865.33 2301952.167
1969-04-01  18520298    3452928.25

尝试的平滑代码

直接对整个DataFrame应用savgol_filter:

from scipy.signal import savgol_filter
df = df.apply(savgol_filter, window_length=df.shape[0] // 5, polyorder=2)

不符合预期的结果

原零值被拟合为非零数值,结果如下:

1960-09-01  25874679.88 4850242.328
1960-10-01  24574614.17 4606543.324
1960-11-01  23301520.97 4367900.35
1960-12-01  22055400.26 4134313.405
1961-01-01  20836252.04 3905782.489
1961-02-01  19644076.31 3682307.603
1961-03-01  18478873.09 3463888.745
1961-04-01  17340642.35 3250525.916
1961-05-01  16229384.11 3042219.117
1961-06-01  15145098.37 2838968.347
1961-07-01  14087785.12 2640773.605
1961-08-01  13057444.36 2447634.893
1961-09-01  12054076.1  2259552.21
1961-10-01  11077680.33 2076525.557
1961-11-01  10128257.06 1898554.932
1961-12-01  9205806.28  1725640.336
1969-01-01  19071395.37 5088684.927
1969-02-01  19448311.7  5412158.942
1969-03-01  19790962.91 5737508.936
1969-04-01  20099349    6080752.937

核心需求

  • 保留所有原始零值,不做任何修改
  • 仅对连续的非零数据段单独应用平滑处理,滑动窗口计算时忽略零值
  • 本质是实现分段曲线拟合平滑,非零段之间的零值区域完全隔离

解决方案

通过识别连续非零数据分组,对每个分组单独应用savgol_filter,零值部分直接保留:

步骤1:定义分段平滑函数

import pandas as pd
from scipy.signal import savgol_filter

def segment_savgol(series, window_length, polyorder):
    # 为连续非零数据分配唯一分组ID,零值会被分到独立分组
    non_zero_groups = series.ne(0).cumsum()
    
    def process_group(group):
        # 只有当分组长度大于多项式阶数时,才应用平滑(savgol要求window_length > polyorder)
        if len(group) > polyorder:
            # 窗口长度不能超过分组本身的长度
            adjusted_window = min(window_length, len(group))
            return savgol_filter(group, window_length=adjusted_window, polyorder=polyorder)
        # 长度不足的分组(包括零值分组)直接返回原数据
        return group
    
    # 按分组处理后,还原为原索引顺序
    return series.groupby(non_zero_groups).apply(process_group)

步骤2:应用到DataFrame

# 设置参数,和原代码保持一致
window_len = df.shape[0] // 5
poly_order = 2

# 对每一列应用分段平滑
df_smoothed = df.apply(segment_savgol, window_length=window_len, polyorder=poly_order)

效果说明

  • 所有原始零值会被完整保留,不会参与任何平滑计算
  • 每个连续非零数据段会被独立平滑,不会受到其他段或零值区域的影响
  • 对于长度不足的非零段(长度≤多项式阶数),直接保留原数据避免报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 11:57:32