Supongamos que tenemos un conjunto de datos que podría ser dado aproximadamente por
import numpy as np
x = np.linspace(0,2*np.pi,100)
y = np.sin(x) + np.random.random(100) * 0.2
Por lo tanto, tenemos una variación del 20% del conjunto de datos. Mi primera idea fue usar la función UnivariateSpline de scipy, pero el problema es que esto no considera el ruido pequeño en el buen sentido. Si considera las frecuencias, el fondo es mucho más pequeño que la señal, por lo que una spline solo del corte podría ser una idea, pero eso implicaría una transformación de Fourier de ida y vuelta, lo que podría provocar un mal comportamiento. Otra forma sería un promedio móvil, pero esto también necesitaría la elección correcta del retraso.
¿Alguna pista / libro o enlace sobre cómo abordar este problema?
python
numpy
scipy
signal-processing
data-processing
varantir
fuente
fuente
Respuestas:
Prefiero un filtro Savitzky-Golay . Utiliza mínimos cuadrados para hacer retroceder una pequeña ventana de sus datos en un polinomio, luego usa el polinomio para estimar el punto en el centro de la ventana. Finalmente, la ventana se desplaza hacia adelante por un punto de datos y el proceso se repite. Esto continúa hasta que cada punto se haya ajustado de manera óptima en relación con sus vecinos. Funciona muy bien incluso con muestras ruidosas de fuentes no periódicas y no lineales.
Aquí hay un ejemplo completo de libro de cocina . Vea mi código a continuación para tener una idea de lo fácil que es usarlo. Nota: omití el código para definir la
savitzky_golay()
función porque literalmente puedes copiarlo / pegarlo del ejemplo del libro de cocina que vinculé anteriormente.ACTUALIZACIÓN: Me ha llamado la atención que el ejemplo del libro de cocina al que me vinculé ha sido eliminado. Afortunadamente, el filtro Savitzky-Golay se ha incorporado a la biblioteca SciPy , como lo señaló @dodohjk . Para adaptar el código anterior utilizando la fuente SciPy, escriba:
fuente
savgol_filter((x, y), ...)
.Una forma rápida y sucia de suavizar los datos que uso, basada en un cuadro de media móvil (por convolución):
fuente
scipy.ndimage.filters.convolve1d()
le permite especificar un eje de una matriz nd para hacer el filtrado. Pero creo que ambos sufren algunos problemas en los valores enmascarados.Si está interesado en una versión "uniforme" de una señal que sea periódica (como su ejemplo), entonces una FFT es el camino correcto. Tome la transformada de Fourier y reste las frecuencias de baja contribución:
Incluso si su señal no es completamente periódica, esto hará un gran trabajo restando el ruido blanco. Hay muchos tipos de filtros para usar (paso alto, paso bajo, etc.), el apropiado depende de lo que esté buscando.
fuente
Ajustar un promedio móvil a sus datos suavizaría el ruido, vea esta respuesta para saber cómo hacerlo.
Si desea utilizar LOWESS para ajustar sus datos (es similar a un promedio móvil pero más sofisticado), puede hacerlo utilizando la biblioteca de statsmodels :
Finalmente, si conoce la forma funcional de su señal, podría ajustar una curva a sus datos, lo que probablemente sería lo mejor.
fuente
loess
implementado.Otra opción es usar KernelReg en statsmodels :
fuente
¡Mira esto! Hay una definición clara de suavizado de una señal 1D.
http://scipy-cookbook.readthedocs.io/items/SignalSmooth.html
Atajo:
fuente
Si está trazando un gráfico de series de tiempo y si ha utilizado mtplotlib para dibujar gráficos, utilice el método mediano para suavizar el gráfico
¿Dónde se
timeseries
pasa su conjunto de datos que puede modificarwindowsize
para obtener más suavizado?fuente