【问题标题】:Reducing noise on Data减少数据噪音
【发布时间】:2016-10-02 14:40:36
【问题描述】:

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

我能减少数据上的噪音吗?卡尔曼滤波器可以在这里工作吗?

【问题讨论】:

    标签: python smoothing noise kalman-filter


    【解决方案1】:

    这取决于您如何定义“噪音”以及它是如何产生的。由于您没有提供有关您的案例的太多信息,因此我将您的问题视为“如何使曲线平滑”。卡尔曼滤波器可以做到,但是太复杂了,我更喜欢简单的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。卡尔曼滤波器也应该适用于这种情况,只是没那么必要。

    【讨论】:

      【解决方案2】:

      根据您想要去除噪音的程度,您还可以使用来自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

      【讨论】:

        【解决方案3】:

        如果您正在处理时间序列,我建议您 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可以以矢量化的方式对多个时间序列进行平滑

        【讨论】:

          【解决方案4】:

          根据您的最终用途,可能值得考虑使用 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 可能就足够了。

          例如,使用窗口大小为 30 的pandas

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

          您可能需要对数据尝试几种窗口大小。 请注意,df_mva 的前 30 个值将是 NaN,但可以使用 dropna 方法删除这些值。

          pandas rolling function 的使用详情。


          最后,插值可用于通过平滑降噪。

          这是来自scipyradial basis function interpolation 示例:

          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 中的其他Rbf 选项。 Scipy 提供了其他单变量和多变量插值技术(参见tutorial)。


          如果您的数据以固定间隔进行采样,LOWESS 和滚动平均方法都将提供更好的结果。

          径向基函数插值对于这个数据集来说可能是多余的,但如果您的数据是更高维度的和/或不是在常规网格上采样的,那么它绝对值得您注意。

          所有这些方法都必须小心;很容易去除过多的噪声并扭曲基础信号。

          【讨论】:

            猜你喜欢
            • 2011-06-10
            • 2020-05-22
            • 1970-01-01
            • 2015-09-25
            • 1970-01-01
            • 2012-07-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多