NumPy का उपयोग करके मूविंग एवरेज की गणना कैसे करें?


109

ऐसा प्रतीत होता है कि ऐसा कोई कार्य नहीं है जो बस औसतन / घिनौने पर चलती औसत की गणना करता है, जिससे जटिल समाधान निकलते हैं

मेरा सवाल दो गुना है:

  • सुचारू रूप से चलती औसत को (सही तरीके से) लागू करने का सबसे आसान तरीका क्या है?
  • चूंकि यह गैर-तुच्छ और त्रुटि प्रवण लगता है, तो क्या इस मामले में बैटरी शामिल नहीं होने का एक अच्छा कारण है ?

19
कन्वर्सेशन सॉल्यूशन मुझे ऐसा प्रतीत नहीं होता!
विम

4
एक चलती औसत सिर्फ एक कम-पास फिल्टर (यानी 'धुंधला') नहीं है? बहुत यकीन है कि वास्तव में बात के लिए इस तरह की
सजा

@mmgp मुझे लगता है कि मैं गलत होने की उम्मीद कर रहा था, या यह एक अच्छा, स्पष्ट कारण था।
गोनोकॉप्लॉप

3
@ यह एक सजा के रूप में आधा मतलब था। लेकिन सवाल यह है कि केवल मौजूद तथ्य का मतलब है कि यह numpy.convolute से एक चलती औसत बनाने के लिए सीधा नहीं है।
गोनोकॉपॉप

जवाबों:


165

यदि आप एक सीधा गैर-भारित मूविंग एवरेज चाहते हैं, तो आप इसे आसानी से लागू कर सकते हैं np.cumsum, जो कि एफसीआर आधारित तुलना में तेज हो सकता है :

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])

इसलिए मुझे लगता है कि इसका उत्तर है: इसे लागू करना वास्तव में आसान है, और शायद खांसी पहले से ही विशेष कार्यक्षमता के साथ थोड़ा फूला हुआ है।


10
यह कोड गलत है। जैसे कि मूविंग_आवरेज ([1,2,5,10], n = 2) [1., 3.5, 8.5] देता है। यहां तक ​​कि 0 से 19 तक मूविंग एवरेज के लिए उत्तरदाता का टेस्ट केस गलत है, यह दावा करते हुए कि 0, 1, और 2 का औसत 0.5 है। इसे 6 अपवोट कैसे मिले?
जेरेमीकन

2
बग की जाँच के लिए धन्यवाद, अब यह ठीक काम कर रहा है। के रूप में upvotes के लिए, मैं जवाब के पीछे सामान्य विचार का अनुमान लगा रहा हूं कि कार्यान्वयन में एक-एक त्रुटि से अधिक भारी तौला गया था, लेकिन कौन जानता है।
Jaime

2
मुझे समस्या मिल गई है। ret[n:] -= ret[:-n]के रूप में ही नहीं है ret[n:] = ret[n:] - ret[:-n]। मैंने इस उत्तर में कोड तय किया है। संपादित करें: नहींं किसी और ने मुझे सिर्फ इसके लिए हराया।
टिम्मम्म

7
@Timmmm मैंने किया, यह वास्तव में मुद्दा था। इस उत्तर के पीछे का सामान्य सिद्धांत व्यापक रूप से छवि प्रसंस्करण (सारांशित क्षेत्र तालिकाओं जिसे वे इसे कहते हैं) में उपयोग किया जाता है, इसलिए इस मुद्दे को कार्यान्वयन में होना था। समय से पहले अनुकूलन द्वारा थोड़ा सा होने का एक अच्छा उदाहरण, क्योंकि मैं ऑपरेशन को जगह में करते हुए याद करता हूं "क्योंकि यह अधिक कुशल होगा।" उज्जवल पक्ष पर, यह शायद गलत उत्तर का उत्पादन तेजी से करता है ...
Jaime

43
हम्म, ऐसा लगता है कि यह "लागू करना आसान" फ़ंक्शन वास्तव में गलत होने के लिए बहुत आसान है और स्मृति दक्षता पर एक अच्छी चर्चा को बढ़ावा दिया है। मैं खुश हूँ अगर यह जानने का मतलब है कि कुछ सही किया गया है।
रिचर्ड

81

