Данные сглаживания Python

У меня есть набор данных, который я хочу сгладить. У меня есть две переменные y и x, которые расположены неравномерно. у - зависимая переменная. Однако я не знаю, какая формула связывает x с y.

Я много читал об интерполяции, но интерполяция требует, чтобы я знал формулу, связывающую x с y. Я также рассмотрел другие функции сглаживания, но они вызывают проблемы в начальной и конечной точках.

Кто-нибудь знает, как: - получить формулу, которая связывает x с y - сгладить точки данных, не испортив конечные точки

Мои данные выглядят следующим образом:

import matplotlib.pyplot as plt

x = [0.0, 2.4343476531707129, 3.606959459205791, 3.9619355597454664, 4.3503348239356558, 4.6651002761894667, 4.9360228447915109, 5.1839565805565826, 5.5418099660513596, 5.7321342976055165,5.9841050994671106, 6.0478709402949216, 6.3525180590674513, 6.5181245134579893, 6.6627517592933767, 6.9217136972938444,7.103121623408132, 7.2477706136047413, 7.4502723880766748, 7.6174503055171137, 7.7451599936721376, 7.9813193157205191, 8.115292520850506,8.3312689109403202, 8.5648187916197998, 8.6728478860287623, 8.9629327234023926, 8.9974662723308612, 9.1532523634107257, 9.369326186780814, 9.5143785756455479, 9.5732694726297893, 9.8274813411538613, 10.088572892445802, 10.097305715988142, 10.229215999264703, 10.408589988296546, 10.525354763219688, 10.574678982757082, 10.885039893236041, 11.076574204171795, 11.091570626351352, 11.223859812944436, 11.391634940142225, 11.747328449715521, 11.799186895037078, 11.947711314893802, 12.240901223703657, 12.50151825769724, 12.811712563174883, 13.153496854155087, 13.978408296586579, 17.0, 25.0]
y = [0.0, 4.0, 6.0, 18.0, 30.0, 42.0, 54.0, 66.0, 78.0, 90.0, 102.0, 114.0, 126.0, 138.0, 150.0, 162.0, 174.0, 186.0, 198.0, 210.0, 222.0, 234.0, 246.0, 258.0, 270.0, 282.0, 294.0, 306.0, 318.0, 330.0, 342.0, 354.0, 366.0, 378.0, 390.0, 402.0, 414.0, 426.0, 438.0, 450.0, 462.0, 474.0, 486.0, 498.0, 510.0, 522.0, 534.0, 546.0, 558.0, 570.0, 582.0, 594.0, 600.0, 600.0]

#Smoothing here

fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(x, y, color='red', label= 'Unsmoothed curve')

person Alex    schedule 04.03.2015    source источник


Ответы (2)


Я думаю, что здесь есть путаница между сглаживанием (то есть фильтрацией), интерполяцией и подгонкой кривой,

  • Фильтрация/сглаживание: мы применяем оператор к данным, который модифицирует исходные y точки таким образом, чтобы удалить высокочастотные колебания. Этого можно достичь, например, с помощью подходов на основе scipy.signal.convolve, scipy.signal.medfilt, scipy.signal.savgol_filter или БПФ.

  • Интерполяция: мы создаем непрерывное локальное представление данных из доступных точек данных. Интерполяция определяет поведение функции между точками данных, но не изменяет сами точки данных. См., например, scipy.interpolate.interp1d. Хотя, чтобы усложнить ситуацию, сплайн-интерполяция на самом деле также делает некоторое сглаживание.

  • Подгонка кривой: мы подгоняем точку данных с помощью некоторой аналитической функции. Это позволяет определить глобальную взаимосвязь между x и y в наших данных, но требует некоторого предварительного понимания подходящей функции подбора. См. scipy.optimize.curve_fit

В этом конкретном случае подход, который мы можем использовать, состоит в том, чтобы сначала интерполировать по равномерной сетке (как в @agomcas). ответ), а затем применить фильтр Савицкого-Голея, чтобы сгладить данные. В качестве альтернативы данные могут быть приспособлены к некоторому аналитическому выражению, скажем, на основе функции тангенса, но это требует дальнейшей настройки:

import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy.interpolate import interp1d
from scipy.signal import savgol_filter
import numpy as np

