减少数据噪声

17

我有两个包含数据点的列表。

x = ["bunch of data points"]
y = ["bunch of data points"]

我使用Python中的Matplotlib生成了一个图表

import matplotlib.pyplot as plt

plt.plot(x, y, linewidth=2, linestyle="-", c="b")
plt.show()
plt.close()

我能否降低数据的噪声?卡尔曼滤波器在这里是否有效?

输入图片描述

4个回答

27

这要看你如何定义“噪声”以及它是如何引起的。由于你没有提供关于你的情况的太多信息,我会把你的问题理解为“如何使曲线平滑”。卡尔曼滤波器可以实现这一点,但它过于复杂,我更喜欢简单的IIR滤波器。

import matplotlib.pyplot as plt
import numpy as np

mu, sigma = 0, 500

x = np.arange(1, 100, 0.1)  # x axis
z = np.random.normal(mu, sigma, len(x))  # noise
y = x ** 2 + z  # data
plt.plot(x, y, linewidth=2, linestyle="-", c="b")  # it includes some noise

输入图像描述

筛选后

from scipy.signal import lfilter

n = 15  # the larger n is, the smoother curve will be
b = [1.0 / n] * n
a = 1
yy = lfilter(b, a, y)
plt.plot(x, yy, linewidth=2, linestyle="-", c="b")  # smooth by filter

输入图像描述

lfilter 是来自scipy.signal的一个函数。

顺便说一下,如果您想要使用Kalman滤波进行平滑处理,scipy也提供了一个示例。 Kalman滤波器在这种情况下也可以工作,但并不是必须的。


19

根据您想要减少噪音的程度,您也可以使用scipy中的Savitzky-Golay过滤器。

以下是来自@lyken-syu的示例:

import matplotlib.pyplot as plt
import numpy as np
mu, sigma = 0, 500
x = np.arange(1, 100, 0.1)  # x axis
z = np.random.normal(mu, sigma, len(x))  # noise
y = x ** 2 + z # data
plt.plot(x, y, linewidth=2, linestyle="-", c="b")  # it include some noise

输入图像描述

并应用了Savitzky-Golay过滤器

from scipy.signal import savgol_filter
w = savgol_filter(y, 101, 2)
plt.plot(x, w, 'b')  # high frequency noise removed

window_length = 101

window_length增加到501:

window_length = 501

在此处阅读有关滤波器的更多信息


6
如果你正在处理时间序列,我建议你使用tsmoothie:一个用于向量化时间序列平滑和异常值检测的Python库。它提供了不同的平滑算法以及计算区间的可能性。在这里,我使用了ConvolutionSmoother,但你也可以尝试其他方法。(还有KalmanSmoother可用)
import numpy as np
import matplotlib.pyplot as plt
from tsmoothie.smoother import *

mu, sigma = 0, 500
x = np.arange(1, 100, 0.1)  # x axis
z = np.random.normal(mu, sigma, len(x))  # noise
y = x ** 2 + z # data

# operate smoothing
smoother = ConvolutionSmoother(window_len=30, window_type='ones')
smoother.smooth(y)

# generate intervals
low, up = smoother.get_intervals('sigma_interval', n_sigma=3)

# plot the smoothed timeseries with intervals
plt.figure(figsize=(11,6))
plt.plot(smoother.data[0], color='orange')
plt.plot(smoother.smooth_data[0], linewidth=3, color='blue')
plt.fill_between(range(len(smoother.data[0])), low[0], up[0], alpha=0.3)

enter image description here

我还要指出,tsmoothie可以以向量化的方式平滑多个时间序列。

3

根据您的最终使用情况,考虑使用LOWESS(局部加权散点图平滑)去除噪声可能是值得的。我已经在重复测量数据集中成功使用过它。

有关局部回归方法(包括LOWESS和LOESS)的更多信息,请单击此处

为了与其他答案保持一致,使用@lyken-syu的示例数据:

import numpy as np
import matplotlib.pyplot as plt

mu, sigma = 0, 500
x = np.arange(1, 100, 0.1)  # x axis
z = np.random.normal(mu, sigma, len(x))  # noise
y = x ** 2 + z  # signal + noise

plt.plot(x, y, linewidth = 2, linestyle = "-", c = "b")  # includes some noise
plt.show()

enter image description here

以下是使用statsmodels实现LOWESS技术的方法:

import statsmodels.api as sm

y_lowess = sm.nonparametric.lowess(y, x, frac = 0.3)  # 30 % lowess smoothing

plt.plot(y_lowess[:, 0], y_lowess[:, 1], 'b')  # some noise removed
plt.show()

enter image description here

在估计每个y值时使用的数据分数参数可能需要变化。 增加frac值可以增加平滑量。 frac值必须介于0和1之间。

statsmodels lowess usage上有更多详细信息。


有时候,一个简单的滚动均值可能就足够了。
例如,使用pandas,窗口大小为30:
import pandas as pd

df = pd.DataFrame(y, x)
df_mva = df.rolling(30).mean()  # moving average with a window size of 30

df_mva.plot(legend = False);

enter image description here

你可能需要尝试多个窗口大小来处理数据。 请注意,df_mva 的前30个值将是NaN,但可以使用dropna方法删除这些值。 pandas rolling function的使用细节。

最后,插值可以通过平滑来进行噪声降低。

以下是scipy提供的径向基函数插值示例:

from scipy.interpolate import Rbf

rbf = Rbf(x, y, function = 'quintic', smooth = 10)

xnew = np.linspace(x.min(), x.max(), num = 100, endpoint = True)
ynew = rbf(xnew)

plt.plot(xnew, ynew)
plt.show()

enter image description here

通过增加smooth参数可以实现更平滑的逼近。考虑其他function参数,包括'cubic'和'thin_plate'。在考虑function值时,我通常先尝试'thin_plate',然后再尝试'cubic'; 'thin_plate' 产生了良好的结果,但需要非常高的smooth值来处理此数据集,而'cubic'似乎无法处理噪声。

查看scipy docs中的其他Rbf选项。Scipy提供其他一元和多元插值技术(请参见此tutorial)。


如果您的数据按照规律间隔采样,则LOWESS和滚动平均方法都能够提供更好的结果。

对于这个数据集,径向基函数插值可能过于复杂,但如果您的数据是高维的或者不在规则网格上采样,则一定值得关注。

需要注意所有这些方法;很容易消除过多噪声并扭曲基本信号。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接