在 Python 中平滑曲线

新手上路,请多包涵

我有两个数据点列表:

 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()

在此处输入图像描述

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

在此处输入图像描述

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

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

 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()

在此处输入图像描述

原文由 Fxs7576 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
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()

B 样条逼近

原文由 Dmitri Chubarov 发布,翻译遵循 CC BY-SA 3.0 许可协议

这里还有 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 文档 中阅读有关使用此过滤器的更多信息。


  1. 来自 statsmodels 的 LOWESS 更平滑

LOWESS(局部加权散点图平滑)是一种 局部回归 方法。根据我的经验,调整起来很简单,而且通常会产生很好的结果。

如何使用 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 文档 以了解有关如何在差分方程中使用分子和分母系数的实现细节。

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


必须注意避免使用所有这些方法过度平滑。

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

原文由 makeyourownmaker 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题