【问题标题】:Smoothing out curve in Python在 Python 中平滑曲线
【发布时间】:2018-03-19 21:38:02
【问题描述】:

我有两个数据点列表:

list_x = [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
list_y = [1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

当我绘制它们时,图表将如下所示:

import matplotlib.pyplot as plt
plt.plot(list_x, list_y)
plt.show()

根据这些数据点,有没有办法让图形看起来像下图并得到它的图形方程?

================================================ =============

我尝试使用here 的解决方案,但它生成的图形不平滑。

from scipy.interpolate import spline
import numpy as np

list_x_new = np.linspace(min(list_x), max(list_x), 1000)
list_y_smooth = spline(list_x, list_y, list_x_new)

plt.plot(list_x_new, list_y_smooth)
plt.show() 

【问题讨论】:

    标签: python plot smoothing


    【解决方案1】:

    这里还有 3 个曲线平滑选项:

    1. Savitzky-Golay 过滤器
    2. LOWESS 更平滑
    3. IIR 滤波器

    但首先,重新创建原始情节:

    import matplotlib.pyplot as plt
    
    list_x = [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
    list_y = [1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    
    plt.plot(list_x, list_y)
    plt.show()
    


    1. 来自 scipy 的 Savitzky-Golay 过滤器

    Savitzky-Golay 技术使用最小二乘法将相邻点的子集(窗口)拟合到低阶多项式。

    如何应用 Savitzky-Golay 过滤器:

    from scipy.signal import savgol_filter
    
    window = 21
    order = 2
    y_sf = savgol_filter(list_y, window, order)
    plt.plot(list_x, y_sf)
    plt.show()
    

    windoworder 参数表示此过滤器的适应性很强。

    scipy documentation 中阅读有关使用此过滤器的更多信息。


    1. 来自 statsmodels 的 LOWESS 更平滑

    LOWESS(局部加权散点图平滑)是一种local regression 方法。以我的经验,它很容易调整,并且通常会产生很好的效果。

    如何应用 LOWESS 平滑器:

    import statsmodels.api as sm
    
    y_lowess = sm.nonparametric.lowess(list_y, list_x, frac = 0.30)  # 30 % lowess smoothing
    
    plt.plot(y_lowess[:, 0], y_lowess[:, 1])
    plt.show()
    

    可以通过改变frac 参数来改进近似值,这是估计每个y 值时使用的数据的一部分。增加frac 值以增加平滑量。 frac 值必须介于 0 和 1 之间。

    有关statsmodels lowess usage的更多详细信息。


    1. 来自 scipy 的 IIR 过滤器

    应用 lfilter 后:

    from scipy.signal import lfilter
    
    n = 15             # larger n gives smoother curves
    b = [1.0 / n] * n  # numerator coefficients
    a = 1              # denominator coefficient
    y_lf = lfilter(b, a, list_y)
    
    plt.plot(list_x, y_lf)
    plt.show()
    

    查看scipy lfilter documentation,了解有关如何在差分方程中使用分子和分母系数的实施细节。

    scipy.signal package 中还有其他过滤器。


    必须注意避免对所有这些方法进行过度平滑。

    此外,其中一些方法可能会产生意想不到的边缘效应。

    【讨论】:

      【解决方案2】:

      与 Davis Herring 的建议相呼应的一个简单选择是对数据使用多项式近似

      import numpy as np
      import matplotlib.pyplot as plt
      
      plt.figure()
      poly = np.polyfit(list_x,list_y,5)
      poly_y = np.poly1d(poly)(list_x)
      plt.plot(list_x,poly_y)
      plt.plot(list_x,list_y)
      plt.show()
      

      您会注意到图右端的振荡在原始数据中不存在,这是多项式逼近的产物。

      Davis 建议的样条插值是另一个不错的选择。改变平滑度参数s可以在平滑度和与原始数据的距离之间取得不同的平衡。

      from scipy.interpolate import splrep, splev
      
      plt.figure()
      bspl = splrep(list_x,list_y,s=5)
      bspl_y = splev(list_x,bspl)
      plt.plot(list_x,list_y)
      plt.plot(list_x,bspl_y)
      plt.show()
      

      【讨论】:

      • 样条曲线现已弃用。这个答案描述了 BSpline 的新用法:stackoverflow.com/a/5284038/730150
      • 我在实现看似较新的 BSpline 时遇到了问题。它无法处理 None 值,并且曲线不像样条曲线那样平滑。可能是我的错,但也没有警告splrep, splev 被弃用。会不会是它们与已弃用的spline 不同?
      • 难道BSpline是在底部的脚本中手动完成的?至少它可以工作,没有被弃用的警告,并且被分配给 bspl,这似乎是 BSpline 的缩写。
      【解决方案3】:

      因为您的数据是近似的(,它已被量化),您需要approximating spline,而不是插值样条。

      【讨论】:

      • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
      • @SimasJoneliunas:对示例中的代码进行必要的更改是微不足道的,复制 SciPy 的 文档 与总结一些随机的博客文章有点不同。同时,可能有用的工作示例在几分钟内就被另一个答案采纳了,所以现在没有意义了。
      猜你喜欢
      • 2023-03-04
      • 1970-01-01
      • 1970-01-01
      • 2018-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-10
      • 2023-03-09
      相关资源
      最近更新 更多