2013-04-07 4 views
6

У меня есть энергетический спектр от детектора космических лучей. Спектр следует за экспоненциальной кривой, но в нем будут широкие (и, возможно, очень небольшие) куски. Данные, очевидно, содержат элемент шума.Градиент в шумных данных, python

Я пытаюсь сгладить данные, а затем график его градиента. До сих пор я использовал функцию 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 

Однако, он просто возвращает тот же граф снова!

Data, smoothed data and gradients

+0

Какой уровень сглаживания будет иметь смысл для вас? тот, который дает производную от около -10 до +1, причем большинство значений между -1 и +1? – EOL

+0

Примечание: рекомендую прочитать и применить [PEP 8] (http://www.python.org/dev/peps/pep-0008/) к вашему стилю кодирования. Это упростит чтение кода, как это делает большинство программистов Python (или его часть). Небольшие детали, такие как обычные пробелы вокруг '=' в назначениях или после запятых в списках параметров, делают код более понятным. – EOL

ответ

8

Существует интересный метод опубликовал на этом: Numerical Differentiation of Noisy Data. Это должно дать вам хорошее решение вашей проблемы. Более подробная информация приведена в другом, accompanying paper. Автор также дает Matlab code that implements it; существует альтернатива implementation in Python.

Если вы хотите продолжить интерполяции со шлицами метода, я хотел бы предложить, чтобы настроить коэффициент сглаживания s в scipy.interpolate.UnivariateSpline().

Другим решением будет сглаживание вашей функции посредством свертки (скажем, с гауссовским).

Документ, который я связывал с претензиями, чтобы предотвратить некоторые из артефактов, которые придумывают подход свертки (подход сплайна может пострадать от подобных трудностей).

+0

Я пробовал метод численного дифференцирования: см. Новое вложение – Lucidnonsense

+0

Строка 'part2 = simps (u)' неверна: 'part2' должен быть массивом, который содержит интеграл от u от 0 * до каждой абсциссы *. Затем вы должны попробовать * экспоненциально меняющийся * коэффициент сглаживания, чтобы найти тот, который лучше всего подходит вашим потребностям.Если вы действительно вычислите производную, учитывая размер шага в x, я ожидаю, что хороший коэффициент сглаживания будет составлять около 1e6, для производной, которая лежит в основном между -1 и + 1, в то время как я могу ошибаться, вы можете захотеть чтобы попробовать это значение в любом случае, на всякий случай, если мой вердикт-расчет будет правильным. – EOL

+0

Спасибо, я попробую! – Lucidnonsense

3

Я не буду ручаться за математическую обоснованность этого; это похоже на бумагу из LANL, которую цитировал EOL. Во всяком случае, я получил приличные результаты, используя встроенную дифференциацию сплайнов SciPy при использовании splev.

%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() 

matplotlib output

+0

Можно ли использовать этот метод для неравномерно распределенных данных? Могу ли я добавить свои наборы измерений как для X, так и для Y? – Spu

+0

Документация для используемой здесь функции ('scipy.interpolate.splrep()') не содержит ограничений для неравномерно распределенных данных. Помимо просто просмотра документации, вы также можете попробовать самостоятельно, изменив значение «x» в коде. В более общем плане, вы можете приложить некоторые видимые усилия, чтобы ответить на свой вопрос, на переполнение стека, чтобы немного сэкономить другие (и заставите их с большей вероятностью взять время, чтобы ответить на ваш вопрос). – EOL

+1

@ Спу, да! Я использовал «splrep» всего два дня назад, чтобы выполнить кубическую b-сплайн-интерполяцию пробных данных, полученных с неравномерными интервалами, чтобы я мог выполнять БПФ. – billyjmc

Смежные вопросы