减少数据噪音
Reducing noise on Data
我有 2 个包含数据点的列表。
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()
我能减少数据上的噪音吗?卡尔曼滤波器在这里工作吗?
这取决于您如何定义 "noise" 以及它是如何引起的。由于你没有提供太多关于你的案例的信息,我将你的问题作为 "how to make the curve smooth"。卡尔曼滤波器可以做到这一点,但它太复杂了,我更喜欢简单的 IIR 滤波器
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 # data
plt.plot(x, y, linewidth=2, linestyle="-", c="b") # it include 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.
的函数
顺便说一句,如果你确实想使用卡尔曼滤波器进行平滑,scipy也提供了一个example。卡尔曼滤波器应该也适用于这种情况,只是没那么必要。
根据您喜欢去除噪声的程度,您还可以使用 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
到 501:
阅读有关过滤器的更多信息here
如果您正在处理时间序列,我建议您 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)
我还指出,tsmoothie 可以以矢量化的方式对多个时间序列进行平滑处理
根据您的最终用途,可能值得考虑使用 LOWESS(局部加权散点图平滑)来消除噪声。我已经成功地将它用于重复测量数据集。
有关局部回归方法的更多信息,包括 LOWESS 和 LOESS,here。
使用来自@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()
以下是如何使用 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()
可能需要改变 frac
参数,这是估计每个 y 值时使用的数据的一部分。增加 frac
值以增加平滑量。 frac
值必须介于 0 和 1 之间。
有关 statsmodels lowess usage 的更多详细信息。
有时一个简单的 rolling mean 可能就足够了。
例如,使用 pandas,window 大小为 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);
您可能需要使用您的数据尝试几种 window 大小。
请注意,df_mva
的前 30 个值将是 NaN
,但可以使用 dropna
方法删除这些值。
的使用详情
最后,插值可用于通过平滑降噪。
这里有一个例子 radial basis function interpolation from 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()
可以通过增加 smooth
参数来实现更平滑的近似。要考虑的备选 function
参数包括 'cubic' 和 'thin_plate'。在考虑 function
值时,我通常先尝试 'thin_plate' 然后再尝试 'cubic'; 'thin_plate' 给出了很好的结果,但需要非常高的 smooth
这个数据集的值并且 'cubic' 似乎在与噪音作斗争。
检查 scipy docs. Scipy provides other univariate and multivariate interpolation techniques (see this tutorial 中的其他 Rbf
选项。
如果定期对数据进行采样,LOWESS 和滚动均值方法都会提供更好的结果。
径向基函数插值对于这个数据集可能有点矫枉过正,但如果你的数据是更高维度的and/or而不是在规则网格上采样,那绝对值得你注意。
必须小心使用所有这些方法;很容易消除过多的噪音并扭曲底层信号。
我有 2 个包含数据点的列表。
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()
我能减少数据上的噪音吗?卡尔曼滤波器在这里工作吗?
这取决于您如何定义 "noise" 以及它是如何引起的。由于你没有提供太多关于你的案例的信息,我将你的问题作为 "how to make the curve smooth"。卡尔曼滤波器可以做到这一点,但它太复杂了,我更喜欢简单的 IIR 滤波器
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 # data
plt.plot(x, y, linewidth=2, linestyle="-", c="b") # it include 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.
顺便说一句,如果你确实想使用卡尔曼滤波器进行平滑,scipy也提供了一个example。卡尔曼滤波器应该也适用于这种情况,只是没那么必要。
根据您喜欢去除噪声的程度,您还可以使用 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
到 501:
阅读有关过滤器的更多信息here
如果您正在处理时间序列,我建议您 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)
我还指出,tsmoothie 可以以矢量化的方式对多个时间序列进行平滑处理
根据您的最终用途,可能值得考虑使用 LOWESS(局部加权散点图平滑)来消除噪声。我已经成功地将它用于重复测量数据集。
有关局部回归方法的更多信息,包括 LOWESS 和 LOESS,here。
使用来自@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()
以下是如何使用 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()
可能需要改变 frac
参数,这是估计每个 y 值时使用的数据的一部分。增加 frac
值以增加平滑量。 frac
值必须介于 0 和 1 之间。
有关 statsmodels lowess usage 的更多详细信息。
有时一个简单的 rolling mean 可能就足够了。
例如,使用 pandas,window 大小为 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);
您可能需要使用您的数据尝试几种 window 大小。
请注意,df_mva
的前 30 个值将是 NaN
,但可以使用 dropna
方法删除这些值。
最后,插值可用于通过平滑降噪。
这里有一个例子 radial basis function interpolation from 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()
可以通过增加 smooth
参数来实现更平滑的近似。要考虑的备选 function
参数包括 'cubic' 和 'thin_plate'。在考虑 function
值时,我通常先尝试 'thin_plate' 然后再尝试 'cubic'; 'thin_plate' 给出了很好的结果,但需要非常高的 smooth
这个数据集的值并且 'cubic' 似乎在与噪音作斗争。
检查 scipy docs. Scipy provides other univariate and multivariate interpolation techniques (see this tutorial 中的其他 Rbf
选项。
如果定期对数据进行采样,LOWESS 和滚动均值方法都会提供更好的结果。
径向基函数插值对于这个数据集可能有点矫枉过正,但如果你的数据是更高维度的and/or而不是在规则网格上采样,那绝对值得你注意。
必须小心使用所有这些方法;很容易消除过多的噪音并扭曲底层信号。