Comment calculer la moyenne mobile en utilisant NumPy?
il ne semble pas y avoir de fonction qui calcule simplement la moyenne mobile sur numpy/scipy, conduisant à solutions alambiquées .
ma question Est double:
- Quelle est la façon la plus facile de (correctement) implémenter une moyenne mobile avec numpy?
- étant donné que cela semble non négligeable et sujet aux erreurs, y a-t-il une bonne raison de ne pas inclure les batteries dans ce cas?
3 réponses
si vous voulez simplement une moyenne mobile non pondérée simple, vous pouvez facilement l'implémenter avec np.cumsum
, qui peut être est plus rapide que les méthodes basées sur FFT:
MODIFIER correction d'un tout-en-un mauvais indexation repéré par Bean dans le code. EDIT
def moving_average(a, n=3) :
ret = np.cumsum(a, dtype=float)
ret[n:] = ret[n:] - ret[:-n]
return ret[n - 1:] / n
>>> a = np.arange(20)
>>> moving_average(a)
array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.,
12., 13., 14., 15., 16., 17., 18.])
>>> moving_average(a, n=4)
array([ 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5,
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5])
donc je suppose que la réponse est: il est vraiment facile à mettre en œuvre, et peut-être numpy est déjà un peu gonflé avec des fonctionnalités spécialisées.
L'absence de num Py d'une fonction spécifique au domaine est peut-être due à la discipline de L'équipe de base et à la fidélité à la directive première de num Py: fournissent un type de tableau n-dimensionnel , ainsi que des fonctions pour la création et l'indexation de ces tableaux. Comme beaucoup d'objectifs fondamentaux, celui-ci n'est pas petit, et NumPy le fait brillamment.
le (beaucoup) plus grand SciPy contient un plus grand collection de bibliothèques spécifiques aux domaines (appelées sous-paquets par SciPy devs)--par exemple, optimisation numérique ( optimiser ), traitement de signal ( signal ), et calcul intégral ( intégrer ).
ma conjecture est que la fonction que vous êtes après est dans au moins un des sous-paquets SciPy ( scipy.signal peut-être); cependant, je examinerait d'abord dans la collection de SciPy scikits , identifierait le(s) scikit (s) pertinent (s) et chercherait la fonction d'intérêt là.
Scikits sont des paquets développés indépendamment basés sur NumPy/SciPy et orientés vers une discipline technique particulière (par exemple, scikits-image , scikits-learn , etc.) Plusieurs d'entre eux étaient (en particulier, le OpenOpt pour l'optimisation numérique) ont été très considérés, projets mûrs bien avant de choisir de résider sous la relativement nouvelle scikits rubrique. Le Scikits page d'accueil aimé à des listes ci-dessus environ 30 scikits , bien qu'au moins plusieurs de ceux-ci ne sont plus en développement actif.
suivre ce conseil vous mènerait à scikits-timeseries ; toutefois, ce paquet n'est plus en cours de développement; , Pandas est devenu, AFAIK, le de facto NumPy - basé la bibliothèque de séries chronologiques.
Pandas a plusieurs fonctions qui peuvent être utilisées pour calculer une moyenne mobile ; le plus simple d'entre eux est probablement rolling_mean , que vous utilisez comme ainsi:
>>> # the recommended syntax to import pandas
>>> import pandas as PD
>>> import numpy as NP
>>> # prepare some fake data:
>>> # the date-time indices:
>>> t = PD.date_range('1/1/2010', '12/31/2012', freq='D')
>>> # the data:
>>> x = NP.arange(0, t.shape[0])
>>> # combine the data & index into a Pandas 'Series' object
>>> D = PD.Series(x, t)
maintenant, il suffit d'appeler la fonction rolling_mean passant dans l'objet de série et un taille de fenêtre , qui dans mon exemple ci-dessous est 10 jours .
>>> d_mva = PD.rolling_mean(D, 10)
>>> # d_mva is the same size as the original Series
>>> d_mva.shape
(1096,)
>>> # though obviously the first w values are NaN where w is the window size
>>> d_mva[:3]
2010-01-01 NaN
2010-01-02 NaN
2010-01-03 NaN
vérifier qu'il a fonctionné-par exemple, comparer les valeurs 10-15 dans la série originale par rapport à la nouvelle série lissée avec la moyenne mobile
>>> D[10:15]
2010-01-11 2.041076
2010-01-12 2.041076
2010-01-13 2.720585
2010-01-14 2.720585
2010-01-15 3.656987
Freq: D
>>> d_mva[10:20]
2010-01-11 3.131125
2010-01-12 3.035232
2010-01-13 2.923144
2010-01-14 2.811055
2010-01-15 2.785824
Freq: D
la fonction rolling_mean, avec environ une douzaine d'autres fonctions sont informellement groupés dans la documentation Pandas sous la rubrique fenêtre mobile fonctions; un second, groupe apparenté de fonctions dans Pandas est appelé fonctions à pondération exponentielle (par exemple, ewma , qui calcule la moyenne pondérée à déplacement exponentiel). Le fait que ce deuxième groupe n'est pas inclus dans le premier ( fenêtre mobile fonctions) est peut-être parce que les transformations à pondération exponentielle ne dépendent pas d'une fenêtre de longueur fixe
dans le cas où vous voulez prendre soin des conditions de bord soigneusement ( calculer signifie seulement à partir des éléments disponibles aux bords ), la fonction suivante fera l'affaire.
import numpy as np
def running_mean(x, N):
out = np.zeros_like(x, dtype=np.float64)
dim_len = x.shape[0]
for i in range(dim_len):
if N%2 == 0:
a, b = i - (N-1)//2, i + (N-1)//2 + 2
else:
a, b = i - (N-1)//2, i + (N-1)//2 + 1
#cap indices to min and max indices
a = max(0, a)
b = min(dim_len, b)
out[i] = np.mean(x[a:b])
return out
>>> running_mean(np.array([1,2,3,4]), 2)
array([1.5, 2.5, 3.5, 4. ])
>>> running_mean(np.array([1,2,3,4]), 3)
array([1.5, 2. , 3. , 3.5])