NumPy की एक विशेष डोमेन-विशिष्ट फ़ंक्शन की कमी शायद कोर टीम के अनुशासन और NumPy के प्रमुख निर्देश के प्रति निष्ठा के कारण है: एक एन-आयामी सरणी प्रकार प्रदान करते हैं , साथ ही उन सरणियों को बनाने और अनुक्रमित करने के लिए कार्य करते हैं। कई मूलभूत उद्देश्यों की तरह, यह छोटा नहीं है, और NumPy यह शानदार ढंग से करता है।

(बहुत) बड़ा SciPy एक बहुत बड़ा डोमेन-विशिष्ट पुस्तकालयों में से (बुलाया संग्रह होता सबपैकेज उदाहरण के लिए, संख्यात्मक अनुकूलन (- SciPy द्वारा devs) का अनुकूलन ), संकेत processsing ( संकेत ), और अभिन्न कलन ( एकीकृत )।

मेरा अनुमान है कि आप जिस समारोह में हैं, वह कम से कम एक SciPy उप-पैकेज ( scipy.signal शायद) में है; हालाँकि, मैं पहले SciPy scikits के संग्रह को देखूँगा , प्रासंगिक scikit (s) को पहचानूँगा और वहाँ रुचि के कार्य को देखूँगा।

Scikits स्वतंत्र रूप से विकसित पैकेज हैं जो NumPy / SciPy पर आधारित हैं और एक विशेष तकनीकी अनुशासन के लिए निर्देशित हैं (जैसे, scikits-image , scikits-learn , इत्यादि) इनमें से कई थे (विशेष रूप से, संख्यात्मक अनुकूलन के लिए भयानक OpenOpt ) जिन्हें अत्यधिक माना जाता था, अपेक्षाकृत नए स्किकिट्स रूब्रिक के तहत रहने के लिए चुनने से पहले परिपक्व परियोजनाएं । Scikits 30 ऐसे के बारे में उपरोक्त सूची पसंद मुखपृष्ठ scikits , हालांकि कम से कम उन लोगों में से कई सक्रिय विकास के अंतर्गत नहीं रह रहे हैं।

इस सलाह के बाद आप स्कोर-टाइमरीज़ की ओर बढ़ेंगे ; हालाँकि, वह पैकेज सक्रिय विकास के अंतर्गत नहीं है; वास्तव में, पांडा बन गया है, AFAIK, वास्तविक NumPy आधारित समय श्रृंखला पुस्तकालय।

पंडों के कई कार्य हैं जिनका उपयोग एक चलती औसत की गणना करने के लिए किया जा सकता है ; इनमें से सबसे सरल शायद रोलिंग_मैं है , जिसका आप इस तरह उपयोग करते हैं:

>>> # 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)

अब, सिरीज फंक्शन में पास होने वाले फंक्शन रोलिंग_मैं और एक विंडो साइज़ को कॉल करें , जो मेरे उदाहरण में नीचे 10 दिनों का है

>>> 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

सत्यापित करें कि यह काम किया है - उदाहरण के लिए, मूल श्रृंखला बनाम नई श्रृंखला में 10 - 15 के मूल्यों की तुलना लुढ़का हुआ है

>>> 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

फ़ंक्शन रोलिंग_मैं, लगभग एक दर्जन या तो अन्य फ़ंक्शन के साथ अनौपचारिक रूप से पंडों के दस्तावेज में रूब्रिक मूविंग विंडो फ़ंक्शंस के तहत वर्गीकृत किया जाता है ; पंडों में कार्यों के दूसरे, संबंधित समूह को घातीय कार्यों के रूप में संदर्भित किया जाता है (जैसे,) ईवामा , जो घातीय चलती भारित औसत की गणना करता है) के । यह तथ्य कि यह दूसरा समूह पहले ( चलती खिड़की के कार्यों) में शामिल नहीं है, शायद इसलिए कि तेजी से भारित रूपांतरण एक निश्चित लंबाई वाली खिड़की पर भरोसा नहीं करते हैं


6
पंडों के पास खिड़की के काम करने की एक मजबूत रेखा होती है। लेकिन यह मुझे एक साधारण चलती औसत के लिए बहुत अधिक उपरि की तरह लगता है।
Jaime

