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

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

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, но проблема в том, что это не учитывает небольшой шум в хорошем смысле. Если вы рассматриваете частоты, фон намного меньше сигнала, поэтому сплайн только обрезания может быть идеей, но это будет включать в себя преобразование Фурье назад и вперед, что может привести к плохому поведению. Другим способом будет скользящее среднее, но для этого также потребуется правильный выбор задержки.

Любые подсказки / книги или ссылки, как решить эту проблему?

пример

  • Создание дискретных случайных величин с заданными весами с использованием SciPy или NumPy
  • Должен ли я переключиться на Python?
  • Инструмент для преобразования кода MATLAB в Python
  • Как эффективно вычислять огромное умножение матрицы (функции tfidf) в Python?
  • Как заставить scipy.interpolate дать экстраполированный результат за пределами диапазона ввода?
  • Вырезать частичное изображение с помощью NumPy (или SciPy)
  • Как быстро выполнить установку наименьших квадратов по множеству наборов данных?
  • Установка SciPy / Python на Ubuntu
  • 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() 
    Interesting Posts

    как динамически обновлять график в цикле в ноутбуке ipython (в одной ячейке)

    Как можно сократить идентификаторы монго для лучшего использования в URL-адресах?

    Нужна помощь при добавлении цикла для перезапуска программы в Python

    Создать список одного элемента, повторяющегося n раз в Python

    Как указать порядок установки для питона python?

    добавление каталога в sys.path / PYTHONPATH

    Как проверить, является ли элемент списка списком (в Python)?

    Как нормализовать список положительного и отрицательного десятичного числа до определенного диапазона

    Как установить скрипт для работы в любом месте из командной строки?

    Что означает `**` в выражении `dict (d1, ** d2)`?

    Перемеживающие списки в Python

    Python: удалить слова между двумя разделителями

    Создайте колесо для пакета (например, scipy), в котором отсутствует декларация зависимости

    TF slice_input_producer не синхронизирует тензоры

    Python: Sanitize строку для unicode?

    Python - лучший язык программирования в мире.