Supposons que nous ayons un ensemble de données qui pourrait être donné approximativement par
import numpy as np
x = np.linspace(0,2*np.pi,100)
y = np.sin(x) + np.random.random(100) * 0.2
Nous avons donc une variation de 20% de l'ensemble de données. Ma première idée a été d'utiliser la fonction UnivariateSpline de scipy, mais le problème est que cela ne considère pas le petit bruit dans le bon sens. Si vous considérez les fréquences, l'arrière-plan est beaucoup plus petit que le signal, donc une spline uniquement de la coupure pourrait être une idée, mais cela impliquerait une transformation de Fourier d'avant en arrière, ce qui pourrait entraîner un mauvais comportement. Une autre façon serait une moyenne mobile, mais cela nécessiterait également le bon choix du retard.
Des conseils / livres ou des liens sur la façon de résoudre ce problème?
Réponses:
Je préfère un filtre Savitzky-Golay . Il utilise les moindres carrés pour régresser une petite fenêtre de vos données sur un polynôme, puis utilise le polynôme pour estimer le point au centre de la fenêtre. Enfin, la fenêtre est décalée d'un point de données vers l'avant et le processus se répète. Cela continue jusqu'à ce que chaque point ait été ajusté de manière optimale par rapport à ses voisins. Cela fonctionne très bien même avec des échantillons bruyants provenant de sources non périodiques et non linéaires.
Voici un exemple complet de livre de cuisine . Voir mon code ci-dessous pour avoir une idée de la facilité d'utilisation. Remarque: J'ai omis le code pour définir la
savitzky_golay()
fonction car vous pouvez littéralement le copier / coller à partir de l'exemple de livre de cuisine que j'ai lié ci-dessus.MISE À JOUR: Il est venu à mon attention que l'exemple de livre de cuisine auquel j'ai lié a été retiré. Heureusement, le filtre Savitzky-Golay a été intégré à la bibliothèque SciPy , comme l'a souligné @dodohjk . Pour adapter le code ci-dessus à l'aide de la source SciPy, tapez:
la source
savgol_filter((x, y), ...)
.Un moyen rapide et sale de lisser les données que j'utilise, basé sur une boîte moyenne mobile (par convolution):
la source
scipy.ndimage.filters.convolve1d()
vous permet de spécifier un axe d'un nd-array pour effectuer le filtrage. Mais je pense que les deux souffrent de problèmes de valeurs masquées.Si vous êtes intéressé par une version "fluide" d'un signal périodique (comme votre exemple), alors une FFT est la bonne solution. Prenez la transformée de Fourier et soustrayez les fréquences à faible contribution:
Même si votre signal n'est pas complètement périodique, cela fera un excellent travail pour soustraire le bruit blanc. Il existe de nombreux types de filtres à utiliser (passe-haut, passe-bas, etc ...), celui qui convient dépend de ce que vous recherchez.
la source
Ajuster une moyenne mobile à vos données atténuerait le bruit, voyez ceci cette réponse pour savoir comment procéder.
Si vous souhaitez utiliser LOWESS pour ajuster vos données (c'est similaire à une moyenne mobile mais plus sophistiqué), vous pouvez le faire en utilisant la bibliothèque de modèles de statistiques :
Enfin, si vous connaissez la forme fonctionnelle de votre signal, vous pouvez adapter une courbe à vos données, ce qui serait probablement la meilleure chose à faire.
la source
loess
mis en œuvre.Une autre option consiste à utiliser KernelReg dans les modèles de statistiques :
la source
Regarde ça! Il existe une définition claire du lissage d'un signal 1D.
http://scipy-cookbook.readthedocs.io/items/SignalSmooth.html
Raccourci:
la source
Si vous tracez un graphique de séries chronologiques et si vous avez utilisé mtplotlib pour dessiner des graphiques, utilisez la méthode médiane pour lisser le graphique
où
timeseries
est passé votre ensemble de données que vous pouvez modifierwindowsize
pour plus de lissage.la source