6
अच्छी तरह से मुझे संदेह है कि एक चलती औसत की गणना ओपी के लिए या किसी और के बारे में सिर्फ एक अलग आवश्यकता है। यदि आपको एक चलती औसत की गणना करने की आवश्यकता है, तो आपके पास निश्चित रूप से एक समय श्रृंखला है, जिसका अर्थ है कि आपको एक डेटा संरचना की आवश्यकता है जो आपको अपने डेटा को दिनांक-समय इंडेक्स की पुष्टि करने की अनुमति देती है और यह आपके द्वारा निर्दिष्ट 'ओवरहेड' है।
डौग

2
सबसे पहले, इस अत्यंत जानकारीपूर्ण उत्तर को लिखने के लिए समय निकालने के लिए धन्यवाद। वास्तव में, मैं एक चलती औसत के लिए एक उपयोग नहीं देख सकता हूं जिसमें एक समय श्रृंखला शामिल नहीं है। लेकिन इसका मतलब यह नहीं है कि किसी को
डेटाइम

3
बस यह जोड़ना चाहता था कि अगर एक निर्भरता के रूप में पांडा बहुत भारी लगता है, तो चलती औसत फ़ंक्शन को टोंटी लाइब्रेरी में निकाला गया है ।
रोबोकट

4
'रोलिंग_मैं' अब पीएफ पांडा नहीं है, कृपया इसके बजाय 'रोलिंग' का उपयोग करके उत्तर देखें
व्लाद्न

61

इसे प्राप्त करने का एक सरल तरीका है उपयोग करना np.convolve। इसके पीछे विचार यह है कि जिस तरह से असतत आक्षेप की गणना की जाती है और इसका उपयोग एक रोलिंग माध्य वापस करने के लिए किया जाता है । यह np.onesहम चाहते हैं कि स्लाइडिंग खिड़की की लंबाई के बराबर लंबाई के अनुक्रम के साथ कायल करके किया जा सकता है ।

ऐसा करने के लिए हम निम्नलिखित कार्य को परिभाषित कर सकते हैं:

def moving_average(x, w):
    return np.convolve(x, np.ones(w), 'valid') / w

यह कार्य क्रम xऔर लंबाई वाले लोगों के अनुक्रम का दृढ़ संकल्प ले रहा होगा w। ध्यान दें कि चुना गया modeहै validताकि कनवल्शन उत्पाद केवल उन बिंदुओं के लिए दिया जाए जहां अनुक्रम पूरी तरह से ओवरलैप होते हैं।


कुछ उदाहरण:

x = np.array([5,3,8,10,2,1,5,1,0,2])

लंबाई की खिड़की के साथ एक चलती औसत के लिए 2हमारे पास होगा:

moving_average(x, 2)
# array([4. , 5.5, 9. , 6. , 1.5, 3. , 3. , 0.5, 1. ])

और लंबाई की एक खिड़की के लिए 4:

moving_average(x, 4)
# array([6.5 , 5.75, 5.25, 4.5 , 2.25, 1.75, 2.  ])

कैसे convolveकाम करता है ?

जिस तरह से असतत सजा की गणना की जा रही है, उसे गहराई से देखें। निम्न फ़ंक्शन का उद्देश्य np.convolveआउटपुट मानों की गणना करने के तरीके को दोहराना है :

def mov_avg(x, w):
    for m in range(len(x)-(w-1)):
        yield sum(np.ones(w) * x[m:m+w]) / w 

जो, ऊपर दिए गए उदाहरण के लिए भी निकलेगा:

list(mov_avg(x, 2))
# [4.0, 5.5, 9.0, 6.0, 1.5, 3.0, 3.0, 0.5, 1.0]

तो प्रत्येक चरण पर जो किया जा रहा है, वह आंतरिक उत्पाद को लोगों की सरणी और वर्तमान विंडो के बीच लेना है । इस मामले में गुणा कई गुना अधिक है np.ones(w)जिसे हम सीधे sumअनुक्रम में ले जा रहे हैं ।

Bellow एक उदाहरण है कि पहले आउटपुट की गणना कैसे की जाती है ताकि यह थोड़ा साफ हो। मान लें कि हम एक खिड़की चाहते हैं w=4:

[1,1,1,1]
[5,3,8,10,2,1,5,1,0,2]
= (1*5 + 1*3 + 1*8 + 1*10) / w = 6.5

और निम्न आउटपुट की गणना निम्नानुसार की जाएगी:

  [1,1,1,1]
[5,3,8,10,2,1,5,1,0,2]
= (1*3 + 1*8 + 1*10 + 1*2) / w = 5.75

