平滑离散数据集

Smoothing a discrete data set

我正在尝试平滑此数据集并生成带有误差线的单一代表性曲线。获取数据点的方法是用相当粗略的步骤离散化的。我没有太多编程经验,但正在努力学习。我读到高斯滤波器可能是一个不错的选择。任何帮助,将不胜感激。

这是一个示例数据集:

Time (min)  Non-Normalized Shrinkage    Normalized Shrinkage
200 93  1.021978022
202 92  1.010989011
204 92  1.010989011
206 92  1.010989011
208 92  1.010989011
210 92  1.010989011
212 91  1
214 90  0.989010989
216 90  0.989010989
218 90  0.989010989
220 88  0.967032967
222 88  0.967032967
224 87  0.956043956
226 86  0.945054945
228 86  0.945054945
230 86  0.945054945
232 86  0.945054945
234 86  0.945054945
236 85  0.934065934
238 84  0.923076923
240 83  0.912087912
242 83  0.912087912
244 83  0.912087912
246 82  0.901098901
248 83  0.912087912
250 82  0.901098901
252 81  0.89010989
254 81  0.89010989
256 82  0.901098901
258 82  0.901098901
260 79  0.868131868
262 80  0.879120879
264 80  0.879120879

我在网上的某个地方找到了这个代码片段,但我不知道如何实现它,也不知道它是否正是我要找的。

def smoothListGaussian(list,degree=5):  

window=degree*2-1  

weight=numpy.array([1.0]*window)  

weightGauss=[]  

for i in range(window):  

    i=i-degree+1  

    frac=i/float(window)  

    gauss=1/(numpy.exp((4*(frac))**2))  

    weightGauss.append(gauss)  

weight=numpy.array(weightGauss)*weight  

smoothed=[0.0]*(len(list)-window)  

for i in range(len(smoothed)):  

    smoothed[i]=sum(numpy.array(list[i:i+window])*weight)/sum(weight)  

return smoothed 

通常,您会为此使用一个库,而不是自己实现它。

我将为此使用 scipy.ndimage 而不是 scipy.signal。如果您有过信号处理 class,您可能会发现 scipy.signal 方法更直观,但如果没有,它可能看起来很混乱。 scipy.ndimage 提供了 straight-forward、one-function-call gaussian_filter,而不是必须了解更多的信号处理约定。

这是一个简单的示例,使用您在问题中发布的数据。这假设您的数据是定期采样的(即:每 2 个单位的时间)。

import numpy as np
import matplotlib.pyplot as plt
import scipy.ndimage

time, _, shrinkage = np.loadtxt('discrete_data.txt', skiprows=1).T

fig, ax = plt.subplots()
ax.plot(time, shrinkage, 'ro')
ax.plot(time, scipy.ndimage.gaussian_filter(shrinkage, 3))
plt.show()

其中大部分相当 straight-forward,但您可能会注意到我在 scipy.ndimage.gaussian_filter(shrinkage, 3) 中指定的 3 的 "magical" 值。那就是样本中高斯函数的sigma参数。因为您的数据每 2 个单位及时采样一次,所以 sigma 为 6 个单位。

sigma 参数完全类似于 "bell curve" 正态分布中的标准差。你做得越大,高斯函数就会越宽,你的曲线就会越平滑。通过反复试验,值 3 似乎适合此特定数据集,但您应该进行试验并查看您认为最好的值。

最后一点:有很多不同的方法可以解决这个问题。高斯滤波器是一个合理的解决方案,但还有很多很多其他的。如果确切的结果非常重要,您可能应该比较几种方法,看看哪种方法最适合您的特定数据集。


在您的评论中,您询问了将平滑数据保存到文件而不是绘制它的问题。以下是您可能采用的一种方法的简单示例:

import numpy as np
import scipy.ndimage

time, _, shrinkage = np.loadtxt('discrete_data.txt', skiprows=1).T
smoothed = scipy.ndimage.gaussian_filter(shrinkage, 3)

np.savetxt('smoothed_data.txt', np.c_[time, smoothed])

如果您的数据集是有限的,我会考虑使用径向基函数研究高斯过程回归 (GPR)。这将实现与使用高斯滤波器平滑函数类似的结果,但有两个重要的好处:

  1. 它可以自动 select 过滤器的“神奇”标准偏差,这意味着输出估计将最适合您的数据。
  2. 它将为您提供其输出与您的数据相符的置信度估计 - 为您提供最佳误差线。

下面是 GPR 用于估计正弦波的示例:

如果您认为这可以解决您的问题,我建议您查看 Python 中的 GPy 库:https://nbviewer.jupyter.org/github/SheffieldML/notebook/blob/master/GPy/index.ipynb