Как правильно сгладить кривую?

Предположим, что у нас есть набор данных, который может быть

import numpy as np x = np.linspace(0,2*np.pi,100) y = np.sin(x) + np.random.random(100) * 0.2 

Поэтому мы имеем 20% от набора данных. Моя первая идея заключалась в том, чтобы использовать функцию UnivariateSpline scipy, но проблема в том, что это не учитывает небольшой шум в хорошем смысле. Если вы рассматриваете частоты, фон намного меньше сигнала, поэтому сплайн только обрезания может быть идеей, но это будет включать в себя преобразование Фурье назад и вперед, что может привести к плохому поведению. Другим способом будет скользящее среднее, но для этого также потребуется правильный выбор задержки.

  • Прохождение двоичного дерева с использованием генератора
  • Рекурсивный diff двух словарей python (ключи и значения)
  • Как использовать функцию pandas apply для всех столбцов ряда строк данных
  • Python Реализация шаблона проектирования пула объектов
  • Перемещение оси x в начало графика в matplotlib
  • Каков наилучший способ реализации вложенных словарей?
  • Любые подсказки / книги или ссылки, как решить эту проблему?

    пример

  • Вычисление спектра мощности в python
  • Объекты общей памяти в многопроцессорной обработке
  • Как сделать больше или меньше, чем использовать MongoDB?
  • SQLAlchemy - самореляционное отношение Many-to-many с дополнительным столбцом
  • Питонический способ обнаружения выбросов в одномерных данных наблюдения
  • Перемещение оси x в начало графика в matplotlib
  • 5 Solutions collect form web for “Как правильно сгладить кривую?”

    Я предпочитаю фильтр Савицки-Голея . Он использует наименьшие квадраты для регрессии небольшого окна ваших данных на полином, а затем использует полином для оценки точки в центре окна. Наконец, окно сдвигается вперед на одну точку данных, и процесс повторяется. Это продолжается до тех пор, пока каждая точка не будет оптимально скорректирована относительно своих соседей. Он отлично работает даже с шумными образцами из непериодических и нелинейных источников.

    Вот пример поваренной книги . См. Мой код ниже, чтобы получить представление о том, как легко его использовать. Примечание. Я оставил код для определения функции savitzky_golay() потому что вы можете буквально скопировать / вставить его из приведенного выше примера поваренной книги.

     import numpy as np import matplotlib.pyplot as plt x = np.linspace(0,2*np.pi,100) y = np.sin(x) + np.random.random(100) * 0.2 yhat = savitzky_golay(y, 51, 3) # window size 51, polynomial order 3 plt.plot(x,y) plt.plot(x,yhat, color='red') plt.show() 

    оптимальное сглаживание шумовой синусоиды

    ОБНОВЛЕНИЕ: Мне пришло в голову, что пример кулинарной книги, с которым я связан, был снят. К счастью, похоже, фильтр Savitzky-Golay был включен в библиотеку SciPy , как указывает @dodohjk .

    Если вас интересует «плавная» версия периодического сигнала (например, вашего примера), то FFT – это правильный путь. Возьмите преобразование Фурье и вычтите низкочастотные частоты:

     import numpy as np import scipy.fftpack N = 100 x = np.linspace(0,2*np.pi,N) y = np.sin(x) + np.random.random(N) * 0.2 w = scipy.fftpack.rfft(y) f = scipy.fftpack.rfftfreq(N, x[1]-x[0]) spectrum = w**2 cutoff_idx = spectrum < (spectrum.max()/5) w2 = w.copy() w2[cutoff_idx] = 0 y2 = scipy.fftpack.irfft(w2) 

    введите описание изображения здесь

    Даже если ваш сигнал не является полностью периодическим, это отлично справится с вычитанием белого шума. Там используется множество типов фильтров (high-pass, low-pass и т. Д.), Соответствующий зависит от того, что вы ищете.

    Быстрый и грязный способ сглаживания данных, которые я использую, на основе скользящего среднего (сверткой):

     x = np.linspace(0,2*np.pi,100) y = np.sin(x) + np.random.random(100) * 0.8 def smooth(y, box_pts): box = np.ones(box_pts)/box_pts y_smooth = np.convolve(y, box, mode='same') return y_smooth plot(x, y,'o') plot(x, smooth(y,3), 'r-', lw=2) plot(x, smooth(y,19), 'g-', lw=2) 

    введите описание изображения здесь

    Приведение скользящего среднего к вашим данным сгладит шум, см. Этот ответ, как это сделать.

    Если вы хотите использовать LOWESS для соответствия вашим данным (это похоже на скользящее среднее, но более сложное), вы можете сделать это с помощью библиотеки statsmodels :

     import numpy as np import pylab as plt import statsmodels.api as sm x = np.linspace(0,2*np.pi,100) y = np.sin(x) + np.random.random(100) * 0.2 lowess = sm.nonparametric.lowess(y, x, frac=0.1) plt.plot(x, y, '+') plt.plot(lowess[:, 0], lowess[:, 1]) plt.show() 

    Наконец, если вы знаете функциональную форму вашего сигнала, вы можете подогнать кривую к своим данным, что, вероятно, будет лучше всего.

    Другой вариант – использовать KernelReg в statsmodel :

     from statsmodels.nonparametric.kernel_regression import KernelReg import numpy as np import matplotlib.pyplot as plt x = np.linspace(0,2*np.pi,100) y = np.sin(x) + np.random.random(100) * 0.2 # The third parameter specifies the type of the variable x; # 'c' stands for continuous kr = KernelReg(y,x,'c') plt.plot(x, y, '+') y_pred, y_std = kr.fit(x) plt.plot(x, y_pred) plt.show() 
    Python - лучший язык программирования в мире.