और इसी तरह, सभी ओवरलैप्स के प्रदर्शन के बाद अनुक्रम का एक चलती औसत लौटाना।


यह एक अच्छा विचार है! यह छोटे n के लिए @ Jaime के उत्तर से तेज है, लेकिन बड़े n के लिए धीमा हो जाता है।
फेलिप जेरार्ड

धन्यवाद @ फेलिपगार्ड! हाँ, जैसा कि टिप्पणियों में बताया गया है, जबकि यह दृष्टिकोण शायद कुछ अन्य खस्ता समाधानों की तरह कुशल नहीं हो सकता है, क्योंकि यह भविष्य के आगंतुकों के लिए एक विकल्प के रूप में अपनी सादगी और सुगमता को देखते हुए अच्छा है
yatu

कभी-कभी आउटपुट सरणी का इनपुट के समान आकार होना उपयोगी होता है। इसके लिए के mode='valid'साथ प्रतिस्थापित किया जा सकता है 'same'। बस इस मामले में बढ़त अंक शून्य की ओर बढ़ जाएगा।
इलिया बाराहोवस्की

15

यहाँ कुछ बेंचमार्क के साथ ऐसा करने के कई तरीके दिए गए हैं। अन्य पुस्तकालयों से अनुकूलित कोड का उपयोग करके सबसे अच्छे तरीके संस्करण हैं। bottleneck.move_meanविधि शायद सबसे अच्छा चारों ओर है। scipy.convolveदृष्टिकोण भी बहुत तेजी से, एक्स्टेंसिबल, और वाक्य रचना और धारणा सरल है, लेकिन बहुत बड़ी खिड़की मूल्यों के लिए अच्छी तरह से बड़े पैमाने नहीं है। numpy.cumsumयदि आप एक शुद्ध जरूरत विधि अच्छा है numpyदृष्टिकोण।

नोट: इनमें से कुछ (जैसे bottleneck.move_mean) केंद्रित नहीं हैं, और आपके डेटा को स्थानांतरित कर देंगे।

import numpy as np
import scipy as sci
import scipy.signal as sig
import pandas as pd
import bottleneck as bn
import time as time