x = np.array([0.0, 2.4343476531707129, 3.606959459205791, 3.9619355597454664, 4.3503348239356558, 4.6651002761894667, 4.9360228447915109, 5.1839565805565826, 5.5418099660513596, 5.7321342976055165,5.9841050994671106, 6.0478709402949216, 6.3525180590674513, 6.5181245134579893, 6.6627517592933767, 6.9217136972938444,7.103121623408132, 7.2477706136047413, 7.4502723880766748, 7.6174503055171137, 7.7451599936721376, 7.9813193157205191, 8.115292520850506,8.3312689109403202, 8.5648187916197998, 8.6728478860287623, 8.9629327234023926, 8.9974662723308612, 9.1532523634107257, 9.369326186780814, 9.5143785756455479, 9.5732694726297893, 9.8274813411538613, 10.088572892445802, 10.097305715988142, 10.229215999264703, 10.408589988296546, 10.525354763219688, 10.574678982757082, 10.885039893236041, 11.076574204171795, 11.091570626351352, 11.223859812944436, 11.391634940142225, 11.747328449715521, 11.799186895037078, 11.947711314893802, 12.240901223703657, 12.50151825769724, 12.811712563174883, 13.153496854155087, 13.978408296586579, 17.0, 25.0])
y = np.array([0.0, 4.0, 6.0, 18.0, 30.0, 42.0, 54.0, 66.0, 78.0, 90.0, 102.0, 114.0, 126.0, 138.0, 150.0, 162.0, 174.0, 186.0, 198.0, 210.0, 222.0, 234.0, 246.0, 258.0, 270.0, 282.0, 294.0, 306.0, 318.0, 330.0, 342.0, 354.0, 366.0, 378.0, 390.0, 402.0, 414.0, 426.0, 438.0, 450.0, 462.0, 474.0, 486.0, 498.0, 510.0, 522.0, 534.0, 546.0, 558.0, 570.0, 582.0, 594.0, 600.0, 600.0])


xx = np.linspace(x.min(),x.max(), 1000)

# interpolate + smooth
itp = interp1d(x,y, kind='linear')
window_size, poly_order = 101, 3
yy_sg = savgol_filter(itp(xx), window_size, poly_order)


# or fit to a global function
def func(x, A, B, x0, sigma):
    return A+B*np.tanh((x-x0)/sigma)

fit, _ = curve_fit(func, x, y)
yy_fit = func(xx, *fit)

fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(x, y, 'r.', label= 'Unsmoothed curve')
ax.plot(xx, yy_fit, 'b--', label=r"$f(x) = A + B \tanh\left(\frac{x-x_0}{\sigma}\right)$")
ax.plot(xx, yy_sg, 'k', label= "Smoothed curve")
plt.legend(loc='best')

метод сглаживания

person rth    schedule 04.03.2015
comment
Здравствуйте, спасибо за ваш ответ, но я действительно не понимаю, что вы имеете в виду под последней формулой для подгонки. Должен ли я использовать эту формулу в качестве параметров для функции scipy.optimize.curve.fit? - person Alex; 04.03.2015
comment
Правильно, я отредактировал ответ выше, чтобы он был более явным, а также исправил несколько неправильных утверждений. - person rth; 05.03.2015
comment
Вау, фильтр савгол у них классно смотрится. Это, безусловно, решило мою проблему сглаживания. Однако мне все еще интересно, есть ли способ найти математическую формулу, описывающую график. - person Alex; 05.03.2015

Интерполяция не требует знания формулы, связывающей x и y.

import matplotlib.pyplot as plt
from scipy import interpolate
import numpy as np

x = [0.0, 2.4343476531707129, 3.606959459205791, 3.9619355597454664, 4.3503348239356558, 4.6651002761894667, 4.9360228447915109, 5.1839565805565826, 5.5418099660513596, 5.7321342976055165,5.9841050994671106, 6.0478709402949216, 6.3525180590674513, 6.5181245134579893, 6.6627517592933767, 6.9217136972938444,7.103121623408132, 7.2477706136047413, 7.4502723880766748, 7.6174503055171137, 7.7451599936721376, 7.9813193157205191, 8.115292520850506,8.3312689109403202, 8.5648187916197998, 8.6728478860287623, 8.9629327234023926, 8.9974662723308612, 9.1532523634107257, 9.369326186780814, 9.5143785756455479, 9.5732694726297893, 9.8274813411538613, 10.088572892445802, 10.097305715988142, 10.229215999264703, 10.408589988296546, 10.525354763219688, 10.574678982757082, 10.885039893236041, 11.076574204171795, 11.091570626351352, 11.223859812944436, 11.391634940142225, 11.747328449715521, 11.799186895037078, 11.947711314893802, 12.240901223703657, 12.50151825769724, 12.811712563174883, 13.153496854155087, 13.978408296586579, 17.0, 25.0]
y = [0.0, 4.0, 6.0, 18.0, 30.0, 42.0, 54.0, 66.0, 78.0, 90.0, 102.0, 114.0, 126.0, 138.0, 150.0, 162.0, 174.0, 186.0, 198.0, 210.0, 222.0, 234.0, 246.0, 258.0, 270.0, 282.0, 294.0, 306.0, 318.0, 330.0, 342.0, 354.0, 366.0, 378.0, 390.0, 402.0, 414.0, 426.0, 438.0, 450.0, 462.0, 474.0, 486.0, 498.0, 510.0, 522.0, 534.0, 546.0, 558.0, 570.0, 582.0, 594.0, 600.0, 600.0]


f = interpolate.interp1d(x, y, kind="linear")
x_int = np.linspace(x[0],x[-1], 20)
y_int = f(x_int)

#Smoothing here

fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(x, y, color='red', label= 'Unsmoothed curve')
ax.plot(x_int, y_int, color="blue", label= "Interpolated curve")
person agomcas    schedule 04.03.2015
comment
Забыл сказать, кривая технически еще не сглажена. Однако, поскольку я использовал меньше точек для интерполированных данных, они уже выглядят менее зашумленными. - person agomcas; 04.03.2015