【问题标题】:Gradient in noisy data, python噪声数据中的梯度,python
【发布时间】:2013-03-29 12:42:24
【问题描述】:

我有一个来自宇宙射线探测器的能谱。光谱遵循指数曲线,但其中会有很宽(可能非常轻微)的肿块。显然,数据包含噪声元素。

我正在尝试平滑数据,然后绘制其梯度。 到目前为止,我一直在使用 scipy sline 函数对其进行平滑处理,然后使用 np.gradient()。

从图中可以看出,梯度函数的方法是寻找每个点之间的差异,并不能很清楚地显示出肿块。

我基本上需要一个平滑的渐变图。任何帮助都会很棒!

我尝试了 2 种样条方法:

def smooth_data(y,x,factor):
    print "smoothing data by interpolation..."
    xnew=np.linspace(min(x),max(x),factor*len(x))
    smoothy=spline(x,y,xnew)
    return smoothy,xnew

def smooth2_data(y,x,factor):
    xnew=np.linspace(min(x),max(x),factor*len(x))
    f=interpolate.UnivariateSpline(x,y)
    g=interpolate.interp1d(x,y)
    return g(xnew),xnew

编辑:尝试数值微分:

def smooth_data(y,x,factor):
    print "smoothing data by interpolation..."
    xnew=np.linspace(min(x),max(x),factor*len(x))
    smoothy=spline(x,y,xnew)
    return smoothy,xnew

def minim(u,f,k):
    """"functional to be minimised to find optimum u. f is original, u is approx"""
    integral1=abs(np.gradient(u))
    part1=simps(integral1)
    part2=simps(u)
    integral2=abs(part2-f)**2.
    part3=simps(integral2)
    F=k*part1+part3
    return F


def fit(data_x,data_y,denoising,smooth_fac):
    smy,xnew=smooth_data(data_y,data_x,smooth_fac)
    y0,xnnew=smooth_data(smy,xnew,1./smooth_fac)
    y0=list(y0)
    data_y=list(data_y)
    data_fit=fmin(minim, y0, args=(data_y,denoising), maxiter=1000, maxfun=1000)
    return data_fit

但是,它只是再次返回相同的图表!

【问题讨论】:

    标签: python gradient smoothing


    【解决方案1】:

    在此发布了一个有趣的方法Numerical Differentiation of Noisy Data。它应该为您的问题提供一个很好的解决方案。更多细节在另一个accompanying paper 中给出。作者还给Matlab code that implements it;也可以使用替代implementation in Python

    如果你想追求样条插值方法,我建议调整s的平滑因子scipy.interpolate.UnivariateSpline()

    另一种解决方案是通过卷积(例如使用高斯)平滑您的函数。

    我链接到的那篇论文声称可以防止卷积方法产生的一些伪影(样条方法可能会遇到类似的困难)。

    【讨论】:

    • 我试过数值微分法:见新附件
    • part2 = simps(u) 不正确:part2 应该是一个数组,其中包含 u 从 0 到每个横坐标 的积分。然后你应该尝试一个指数变化的平滑系数,以便找到最适合你需要的那个。如果您真的通过考虑 x 中的步长来计算导数,那么我希望一个好的平滑因子约为 1e6,因为导数主要位于 -1 和 +1 之间——虽然我可能错了,但您可能想要无论如何都要尝试这个值,以防万一我的粗略计算是正确的。
    • PS:也没有没有必要事先平滑你的数据,使用噪声数据的数值微分方法。这看起来是一个有趣的方法。我期待着你的结果!祝你好运……
    • 有人能告诉我如何处理类似的问题,但数据分布不均匀吗?我有 X 和 Y 的测量集。论文中描述的算法是否合适?我尝试通过 python 实现,但还没有找到引入 X 测量值的方法。
    • @Spu,它只适用于均匀分布的数据。 @EOL 在此处发布的 python 实现中包含的函数将网格间距 dx 作为标量
    【解决方案2】:

    我不会保证这在数学上的有效性;看起来 EOL 引用的 LANL 的论文值得研究。无论如何,在使用 splev 时,我使用 SciPy 的样条曲线的内置微分得到了不错的结果。

    %matplotlib inline
    from matplotlib import pyplot as plt
    import numpy as np
    from scipy.interpolate import splrep, splev
    
    x = np.arange(0,2,0.008)
    data = np.polynomial.polynomial.polyval(x,[0,2,1,-2,-3,2.6,-0.4])
    noise = np.random.normal(0,0.1,250)
    noisy_data = data + noise
    
    f = splrep(x,noisy_data,k=5,s=3)
    #plt.plot(x, data, label="raw data")
    #plt.plot(x, noise, label="noise")
    plt.plot(x, noisy_data, label="noisy data")
    plt.plot(x, splev(x,f), label="fitted")
    plt.plot(x, splev(x,f,der=1)/10, label="1st derivative")
    #plt.plot(x, splev(x,f,der=2)/100, label="2nd derivative")
    plt.hlines(0,0,2)
    plt.legend(loc=0)
    plt.show()
    

    【讨论】:

    • 这种方法可以用于非均匀分布的数据吗?我可以为 X 和 Y 添加我的测量集吗?
    • 这里使用的函数的文档 (scipy.interpolate.splrep()) 没有提到对非均匀分布数据的任何限制。除了查看文档之外,您当然也可以通过更改代码中x 的值自行尝试。更一般地说,感谢您在 Stack Overflow 上为回答自己的问题做出了一些明显的努力,以便为其他人节省一些时间(并使他们更有可能花时间回答您的问题)。
    • @Spu,是的!就在两天前,我使用splrep 对以非均匀间隔采集的样本数据执行三次 b 样条插值,以便执行 FFT。
    【解决方案3】:

    您也可以使用scipy.signal.savgol_filter

    结果

    示例

    import matplotlib.pyplot as plt
    import numpy as np
    import scipy
    from random import random
    
    # generate data
    x = np.array(range(100))/10
    y = np.sin(x) + np.array([random()*0.25 for _ in x])
    dydx = scipy.signal.savgol_filter(y, window_length=11, polyorder=2, deriv=1)
    
    # Plot result
    plt.plot(x, y, label='Original signal')
    plt.plot(x, dydx*10, label='1st Derivative')
    plt.plot(x, np.cos(x), label='Expected 1st Derivative')
    plt.legend()
    plt.show()
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 2016-09-27
    • 1970-01-01
    • 1970-01-01
    • 2020-08-19
    • 2010-12-10
    相关资源
    最近更新 更多