def rollavg_direct(a,n): 
    'Direct "for" loop'
    assert n%2==1
    b = a*0.0
    for i in range(len(a)) :
        b[i]=a[max(i-n//2,0):min(i+n//2+1,len(a))].mean()
    return b

def rollavg_comprehension(a,n):
    'List comprehension'
    assert n%2==1
    r,N = int(n/2),len(a)
    return np.array([a[max(i-r,0):min(i+r+1,N)].mean() for i in range(N)]) 

def rollavg_convolve(a,n):
    'scipy.convolve'
    assert n%2==1
    return sci.convolve(a,np.ones(n,dtype='float')/n, 'same')[n//2:-n//2+1]  

def rollavg_convolve_edges(a,n):
    'scipy.convolve, edge handling'
    assert n%2==1
    return sci.convolve(a,np.ones(n,dtype='float'), 'same')/sci.convolve(np.ones(len(a)),np.ones(n), 'same')  

def rollavg_cumsum(a,n):
    'numpy.cumsum'
    assert n%2==1
    cumsum_vec = np.cumsum(np.insert(a, 0, 0)) 
    return (cumsum_vec[n:] - cumsum_vec[:-n]) / n

def rollavg_cumsum_edges(a,n):
    'numpy.cumsum, edge handling'
    assert n%2==1
    N = len(a)
    cumsum_vec = np.cumsum(np.insert(np.pad(a,(n-1,n-1),'constant'), 0, 0)) 
    d = np.hstack((np.arange(n//2+1,n),np.ones(N-n)*n,np.arange(n,n//2,-1)))  
    return (cumsum_vec[n+n//2:-n//2+1] - cumsum_vec[n//2:-n-n//2]) / d

def rollavg_roll(a,n):
    'Numpy array rolling'
    assert n%2==1
    N = len(a)
    rolling_idx = np.mod((N-1)*np.arange(n)[:,None] + np.arange(N), N)
    return a[rolling_idx].mean(axis=0)[n-1:] 

def rollavg_roll_edges(a,n):
    # see /programming/42101082/fast-numpy-roll
    'Numpy array rolling, edge handling'
    assert n%2==1
    a = np.pad(a,(0,n-1-n//2), 'constant')*np.ones(n)[:,None]
    m = a.shape[1]
    idx = np.mod((m-1)*np.arange(n)[:,None] + np.arange(m), m) # Rolling index
    out = a[np.arange(-n//2,n//2)[:,None], idx]
    d = np.hstack((np.arange(1,n),np.ones(m-2*n+1+n//2)*n,np.arange(n,n//2,-1)))
    return (out.sum(axis=0)/d)[n//2:]

def rollavg_pandas(a,n):
    'Pandas rolling average'
    return pd.DataFrame(a).rolling(n, center=True, min_periods=1).mean().to_numpy()

def rollavg_bottlneck(a,n):
    'bottleneck.move_mean'
    return bn.move_mean(a, window=n, min_count=1)

N = 10**6
a = np.random.rand(N)
functions = [rollavg_direct, rollavg_comprehension, rollavg_convolve, 
        rollavg_convolve_edges, rollavg_cumsum, rollavg_cumsum_edges, 
        rollavg_pandas, rollavg_bottlneck, rollavg_roll, rollavg_roll_edges]

print('Small window (n=3)')
%load_ext memory_profiler
for f in functions : 
    print('\n'+f.__doc__+ ' : ')
    %timeit b=f(a,3)

print('\nLarge window (n=1001)')
for f in functions[0:-2] : 
    print('\n'+f.__doc__+ ' : ')
    %timeit b=f(a,1001)

print('\nMemory\n')
print('Small window (n=3)')
N = 10**7
a = np.random.rand(N)
%load_ext memory_profiler
for f in functions[2:] : 
    print('\n'+f.__doc__+ ' : ')
    %memit b=f(a,3)

print('\nLarge window (n=1001)')
for f in functions[2:-2] : 
    print('\n'+f.__doc__+ ' : ')
    %memit b=f(a,1001)

समय, छोटी खिड़की (n = 3)

Direct "for" loop : 

4.14 s ± 23.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

List comprehension : 
3.96 s ± 27.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

scipy.convolve : 
1.07 ms ± 26.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

scipy.convolve, edge handling : 
4.68 ms ± 9.69 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

numpy.cumsum : 
5.31 ms ± 5.11 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

numpy.cumsum, edge handling : 
8.52 ms ± 11.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Pandas rolling average : 
9.85 ms ± 9.63 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

bottleneck.move_mean : 
1.3 ms ± 12.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Numpy array rolling : 
31.3 ms ± 91.9 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Numpy array rolling, edge handling : 
61.1 ms ± 55.9 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

समय, बड़ी खिड़की (n = 1001)

Direct "for" loop : 
4.67 s ± 34 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

List comprehension : 
4.46 s ± 14.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

scipy.convolve : 
103 ms ± 165 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

scipy.convolve, edge handling : 
272 ms ± 1.23 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

numpy.cumsum : 
5.19 ms ± 12.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

numpy.cumsum, edge handling : 
8.7 ms ± 11.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Pandas rolling average : 
9.67 ms ± 199 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

bottleneck.move_mean : 
1.31 ms ± 15.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

मेमोरी, छोटी विंडो (n = 3)

The memory_profiler extension is already loaded. To reload it, use:
  %reload_ext memory_profiler

scipy.convolve : 
peak memory: 362.66 MiB, increment: 73.61 MiB

scipy.convolve, edge handling : 
peak memory: 510.24 MiB, increment: 221.19 MiB

numpy.cumsum : 
peak memory: 441.81 MiB, increment: 152.76 MiB

numpy.cumsum, edge handling : 
peak memory: 518.14 MiB, increment: 228.84 MiB

Pandas rolling average : 
peak memory: 449.34 MiB, increment: 160.02 MiB

bottleneck.move_mean : 
peak memory: 374.17 MiB, increment: 75.54 MiB

Numpy array rolling : 
peak memory: 661.29 MiB, increment: 362.65 MiB

Numpy array rolling, edge handling : 
peak memory: 1111.25 MiB, increment: 812.61 MiB

मेमोरी, बड़ी विंडो (n = 1001)

scipy.convolve : 
peak memory: 370.62 MiB, increment: 71.83 MiB

scipy.convolve, edge handling : 
peak memory: 521.98 MiB, increment: 223.18 MiB

numpy.cumsum : 
peak memory: 451.32 MiB, increment: 152.52 MiB

numpy.cumsum, edge handling : 
peak memory: 527.51 MiB, increment: 228.71 MiB

Pandas rolling average : 
peak memory: 451.25 MiB, increment: 152.50 MiB

bottleneck.move_mean : 
peak memory: 374.64 MiB, increment: 75.85 MiB

11

पंडों के उपयोग का यह उत्तर ऊपर से अनुकूलित है, जैसा rolling_meanकि पंडों का हिस्सा नहीं है

# 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)

अब, बस rollingएक विंडो आकार के साथ डेटाफ्रेम पर फ़ंक्शन को कॉल करें , जो मेरे उदाहरण में नीचे 10 दिनों का है।

d_mva10 = D.rolling(10).mean()

# d_mva is the same size as the original Series
# though obviously the first w values are NaN where w is the window size
d_mva10[:11]

2010-01-01    NaN
2010-01-02    NaN
2010-01-03    NaN
2010-01-04    NaN
2010-01-05    NaN
2010-01-06    NaN
2010-01-07    NaN
2010-01-08    NaN
2010-01-09    NaN
2010-01-10    4.5
2010-01-11    5.5
Freq: D, dtype: float64

5

मुझे लगता है कि टोंटी का उपयोग करके इसे आसानी से हल किया जा सकता है

नीचे मूल नमूना देखें:

import numpy as np
import bottleneck as bn

a = np.random.randint(4, 1000, size=(5, 7))
mm = bn.move_mean(a, window=2, min_count=1)

यह प्रत्येक अक्ष के साथ चाल का अर्थ देता है।

  • "mm" "a" का मूविंग माध्य है।

  • "विंडो" चलती औसत के लिए विचार करने के लिए प्रविष्टियों की अधिकतम संख्या है।

  • "min_count" चलती माध्य के लिए विचार करने के लिए प्रविष्टियों की न्यूनतम संख्या है (जैसे पहले तत्व के लिए या यदि सरणी में नैनो मान है)।

अच्छा हिस्सा टोंटी नेक नेन मूल्यों से निपटने में मदद करता है और यह बहुत कुशल भी है।


2

यदि आप किनारे की स्थितियों को सावधानीपूर्वक संभालना चाहते हैं ( केवल किनारों पर उपलब्ध तत्वों से गणना का मतलब है ), तो निम्न फ़ंक्शन ट्रिक करेगा।

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])

1
for i in range(len(Data)):
    Data[i, 1] = Data[i-lookback:i, 0].sum() / lookback

कोड के इस टुकड़े की कोशिश करो। मुझे लगता है कि यह सरल है और काम करता है। लुकबैक चलती औसत की विंडो है।

में Data[i-lookback:i, 0].sum()मैं डाल दिया है 0डाटासेट का पहला स्तंभ का उल्लेख करने, लेकिन आप के मामले में आप की तरह किसी भी स्तंभ रख सकते हैं आप अधिक से अधिक एक स्तंभ है।


0

मैं वास्तव में स्वीकृत उत्तर की तुलना में थोड़ा अलग व्यवहार चाहता था। मैं एक sklearnपाइप लाइन के लिए एक चलती औसत सुविधा चिमटा का निर्माण कर रहा था , इसलिए मुझे आवश्यकता थी कि चलती औसत के आउटपुट में इनपुट के समान आयाम हो। मैं चाहता हूं कि मूविंग एवरेज के लिए यह मान लिया जाए कि सीरीज़ स्थिर रहे, यानी [1,2,3,4,5]विंडो 2 के साथ मूविंग एवरेज दे [1.5,2.5,3.5,4.5,5.0]

कॉलम वैक्टर (मेरे उपयोग के मामले) के लिए हम प्राप्त करते हैं

def moving_average_col(X, n):
  z2 = np.cumsum(np.pad(X, ((n,0),(0,0)), 'constant', constant_values=0), axis=0)
  z1 = np.cumsum(np.pad(X, ((0,n),(0,0)), 'constant', constant_values=X[-1]), axis=0)
  return (z1-z2)[(n-1):-1]/n

और सरण के लिए

def moving_average_array(X, n):
  z2 = np.cumsum(np.pad(X, (n,0), 'constant', constant_values=0))
  z1 = np.cumsum(np.pad(X, (0,n), 'constant', constant_values=X[-1]))
  return (z1-z2)[(n-1):-1]/n

बेशक, किसी को गद्दी के लिए निरंतर मूल्यों को मानने की ज़रूरत नहीं है, लेकिन ऐसा करना ज्यादातर मामलों में पर्याप्त होना चाहिए।


0

तालिब में एक सरल मूविंग एवरेज टूल होता है, साथ ही साथ अन्य समान एवरेज टूल (यानी घातीय मूविंग एवरेज)। नीचे कुछ अन्य समाधानों की विधि की तुलना की गई है।


%timeit pd.Series(np.arange(100000)).rolling(3).mean()
2.53 ms ± 40.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit talib.SMA(real = np.arange(100000.), timeperiod = 3)
348 µs ± 3.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit moving_average(np.arange(100000))
638 µs ± 45.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

एक चेतावनी यह है कि वास्तविक में तत्व होने चाहिए dtype = float। अन्यथा निम्न त्रुटि उठाई जाती है

अपवाद: वास्तविक दोहरा नहीं है


0

यहां सुंबा (प्रकारों को ध्यान में रखते हुए) का तेजी से कार्यान्वयन किया गया है। ध्यान दें कि इसमें ऐसे नाम शामिल हैं जहां स्थानांतरित कर दिया गया है।

import numpy as np
import numba as nb

@nb.jit(nb.float64[:](nb.float64[:],nb.int64),
        fastmath=True,nopython=True)
def moving_average( array, window ):    
    ret = np.cumsum(array)
    ret[window:] = ret[window:] - ret[:-window]
    ma = ret[window - 1:] / window
    n = np.empty(window-1); n.fill(np.nan)
    return np.concatenate((n.ravel(), ma.ravel())) 

यह शुरुआत में ही रिटर्न देता है।
एडम एरिकसन

0

सामान्य गति

  • i पर सरणी को उल्टा करें, और केवल i से n तक के बीच का अर्थ निकालें।

  • मक्खी पर मिनी arrays उत्पन्न करने के लिए सूची समझ का उपयोग करें।

x = np.random.randint(10, size=20)

def moving_average(arr, n):
    return [ (arr[:i+1][::-1][:n]).mean() for i, ele in enumerate(arr) ]
n = 5

moving_average(x, n)

0

मैं या तो स्वीकृत उत्तर के समाधान का उपयोग करता हूं , आउटपुट के लिए समान लंबाई के लिए थोड़ा संशोधित किया गया है, या pandasकिसी अन्य उत्तर की टिप्पणी में वर्णित संस्करण के रूप में। मैं भविष्य के संदर्भ के लिए एक प्रतिलिपि प्रस्तुत करने योग्य उदाहरण के साथ दोनों को यहाँ संक्षेप में प्रस्तुत करता हूं:

import numpy as np
import pandas as pd

def moving_average(a, n):
    ret = np.cumsum(a, dtype=float)
    ret[n:] = ret[n:] - ret[:-n]
    return ret / n

def moving_average_centered(a, n):
    return pd.Series(a).rolling(window=n, center=True).mean().to_numpy()

A = [0, 0, 1, 2, 4, 5, 4]
print(moving_average(A, 3))    
# [0.         0.         0.33333333 1.         2.33333333 3.66666667 4.33333333]
print(moving_average_centered(A, 3))
# [nan        0.33333333 1.         2.33333333 3.66666667 4.33333333 nan       ]

0

नीचे दिए गए घोल का तुलनात्मक रूप से अंको का कम्प्रेशम प्रयोग करने से, यह लगभग आधा समय लेता है । ऐसा इसलिए है क्योंकि कम्ब्सम करने के लिए पूरे अरेंजमेंट से गुजरने की जरूरत नहीं होती है और फिर सभी सबट्रेक्शन करते हैं। इसके अलावा, अगर सरणी विशाल है और संख्या बहुत बड़ी है ( संभावित अतिप्रवाह ) , तो कम्सम " खतरनाक " हो सकता है । बेशक, यहां भी खतरा मौजूद है, लेकिन कम से कम केवल आवश्यक संख्याओं को एक साथ समेटा गया है।

def moving_average(array_numbers, n):
    if n > len(array_numbers):
      return []
    temp_sum = sum(array_numbers[:n])
    averages = [temp_sum / float(n)]
    for first_index, item in enumerate(array_numbers[n:]):
        temp_sum += item - array_numbers[first_index]
        averages.append(temp_sum / float(n))
    return averages
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.