উত্তর:
একটি সংক্ষিপ্ত, দ্রুত সমাধানের জন্য যা পুরোপুরি এক লুপে করে, নির্ভরতা ছাড়াই, নীচের কোডটি দুর্দান্ত কাজ করে।
mylist = [1, 2, 3, 4, 5, 6, 7]
N = 3
cumsum, moving_aves = [0], []
for i, x in enumerate(mylist, 1):
cumsum.append(cumsum[i-1] + x)
if i>=N:
moving_ave = (cumsum[i] - cumsum[i-N])/N
#can do stuff with moving_ave here
moving_aves.append(moving_ave)
ইউপিডি: আরও দক্ষ সমাধানের প্রস্তাব দেওয়া হয়েছে আলেও এবং জাসারিমের দ্বারা ।
আপনি এটির np.convolve
জন্য ব্যবহার করতে পারেন :
np.convolve(x, np.ones((N,))/N, mode='valid')
চলমান গড় গাণিতিক অপারেশন একটি ক্ষেত্রে দেখা যায় সংবর্তন । চলমান গড়ের জন্য, আপনি ইনপুট বরাবর একটি উইন্ডো স্লাইড করুন এবং উইন্ডোর সামগ্রীর গড় গণনা করুন। বিচ্ছিন্ন 1 ডি সংকেতের জন্য, সমঝোতা একই জিনিস, আপনি একটি স্বেচ্ছাসৈনিক রৈখিক সংমিশ্রণ গণনা করার অর্থ বাদে অর্থাত্ প্রতিটি উপাদানকে একটি সমান গুণফল দ্বারা গুণিত করুন এবং ফলাফলগুলি যুক্ত করুন। এই সহগগুলি, উইন্ডোতে প্রতিটি পদের জন্য একটি, কখনও কখনও কনভ্যুশন কার্নেল নামে পরিচিত । এখন, এন মানগুলির গাণিতিক গড়টি হ'ল (x_1 + x_2 + ... + x_N) / N
তাই সংশ্লিষ্ট কার্নেলটি হ'ল (1/N, 1/N, ..., 1/N)
এবং এটি ব্যবহার করে আমরা ঠিক পাইnp.ones((N,))/N
।
কীভাবে প্রান্তগুলি পরিচালনা করতে হবে তার mode
যুক্তি np.convolve
। আমি valid
এখানে মোডটি বেছে নিয়েছি কারণ আমি মনে করি বেশিরভাগ লোকেরা চলমান গড়ের কাজটি কীভাবে প্রত্যাশা করে তবে আপনার অন্যান্য অগ্রাধিকার থাকতে পারে। মোডের মধ্যে পার্থক্য তুলে ধরে এখানে একটি প্লট দেওয়া হয়েছে:
import numpy as np
import matplotlib.pyplot as plt
modes = ['full', 'same', 'valid']
for m in modes:
plt.plot(np.convolve(np.ones((200,)), np.ones((50,))/50, mode=m));
plt.axis([-10, 251, -.1, 1.1]);
plt.legend(modes, loc='lower center');
plt.show()
numpy.cumsum
ক্ষেত্রে আরও জটিলতা রয়েছে।
কনভলিউশন সোজা পদ্ধতির চেয়ে অনেক ভাল, তবে (আমার ধারণা) এটি এফএফটি ব্যবহার করে এবং এইভাবে বেশ ধীর হয়। তবে বিশেষ করে চলমান গণনার জন্য নিম্নলিখিত পদ্ধতির সূক্ষ্ম কাজ করে
def running_mean(x, N):
cumsum = numpy.cumsum(numpy.insert(x, 0, 0))
return (cumsum[N:] - cumsum[:-N]) / float(N)
কোডটি যাচাই করতে হবে
In[3]: x = numpy.random.random(100000)
In[4]: N = 1000
In[5]: %timeit result1 = numpy.convolve(x, numpy.ones((N,))/N, mode='valid')
10 loops, best of 3: 41.4 ms per loop
In[6]: %timeit result2 = running_mean(x, N)
1000 loops, best of 3: 1.04 ms per loop
মনে রাখবেন যে, numpy.allclose(result1, result2)
হয়True
, দুটি পদ্ধতি সমতুল্য। বৃহত্তর এন, সময় বৃহত্তর পার্থক্য।
# demonstrate loss of precision with only 100,000 points
np.random.seed(42)
x = np.random.randn(100000)+1e6
y1 = running_mean_convolve(x, 10)
y2 = running_mean_cumsum(x, 10)
assert np.allclose(y1, y2, rtol=1e-12, atol=0)
np.longdouble
তবে আপনার ভাসমান পয়েন্ট ত্রুটিটি এখনও তুলনামূলকভাবে বড় সংখ্যক পয়েন্টের জন্য গুরুত্বপূর্ণ হবে (প্রায়> 1e5 তবে আপনার ডেটার উপর নির্ভর করে)numpy.convolve
ও (এমএন); এর দস্তাবেজগুলিscipy.signal.fftconvolve
এফএফটি ব্যবহার করে উল্লেখ করে ।
running_mean([1,2,3], 2)
দেয় array([1, 2])
। x
দ্বারা প্রতিস্থাপন [float(value) for value in x]
কৌশলটি করে।
x
ভাসা থাকে। উদাহরণ: running_mean(np.arange(int(1e7))[::-1] + 0.2, 1)[-1] - 0.2
আয় 0.003125
যখন এক আশা 0.0
। আরও তথ্য: en.wikedia.org/wiki/Loss_of_significance
আপডেট: নীচের উদাহরণে পুরানো pandas.rolling_mean
ফাংশনটি দেখানো হয়েছে যা পান্ডার সাম্প্রতিক সংস্করণগুলিতে সরানো হয়েছে। নীচে ফাংশন কলটির একটি আধুনিক সমমান হবে
In [8]: pd.Series(x).rolling(window=N).mean().iloc[N-1:].values
Out[8]:
array([ 0.49815397, 0.49844183, 0.49840518, ..., 0.49488191,
0.49456679, 0.49427121])
পান্ডাস নুমপি বা সায়্পাইয়ের চেয়ে এর জন্য আরও উপযুক্ত। এর ফাংশন রোলিং_মিনটি সুবিধামত কাজ করে। ইনপুটটি অ্যারে হলে এটি একটি নম্পপি অ্যারেও ফেরত দেয়।
যে rolling_mean
কোনও কাস্টম খাঁটি পাইথন প্রয়োগের সাথে পারফরম্যান্সে পরাজিত করা কঠিন । প্রস্তাবিত দুটি সমাধানের বিপরীতে এখানে উদাহরণের পারফরম্যান্স:
In [1]: import numpy as np
In [2]: import pandas as pd
In [3]: def running_mean(x, N):
...: cumsum = np.cumsum(np.insert(x, 0, 0))
...: return (cumsum[N:] - cumsum[:-N]) / N
...:
In [4]: x = np.random.random(100000)
In [5]: N = 1000
In [6]: %timeit np.convolve(x, np.ones((N,))/N, mode='valid')
10 loops, best of 3: 172 ms per loop
In [7]: %timeit running_mean(x, N)
100 loops, best of 3: 6.72 ms per loop
In [8]: %timeit pd.rolling_mean(x, N)[N-1:]
100 loops, best of 3: 4.74 ms per loop
In [9]: np.allclose(pd.rolling_mean(x, N)[N-1:], running_mean(x, N))
Out[9]: True
প্রান্তের মানগুলি কীভাবে মোকাবেলা করা যায় সে সম্পর্কেও দুর্দান্ত বিকল্প রয়েছে।
df.rolling(windowsize).mean()
এখন পরিবর্তে কাজ করে (খুব দ্রুত আমি যুক্ত করতে পারি)। 6,000 সারি সিরিজের জন্য 1000 লুপগুলি%timeit test1.rolling(20).mean()
ফিরেছে , 3
df.rolling()
যথেষ্ট ভাল কাজ করে, সমস্যাটি হ'ল এমনকি এই ফর্মটি ভবিষ্যতেও নাদরাদের সমর্থন করবে না। এটি ব্যবহারের জন্য আমাদের প্রথমে একটি পান্ডাস ডেটাফ্রেমে আমাদের ডেটা লোড করতে হবে। আমি এই ফাংশনটি হয় numpy
বা এর সাথে যুক্ত দেখতে চাই scipy.signal
।
%timeit bottleneck.move_mean(x, N)
আমার পিসিতে চামসাম এবং পান্ডাস পদ্ধতির চেয়ে 3 থেকে 15 গুণ বেশি গতিযুক্ত। রেপোর README এ তাদের মানদণ্ডটি একবার দেখুন ।
আপনি এটির সাথে একটি চলমান গড় গণনা করতে পারেন:
import numpy as np
def runningMean(x, N):
y = np.zeros((len(x),))
for ctr in range(len(x)):
y[ctr] = np.sum(x[ctr:(ctr+N)])
return y/N
তবে এটা ধীর।
সৌভাগ্যবসত, numpy একটি অন্তর্ভুক্ত বিভিন্ন বস্তু একত্র পাকান ফাংশন যা আমরা গতি বাড়াতে জিনিস ব্যবহার করতে পারেন। চলমান গড় হ'ল লম্বা x
ভেক্টরের সাথে কনভলভ করার সমতুল্য N
, সমস্ত সদস্যের সমান 1/N
। কনভলভের অদ্ভুত বাস্তবায়নের শুরুতে ক্ষণস্থায়ী অন্তর্ভুক্ত রয়েছে, সুতরাং আপনাকে প্রথম এন -1 পয়েন্টগুলি সরিয়ে ফেলতে হবে:
def runningMeanFast(x, N):
return np.convolve(x, np.ones((N,))/N)[(N-1):]
আমার মেশিনে, ইনপুট ভেক্টরের দৈর্ঘ্য এবং গড় উইন্ডোটির আকারের উপর নির্ভর করে দ্রুত সংস্করণটি 20-30 গুণ দ্রুত হয়।
নোট করুন যে রূপান্তরটি এমন একটি 'same'
মোড অন্তর্ভুক্ত করে যা মনে হয় এটির শুরু ক্ষণস্থায়ী সমস্যার সমাধান করা উচিত তবে এটি এটি শুরু এবং শেষের মধ্যে বিভক্ত হয়।
mode='valid'
করা convolve
যাতে কোনও পোস্ট-প্রসেসিংয়ের প্রয়োজন হয় না।
mode='valid'
উভয় প্রান্ত থেকে ক্ষণস্থায়ী সরান, তাই না? যদি len(x)=10
এবং N=4
, একটি চলমান গড়ের জন্য আমি 10 ফলাফল চাইব তবে ফলাফল valid
7.
modes = ('full', 'same', 'valid'); [plot(convolve(ones((200,)), ones((50,))/50, mode=m)) for m in modes]; axis([-10, 251, -.1, 1.1]); legend(modes, loc='lower center')
(পাইপলট এবং নিমপি আমদানি করা সহ)।
runningMean
আপনি যখন অ্যারের x[ctr:(ctr+N)]
ডান পাশের জন্য অ্যারের বাইরে চলে যান তখন আমার শূন্যের সাথে গড়ের পার্শ্বপ্রতিক্রিয়া থাকতে হবে?
runningMeanFast
এছাড়াও এই সীমান্ত প্রভাব সমস্যা আছে।
বা পাইথনের জন্য মডিউল যা গণনা করে
ট্রেডওয়েভ.নেট আমার পরীক্ষায় টিএ-লাইব সর্বদা জিততে থাকে:
import talib as ta
import numpy as np
import pandas as pd
import scipy
from scipy import signal
import time as t
PAIR = info.primary_pair
PERIOD = 30
def initialize():
storage.reset()
storage.elapsed = storage.get('elapsed', [0,0,0,0,0,0])
def cumsum_sma(array, period):
ret = np.cumsum(array, dtype=float)
ret[period:] = ret[period:] - ret[:-period]
return ret[period - 1:] / period
def pandas_sma(array, period):
return pd.rolling_mean(array, period)
def api_sma(array, period):
# this method is native to Tradewave and does NOT return an array
return (data[PAIR].ma(PERIOD))
def talib_sma(array, period):
return ta.MA(array, period)
def convolve_sma(array, period):
return np.convolve(array, np.ones((period,))/period, mode='valid')
def fftconvolve_sma(array, period):
return scipy.signal.fftconvolve(
array, np.ones((period,))/period, mode='valid')
def tick():
close = data[PAIR].warmup_period('close')
t1 = t.time()
sma_api = api_sma(close, PERIOD)
t2 = t.time()
sma_cumsum = cumsum_sma(close, PERIOD)
t3 = t.time()
sma_pandas = pandas_sma(close, PERIOD)
t4 = t.time()
sma_talib = talib_sma(close, PERIOD)
t5 = t.time()
sma_convolve = convolve_sma(close, PERIOD)
t6 = t.time()
sma_fftconvolve = fftconvolve_sma(close, PERIOD)
t7 = t.time()
storage.elapsed[-1] = storage.elapsed[-1] + t2-t1
storage.elapsed[-2] = storage.elapsed[-2] + t3-t2
storage.elapsed[-3] = storage.elapsed[-3] + t4-t3
storage.elapsed[-4] = storage.elapsed[-4] + t5-t4
storage.elapsed[-5] = storage.elapsed[-5] + t6-t5
storage.elapsed[-6] = storage.elapsed[-6] + t7-t6
plot('sma_api', sma_api)
plot('sma_cumsum', sma_cumsum[-5])
plot('sma_pandas', sma_pandas[-10])
plot('sma_talib', sma_talib[-15])
plot('sma_convolve', sma_convolve[-20])
plot('sma_fftconvolve', sma_fftconvolve[-25])
def stop():
log('ticks....: %s' % info.max_ticks)
log('api......: %.5f' % storage.elapsed[-1])
log('cumsum...: %.5f' % storage.elapsed[-2])
log('pandas...: %.5f' % storage.elapsed[-3])
log('talib....: %.5f' % storage.elapsed[-4])
log('convolve.: %.5f' % storage.elapsed[-5])
log('fft......: %.5f' % storage.elapsed[-6])
ফলাফল:
[2015-01-31 23:00:00] ticks....: 744
[2015-01-31 23:00:00] api......: 0.16445
[2015-01-31 23:00:00] cumsum...: 0.03189
[2015-01-31 23:00:00] pandas...: 0.03677
[2015-01-31 23:00:00] talib....: 0.00700 # <<< Winner!
[2015-01-31 23:00:00] convolve.: 0.04871
[2015-01-31 23:00:00] fft......: 0.22306
NameError: name 'info' is not defined
। আমি এই ত্রুটি পাচ্ছি, স্যার।
ব্যবহারের জন্য প্রস্তুত সমাধানের জন্য https://scipy-cookbook.readthedocs.io/items/SignalSmooth.html দেখুন । এটি flat
উইন্ডো প্রকারের সাথে চলমান গড় সরবরাহ করে । দ্রষ্টব্য যে এটি নিজের থেকে প্রস্তুত হওয়া সহজ-পদ্ধতির চেয়ে কিছুটা পরিশীলিত, কারণ এটি শুরুতে এবং ডেটাটির প্রতিবিম্বের মাধ্যমে সমস্যাগুলি পরিচালনা করার চেষ্টা করে (যা আপনার ক্ষেত্রে কার্যকর হতে পারে বা নাও পারে)। ..)।
শুরু করার জন্য, আপনি চেষ্টা করতে পারেন:
a = np.random.random(100)
plt.plot(a)
b = smooth(a, window='flat')
plt.plot(b)
numpy.convolve
, কেবল ক্রম পরিবর্তন করতে পার্থক্য।
w
উইন্ডোর আকার এবং s
ডেটা?
আপনি scipy.ndimage.filters.uniform_filter1d ব্যবহার করতে পারেন :
import numpy as np
from scipy.ndimage.filters import uniform_filter1d
N = 1000
x = np.random.random(100000)
y = uniform_filter1d(x, size=N)
uniform_filter1d
:
'reflect'
ডিফল্ট সেখানে পরিচালনা করতে একাধিক উপায়ে অনুমতি দেয় তবে আমার ক্ষেত্রে আমি বরং চেয়েছিলাম'nearest'
এটি বরং দ্রুত ( উপরে উল্লিখিত চিউসাম পদ্ধতির চেয়ে প্রায় 50 গুণ দ্রুত np.convolve
এবং 2-5 গুণ দ্রুত ):
%timeit y1 = np.convolve(x, np.ones((N,))/N, mode='same')
100 loops, best of 3: 9.28 ms per loop
%timeit y2 = uniform_filter1d(x, size=N)
10000 loops, best of 3: 191 µs per loop
এখানে 3 টি ফাংশন যা আপনাকে বিভিন্ন বাস্তবায়নের ত্রুটি / গতির তুলনা করতে দেয়:
from __future__ import division
import numpy as np
import scipy.ndimage.filters as ndif
def running_mean_convolve(x, N):
return np.convolve(x, np.ones(N) / float(N), 'valid')
def running_mean_cumsum(x, N):
cumsum = np.cumsum(np.insert(x, 0, 0))
return (cumsum[N:] - cumsum[:-N]) / float(N)
def running_mean_uniform_filter1d(x, N):
return ndif.uniform_filter1d(x, N, mode='constant', origin=-(N//2))[:-(N-1)]
uniform_filter1d
, np.convolve
, একটি আয়তক্ষেত্র ও np.cumsum
অনুসরণ np.subtract
। আমার ফলাফল: (১.) কনভলভ করা সবচেয়ে ধীর। (২) চামসাম / বিয়োগ প্রায় 20-30x দ্রুত। (3.) ইউনিফর্ম_ফিল্টার 1 ডি চামসাম / বিয়োগফলের চেয়ে প্রায় 2-3x গতিযুক্ত। বিজয়ী অবশ্যই ইউনিফর্ম_ফিল্টার 1 ডি।
uniform_filter1d
করা সমাধানের চেয়ে দ্রুতcumsum
(প্রায় 2-5x দ্বারা)। এবং সমাধানের uniform_filter1d
মতো বিশাল ভাসমান পয়েন্ট ত্রুটিcumsum
পায় না।
আমি জানি এটি একটি পুরানো প্রশ্ন, তবে এখানে একটি সমাধান রয়েছে যা কোনও অতিরিক্ত ডেটা স্ট্রাকচার বা লাইব্রেরি ব্যবহার করে না। এটি ইনপুট তালিকার উপাদানগুলির সংখ্যার মধ্যে লিনিয়ার এবং আমি এটিকে আরও দক্ষ করে তোলার জন্য অন্য কোনও উপায়ের কথা ভাবতে পারি না (আসলে যদি কেউ ফলাফল বরাদ্দ দেওয়ার আরও ভাল উপায় সম্পর্কে জানে তবে দয়া করে আমাকে জানান)।
দ্রষ্টব্য: তালিকার পরিবর্তে একটি অদ্ভুত অ্যারে ব্যবহার করা এটি আরও দ্রুত হবে তবে আমি সমস্ত নির্ভরতা দূর করতে চেয়েছিলাম। মাল্টি-থ্রেড এক্সিকিউশন দ্বারা কর্মক্ষমতা উন্নত করাও সম্ভব হবে
ফাংশন ধরে নেয় যে ইনপুট তালিকাটি একটি মাত্রিক, তাই সাবধানতা অবলম্বন করুন।
### Running mean/Moving average
def running_mean(l, N):
sum = 0
result = list( 0 for x in l)
for i in range( 0, N ):
sum = sum + l[i]
result[i] = sum / (i+1)
for i in range( N, len(l) ):
sum = sum - l[i-N] + l[i]
result[i] = sum / N
return result
উদাহরণ
ধরুন আমাদের একটি তালিকা আছে data = [ 1, 2, 3, 4, 5, 6 ]
রয়েছে যার উপরে আমরা 3 পিরিয়ডের সাথে রোলিং গড় গণনা করতে চাই এবং আপনি একটি আউটপুট তালিকাও চান যা ইনপুটটির একই আকার (এটি বেশিরভাগ ক্ষেত্রে হয়)।
প্রথম উপাদানটির সূচক 0 রয়েছে, সুতরাং ঘূর্ণায়মান গড় সূচক -2, -1 এবং 0 এর উপাদানগুলির সাথে গণনা করা উচিত স্পষ্টতই আমাদের কাছে ডেটা [-2] এবং ডেটা নেই [-1] (আপনি যদি বিশেষ ব্যবহার করতে না চান) সীমানা শর্তাদি), সুতরাং আমরা ধরে নিই যে সেই উপাদানগুলি 0 হয় This তালিকার শূন্য-প্যাডিংয়ের সমতুল্য, আমরা আসলে এটি প্যাড না করে কেবল প্যাডিংয়ের প্রয়োজনীয় সূচকগুলি (0 থেকে এন -1 পর্যন্ত) ট্র্যাক করে রাখি।
সুতরাং, প্রথম এন উপাদানগুলির জন্য আমরা কেবল একটি সঞ্চয়ের মধ্যে উপাদানগুলি যোগ করতে থাকি।
result[0] = (0 + 0 + 1) / 3 = 0.333 == (sum + 1) / 3
result[1] = (0 + 1 + 2) / 3 = 1 == (sum + 2) / 3
result[2] = (1 + 2 + 3) / 3 = 2 == (sum + 3) / 3
উপাদানগুলি থেকে এন + 1 ফরোয়ার্ডে সহজ সংগ্রহ কাজ করে না। আমরা আশা করি result[3] = (2 + 3 + 4)/3 = 3
তবে এটির চেয়ে আলাদা (sum + 4)/3 = 3.333
।
সঠিক মান গণনা করার উপায় হ'ল বিয়োগ data[0] = 1
করা sum+4
, এভাবে দেওয়া sum + 4 - 1 = 9
।
এটি ঘটে কারণ বর্তমানে sum = data[0] + data[1] + data[2]
, তবে এটি প্রতিটি ক্ষেত্রেও সত্য i >= N
, কারণ বিয়োগের আগে, sum
হয় data[i-N] + ... + data[i-2] + data[i-1]
।
আমি মনে করি এটি খুব সুন্দরভাবে বাধা ব্যবহার করে সমাধান করা যেতে পারে
নীচে বেসিক নমুনা দেখুন:
import numpy as np
import bottleneck as bn
a = np.random.randint(4, 1000, size=100)
mm = bn.move_mean(a, window=5, min_count=1)
"মিমি" হ'ল "ক" এর চলন্ত গড়।
"উইন্ডো" হল চলন্ত গড়ের জন্য বিবেচনার জন্য সর্বাধিক সংখ্যা।
"মিনি_কাউন্ট" হ'ল চলমান গড়ের জন্য বিবেচ্য ন্যূনতম এন্ট্রি (উদাহরণস্বরূপ প্রথম কয়েকটি উপাদানগুলির জন্য বা অ্যারের যদি ন্যানের মান থাকে)।
ভাল অংশ হ'ল বোতলেনেক ন্যান মানগুলি মোকাবেলা করতে সহায়তা করে এবং এটি খুব দক্ষ।
এটি এখনও কত দ্রুত তা আমি এখনও পরীক্ষা করে দেখিনি, তবে আপনি চেষ্টা করতে পারেন:
from collections import deque
cache = deque() # keep track of seen values
n = 10 # window size
A = xrange(100) # some dummy iterable
cum_sum = 0 # initialize cumulative sum
for t, val in enumerate(A, 1):
cache.append(val)
cum_sum += val
if t < n:
avg = cum_sum / float(t)
else: # if window is saturated,
cum_sum -= cache.popleft() # subtract oldest value
avg = cum_sum / float(n)
এই উত্তরে তিনটি পৃথক দৃশ্যের জন্য পাইথন স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করে সমাধান রয়েছে ।
itertools.accumulate
এটি একটি মেমরি দক্ষ পাইথন ৩.২+ সমাধান যা উত্তোলন করে মানগুলির পুনরাবৃত্তের তুলনায় চলমান গড়ের গণনা করে itertools.accumulate
।
>>> from itertools import accumulate
>>> values = range(100)
নোট করুন যে values
জেনারেটর বা অন্য কোনও বস্তু যা ফ্লাইতে মান উত্পাদন করে including
প্রথমে অলসভাবে মানগুলির সংযোজক যোগফলটি তৈরি করুন।
>>> cumu_sum = accumulate(value_stream)
এর পরে, enumerate
সংশ্লেষফল (1 থেকে শুরু) এবং একটি জেনারেটর তৈরি করে যা সঞ্চিত মানগুলির বর্তমান ভগ্নাংশ এবং বর্তমান গণনা সূচককে দেয়।
>>> rolling_avg = (accu/i for i, accu in enumerate(cumu_sum, 1))
আপনার means = list(rolling_avg)
যদি মেমরিতে সমস্ত মান একবারে প্রয়োজন হয় বা next
বর্ধিতভাবে কল করা যায় তবে আপনি ইস্যু করতে পারেন ।
(অবশ্যই, আপনি rolling_avg
একটি for
লুপ দিয়ে পুনরাবৃত্তি করতে পারেন , যা next
স্পষ্টভাবে কল করবে ))
>>> next(rolling_avg) # 0/1
>>> 0.0
>>> next(rolling_avg) # (0 + 1)/2
>>> 0.5
>>> next(rolling_avg) # (0 + 1 + 2)/3
>>> 1.0
এই সমাধানটি ফাংশন হিসাবে নিম্নলিখিত হিসাবে লেখা যেতে পারে।
from itertools import accumulate
def rolling_avg(iterable):
cumu_sum = accumulate(iterable)
yield from (accu/i for i, accu in enumerate(cumu_sum, 1))
এই কর্টিন আপনার পাঠানো মানগুলি গ্রাস করে এবং এ পর্যন্ত দেখা মানগুলির একটি চলমান গড় রাখে।
এটি কার্যকর হয় যখন আপনার মানগুলির পুনরাবৃত্তিযোগ্য না থাকে তবে আপনার প্রোগ্রামের পুরো জীবন জুড়ে বিভিন্ন সময়ে একের পর এক গড় মূল্য অর্জন করতে হয়।
def rolling_avg_coro():
i = 0
total = 0.0
avg = None
while True:
next_value = yield avg
i += 1
total += next_value
avg = total/i
কর্টিন এইভাবে কাজ করে:
>>> averager = rolling_avg_coro() # instantiate coroutine
>>> next(averager) # get coroutine going (this is called priming)
>>>
>>> averager.send(5) # 5/1
>>> 5.0
>>> averager.send(3) # (5 + 3)/2
>>> 4.0
>>> print('doing something else...')
doing something else...
>>> averager.send(13) # (5 + 3 + 13)/3
>>> 7.0
N
এই জেনারেটর-ফাংশনটি একটি পুনরাবৃত্তযোগ্য এবং একটি উইন্ডো আকার নেয় এবং উইন্ডোর N
অভ্যন্তরে বর্তমান মানগুলির চেয়ে গড় উপার্জন করে। এটি একটি ব্যবহার করে deque
যা একটি তালিকার মতো একটি ডেটাস্ট্রাকচার, তবে উভয় প্রান্তে দ্রুত পরিবর্তন ( pop
, append
) এর জন্য অনুকূলিত ।
from collections import deque
from itertools import islice
def sliding_avg(iterable, N):
it = iter(iterable)
window = deque(islice(it, N))
num_vals = len(window)
if num_vals < N:
msg = 'window size {} exceeds total number of values {}'
raise ValueError(msg.format(N, num_vals))
N = float(N) # force floating point division if using Python 2
s = sum(window)
while True:
yield s/N
try:
nxt = next(it)
except StopIteration:
break
s = s - window.popleft() + nxt
window.append(nxt)
এখানে ক্রিয়াকলাপটি রয়েছে:
>>> values = range(100)
>>> N = 5
>>> window_avg = sliding_avg(values, N)
>>>
>>> next(window_avg) # (0 + 1 + 2 + 3 + 4)/5
>>> 2.0
>>> next(window_avg) # (1 + 2 + 3 + 4 + 5)/5
>>> 3.0
>>> next(window_avg) # (2 + 3 + 4 + 5 + 6)/5
>>> 4.0
পার্টিতে কিছুটা দেরি হয়ে গেছে, তবে আমি আমার নিজের একটি ছোট্ট ফাংশন তৈরি করেছি যা গড়গুলি বা প্যাডগুলি প্রায় জিরো দিয়ে মুড়ে দেয় না যা পরে গড়গুলি খুঁজে পাওয়ার জন্য ব্যবহৃত হয়। আরও চিকিত্সা হিসাবে, এটি রৈখিক ব্যবধানযুক্ত পয়েন্টগুলিতে সিগন্যালটিকে পুনরায় নমুনা দেয়। অন্যান্য বৈশিষ্ট্য পেতে কোডটি কাস্টমাইজ করুন।
পদ্ধতিটি হ'ল একটি সাধারণ গাউসীয় কর্নেল সহ একটি সাধারণ ম্যাট্রিক্স গুণ।
def running_mean(y_in, x_in, N_out=101, sigma=1):
'''
Returns running mean as a Bell-curve weighted average at evenly spaced
points. Does NOT wrap signal around, or pad with zeros.
Arguments:
y_in -- y values, the values to be smoothed and re-sampled
x_in -- x values for array
Keyword arguments:
N_out -- NoOf elements in resampled array.
sigma -- 'Width' of Bell-curve in units of param x .
'''
N_in = size(y_in)
# Gaussian kernel
x_out = np.linspace(np.min(x_in), np.max(x_in), N_out)
x_in_mesh, x_out_mesh = np.meshgrid(x_in, x_out)
gauss_kernel = np.exp(-np.square(x_in_mesh - x_out_mesh) / (2 * sigma**2))
# Normalize kernel, such that the sum is one along axis 1
normalization = np.tile(np.reshape(sum(gauss_kernel, axis=1), (N_out, 1)), (1, N_in))
gauss_kernel_normalized = gauss_kernel / normalization
# Perform running average as a linear operation
y_out = gauss_kernel_normalized @ y_in
return y_out, x_out
সাধারণ বিতরণকৃত আওয়াজের সাথে সাইনোসয়েডাল সিগন্যালের একটি সাধারণ ব্যবহার:
sum
ব্যবহার np.sum
পরিবর্তে 2@
অপারেটর (কোন ধারণা যে কি) একটি ত্রুটি ছোঁড়ার। আমি পরে এটি সন্ধান করতে পারি তবে এখনই আমার অভাব হচ্ছে
নোংরা বা ছদ্মবেশীর পরিবর্তে আমি পান্ডাদের আরও দ্রুততার সাথে এটি করার পরামর্শ দিচ্ছি:
df['data'].rolling(3).mean()
এটি "ডেটা" কলামের 3 পিরিয়ডের চলমান গড় (এমএ) নেয়। আপনি স্থানান্তরিত সংস্করণগুলিও গণনা করতে পারেন, উদাহরণস্বরূপ, বর্তমান সেলটি বাদ দেয় এমন একটি (একটি পিছনে স্থানান্তরিত) সহজে গণনা করা যায়:
df['data'].shift(periods=1).rolling(3).mean()
pandas.rolling_mean
খনি ব্যবহারের সময় ব্যবহার করে pandas.DataFrame.rolling
। আপনি চলন min(), max(), sum()
ইত্যাদির পাশাপাশি mean()
এই পদ্ধতির সাহায্যে সহজেই গণনা করতে পারেন।
pandas.rolling_min, pandas.rolling_max
etc. ইত্যাদি They এগুলি একই রকম হলেও অন্যরকম।
উপরের উত্তরগুলির মধ্যে একটিতে মাবুর দ্বারা একটি মন্তব্য রয়েছে যার মধ্যে এই পদ্ধতি রয়েছে has হয়েছে যা সিম্পল মুভিং এভারেজ হয়:bottleneck
move_mean
import numpy as np
import bottleneck as bn
a = np.arange(10) + np.random.random(10)
mva = bn.move_mean(a, window=2, min_count=1)
min_count
হ্যান্ডি প্যারামিটার যা মূলত আপনার অ্যারেতে পয়েন্টে মুভিং এভারেজটি গ্রহণ করে। আপনি যদি সেট না করে থাকেন তবে min_count
এটি সমান window
হবে এবং window
পয়েন্ট অবধি সমস্ত কিছু হবে nan
।
নম্পি, পান্ডা ব্যবহার না করে চলমান গড় সন্ধান করার জন্য আরেকটি পদ্ধতি
import itertools
sample = [2, 6, 10, 8, 11, 10]
list(itertools.starmap(lambda a,b: b/a,
enumerate(itertools.accumulate(sample), 1)))
[2.0, 4.0, 6.0, 6.5, 7.4, 7.833333333333333] মুদ্রণ করবে
এই প্রশ্নটি এখন আরও পুরানো যখন নেক্সুএস গত মাসে এটি সম্পর্কে লিখেছিল, তবে আমি পছন্দ করি তার কোডটি কীভাবে কেস কেসগুলি নিয়ে কাজ করে। তবে এটি "সরল চলমান গড়" বলে এর ফলাফলগুলি তারা প্রয়োগ করা ডেটা থেকে পিছিয়ে। আমি ভেবেছিলাম NumPy এর মোড বেশি পরিতৃপ্ত ভাবে প্রান্ত মামলা সঙ্গে তার আচরণ যে valid
, same
এবং full
একটি একটি অনুরূপ পদ্ধতির প্রয়োগের দ্বারা অর্জন করা যেতে পারে convolution()
ভিত্তিক পদ্ধতি।
আমার অবদানের ফলাফলগুলি তাদের ডেটা দিয়ে সারিবদ্ধ করতে একটি কেন্দ্রীয় চলমান গড় ব্যবহার করে। পূর্ণ আকারের উইন্ডোটি ব্যবহার করার জন্য যখন খুব কম পয়েন্ট পাওয়া যায়, তখন চলমান গড়গুলি অ্যারের প্রান্তে ক্রমাগতভাবে ছোট উইন্ডো থেকে গণনা করা হয়। [আসলে, ক্রমান্বয়ে বড় উইন্ডো থেকে, তবে এটি বাস্তবায়নের বিশদ]
import numpy as np
def running_mean(l, N):
# Also works for the(strictly invalid) cases when N is even.
if (N//2)*2 == N:
N = N - 1
front = np.zeros(N//2)
back = np.zeros(N//2)
for i in range(1, (N//2)*2, 2):
front[i//2] = np.convolve(l[:i], np.ones((i,))/i, mode = 'valid')
for i in range(1, (N//2)*2, 2):
back[i//2] = np.convolve(l[-i:], np.ones((i,))/i, mode = 'valid')
return np.concatenate([front, np.convolve(l, np.ones((N,))/N, mode = 'valid'), back[::-1]])
এটি তুলনামূলকভাবে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে convolve()
সেগুলি ব্যবহার করে এবং সত্যিকারের পাইথনিস্টার দ্বারা সম্ভবত এটি অনেকাংশে বেড়ে যায়। তবে আমি বিশ্বাস করি যে ধারণাটি দাঁড়িয়েছে।
একটি চলমান গড় গণনা সম্পর্কে উপরে অনেক উত্তর রয়েছে। আমার উত্তর দুটি অতিরিক্ত বৈশিষ্ট্য যুক্ত করে:
এই দ্বিতীয় বৈশিষ্ট্যটি নির্দিষ্ট পরিমাণে সাধারণ ট্রেন্ডের থেকে কোন মানগুলি পৃথক করে তা নির্ধারণের জন্য বিশেষভাবে কার্যকর।
আমি numpy.cumsum ব্যবহার করি যেহেতু এটি সর্বাধিক সময়োপযোগী পদ্ধতি ( উপরে অ্যালেওর উত্তর দেখুন )।
N=10 # number of points to test on each side of point of interest, best if even
padded_x = np.insert(np.insert( np.insert(x, len(x), np.empty(int(N/2))*np.nan), 0, np.empty(int(N/2))*np.nan ),0,0)
n_nan = np.cumsum(np.isnan(padded_x))
cumsum = np.nancumsum(padded_x)
window_sum = cumsum[N+1:] - cumsum[:-(N+1)] - x # subtract value of interest from sum of all values within window
window_n_nan = n_nan[N+1:] - n_nan[:-(N+1)] - np.isnan(x)
window_n_values = (N - window_n_nan)
movavg = (window_sum) / (window_n_values)
এই কোডটি এমনকি এনএসের জন্যও কাজ করে। প্যাডে_এক্স এবং এন_নানের এনপি ইন্ডিট পরিবর্তন করে এটি বিজোড় সংখ্যার জন্য সামঞ্জস্য করা যেতে পারে।
উদাহরণস্বরূপ আউটপুট (কালো রঙের কাঁচা, নীল রঙের মুভাভ):
এই কোডটি সহজে কাটফ = 3 নন-ন্যান মানের থেকে কম থেকে গণনা করা সমস্ত চলমান গড় মানগুলি সরিয়ে ফেলার জন্য সহজেই রূপান্তর করা যেতে পারে।
window_n_values = (N - window_n_nan).astype(float) # dtype must be float to set some values to nan
cutoff = 3
window_n_values[window_n_values<cutoff] = np.nan
movavg = (window_sum) / (window_n_values)
কেবল পাইথন স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করুন (মেমরি দক্ষ)
কেবলমাত্র স্ট্যান্ডার্ড লাইব্রেরি ব্যবহারের অন্য একটি সংস্করণ দিন deque
। এটি আমার কাছে বেশ অবাক হওয়ার বিষয় যে বেশিরভাগ উত্তর ব্যবহার করছে pandas
বা numpy
।
def moving_average(iterable, n=3):
d = deque(maxlen=n)
for i in iterable:
d.append(i)
if len(d) == n:
yield sum(d)/n
r = moving_average([40, 30, 50, 46, 39, 44])
assert list(r) == [40.0, 42.0, 45.0, 43.0]
আসলে আমি পাইথন ডক্সে আরও একটি বাস্তবায়ন পেয়েছি
def moving_average(iterable, n=3):
# moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
# http://en.wikipedia.org/wiki/Moving_average
it = iter(iterable)
d = deque(itertools.islice(it, n-1))
d.appendleft(0)
s = sum(d)
for elem in it:
s += elem - d.popleft()
d.append(elem)
yield s / n
তবে বাস্তবায়ন আমার কাছে মনে হওয়া উচিত এর চেয়ে কিছুটা জটিল। তবে এটি অবশ্যই স্ট্যান্ডার্ড পাইথন ডক্সে একটি কারণে থাকতে হবে, কেউ আমার এবং স্ট্যান্ডার্ড ডক বাস্তবায়নের বিষয়ে মন্তব্য করতে পারে?
O(n*d)
গণনা করছেন ( d
উইন্ডোর n
আকার, পুনরাবৃত্তের আকার) এবং তারা করছেনO(n)
যদিও এখানে এই প্রশ্নের সমাধান রয়েছে তবে আমার সমাধানটি একবার দেখুন। এটি খুব সাধারণ এবং ভালভাবে কাজ করছে।
import numpy as np
dataset = np.asarray([1, 2, 3, 4, 5, 6, 7])
ma = list()
window = 3
for t in range(0, len(dataset)):
if t+window <= len(dataset):
indices = range(t, t+window)
ma.append(np.average(np.take(dataset, indices)))
else:
ma = np.asarray(ma)
অন্যান্য উত্তরগুলি পড়া থেকে আমি মনে করি না যে এটিই প্রশ্নটি চেয়েছিল, তবে আকারে বাড়ছে এমন মানগুলির একটি তালিকার চলমান গড় রাখার প্রয়োজনে আমি এখানে এসেছি।
সুতরাং আপনি যদি কোথাও (সাইট, একটি পরিমাপের ডিভাইস ইত্যাদি) অর্জন করছেন এমন মানগুলির একটি তালিকা এবং সর্বশেষ n
মানগুলির আপডেট আপডেট রাখতে চান তবে আপনি কোডটি বেলো ব্যবহার করতে পারেন, যা নতুন যুক্ত করার প্রচেষ্টাকে কমিয়ে দেয় উপাদান:
class Running_Average(object):
def __init__(self, buffer_size=10):
"""
Create a new Running_Average object.
This object allows the efficient calculation of the average of the last
`buffer_size` numbers added to it.
Examples
--------
>>> a = Running_Average(2)
>>> a.add(1)
>>> a.get()
1.0
>>> a.add(1) # there are two 1 in buffer
>>> a.get()
1.0
>>> a.add(2) # there's a 1 and a 2 in the buffer
>>> a.get()
1.5
>>> a.add(2)
>>> a.get() # now there's only two 2 in the buffer
2.0
"""
self._buffer_size = int(buffer_size) # make sure it's an int
self.reset()
def add(self, new):
"""
Add a new number to the buffer, or replaces the oldest one there.
"""
new = float(new) # make sure it's a float
n = len(self._buffer)
if n < self.buffer_size: # still have to had numbers to the buffer.
self._buffer.append(new)
if self._average != self._average: # ~ if isNaN().
self._average = new # no previous numbers, so it's new.
else:
self._average *= n # so it's only the sum of numbers.
self._average += new # add new number.
self._average /= (n+1) # divide by new number of numbers.
else: # buffer full, replace oldest value.
old = self._buffer[self._index] # the previous oldest number.
self._buffer[self._index] = new # replace with new one.
self._index += 1 # update the index and make sure it's...
self._index %= self.buffer_size # ... smaller than buffer_size.
self._average -= old/self.buffer_size # remove old one...
self._average += new/self.buffer_size # ...and add new one...
# ... weighted by the number of elements.
def __call__(self):
"""
Return the moving average value, for the lazy ones who don't want
to write .get .
"""
return self._average
def get(self):
"""
Return the moving average value.
"""
return self()
def reset(self):
"""
Reset the moving average.
If for some reason you don't want to just create a new one.
"""
self._buffer = [] # could use np.empty(self.buffer_size)...
self._index = 0 # and use this to keep track of how many numbers.
self._average = float('nan') # could use np.NaN .
def get_buffer_size(self):
"""
Return current buffer_size.
"""
return self._buffer_size
def set_buffer_size(self, buffer_size):
"""
>>> a = Running_Average(10)
>>> for i in range(15):
... a.add(i)
...
>>> a()
9.5
>>> a._buffer # should not access this!!
[10.0, 11.0, 12.0, 13.0, 14.0, 5.0, 6.0, 7.0, 8.0, 9.0]
Decreasing buffer size:
>>> a.buffer_size = 6
>>> a._buffer # should not access this!!
[9.0, 10.0, 11.0, 12.0, 13.0, 14.0]
>>> a.buffer_size = 2
>>> a._buffer
[13.0, 14.0]
Increasing buffer size:
>>> a.buffer_size = 5
Warning: no older data available!
>>> a._buffer
[13.0, 14.0]
Keeping buffer size:
>>> a = Running_Average(10)
>>> for i in range(15):
... a.add(i)
...
>>> a()
9.5
>>> a._buffer # should not access this!!
[10.0, 11.0, 12.0, 13.0, 14.0, 5.0, 6.0, 7.0, 8.0, 9.0]
>>> a.buffer_size = 10 # reorders buffer!
>>> a._buffer
[5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0]
"""
buffer_size = int(buffer_size)
# order the buffer so index is zero again:
new_buffer = self._buffer[self._index:]
new_buffer.extend(self._buffer[:self._index])
self._index = 0
if self._buffer_size < buffer_size:
print('Warning: no older data available!') # should use Warnings!
else:
diff = self._buffer_size - buffer_size
print(diff)
new_buffer = new_buffer[diff:]
self._buffer_size = buffer_size
self._buffer = new_buffer
buffer_size = property(get_buffer_size, set_buffer_size)
এবং আপনি এটি পরীক্ষা করে দেখতে পারেন, উদাহরণস্বরূপ:
def graph_test(N=200):
import matplotlib.pyplot as plt
values = list(range(N))
values_average_calculator = Running_Average(N/2)
values_averages = []
for value in values:
values_average_calculator.add(value)
values_averages.append(values_average_calculator())
fig, ax = plt.subplots(1, 1)
ax.plot(values, label='values')
ax.plot(values_averages, label='averages')
ax.grid()
ax.set_xlim(0, N)
ax.set_ylim(0, N)
fig.show()
যা দেয়:
কেবলমাত্র একটি স্ট্যান্ডার্ড লাইব্রেরি এবং ডিউক ব্যবহার করে অন্য একটি সমাধান:
from collections import deque
import itertools
def moving_average(iterable, n=3):
# http://en.wikipedia.org/wiki/Moving_average
it = iter(iterable)
# create an iterable object from input argument
d = deque(itertools.islice(it, n-1))
# create deque object by slicing iterable
d.appendleft(0)
s = sum(d)
for elem in it:
s += elem - d.popleft()
d.append(elem)
yield s / n
# example on how to use it
for i in moving_average([40, 30, 50, 46, 39, 44]):
print(i)
# 40.0
# 42.0
# 45.0
# 43.0
শিক্ষাগত কাজের জন্য, আমাকে আরও দুটি নম্পি সমাধান যুক্ত করতে দিন (যা ক্লামসাম দ্রবণের চেয়ে ধীর)
import numpy as np
from numpy.lib.stride_tricks import as_strided
def ra_strides(arr, window):
''' Running average using as_strided'''
n = arr.shape[0] - window + 1
arr_strided = as_strided(arr, shape=[n, window], strides=2*arr.strides)
return arr_strided.mean(axis=1)
def ra_add(arr, window):
''' Running average using add.reduceat'''
n = arr.shape[0] - window + 1
indices = np.array([0, window]*n) + np.repeat(np.arange(n), 2)
arr = np.append(arr, 0)
return np.add.reduceat(arr, indices )[::2]/window
ব্যবহৃত ফাংশন: as_Stided , add.reduceat
পূর্বোক্ত সমস্ত সমাধান খুব কম কারণ তাদের অভাব রয়েছে
numpy.cumsum
বা এর দুর্বল ব্যবহারের কারণে সংখ্যাগত স্থায়িত্বO(len(x) * w)
রূপান্তর হিসাবে বাস্তবায়ন কারণে গতি ।প্রদত্ত
import numpy
m = 10000
x = numpy.random.rand(m)
w = 1000
x_[:w].sum()
সমান নোট করুন x[:w-1].sum()
। সুতরাং প্রথম গড়ের জন্য numpy.cumsum(...)
অ্যাডস x[w] / w
(মাধ্যমে x_[w+1] / w
) এবং বিয়োগ করে 0
(থেকে x_[0] / w
)। এর ফলেx[0:w].mean()
কামসামের মাধ্যমে, আপনি অতিরিক্ত যোগ x[w+1] / w
এবং বিয়োগ করে দ্বিতীয় গড় আপডেট করবেন x[0] / w
, ফলস্বরূপ x[1:w+1].mean()
।
এটি x[-w:].mean()
পৌঁছা পর্যন্ত অবধি চলে ।
x_ = numpy.insert(x, 0, 0)
sliding_average = x_[:w].sum() / w + numpy.cumsum(x_[w:] - x_[:-w]) / w
এই সমাধানটি ভেক্টরাইজড, O(m)
পঠনযোগ্য এবং সংখ্যাগতভাবে স্থিতিশীল।
একটি চলমান গড় ফিল্টার সম্পর্কে কী? এটি একটি ওয়ানলাইনার এবং এর সুবিধাও রয়েছে, আপনি যদি আয়তক্ষেত্রের চেয়ে অন্য কিছু প্রয়োজন, তবে উইন্ডো টাইপটি সহজেই পরিচালনা করতে পারেন। একটি অ্যারের একটি এন-দীর্ঘ সরল চলমান গড়:
lfilter(np.ones(N)/N, [1], a)[N:]
এবং ত্রিভুজাকার উইন্ডো প্রয়োগ করে:
lfilter(np.ones(N)*scipy.signal.triang(N)/N, [1], a)[N:]
দ্রষ্টব্য: আমি সাধারণত বোগাস হিসাবে প্রথম এন নমুনাগুলি [N:]
শেষ পর্যন্ত বাতিল করে দিই , তবে এটি প্রয়োজনীয় নয় এবং কেবল একটি ব্যক্তিগত পছন্দের বিষয়।
আপনি যদি কোনও বিদ্যমান লাইব্রেরি ব্যবহার না করে নিজের রোলটি বেছে নেন, দয়া করে ভাসমান পয়েন্ট ত্রুটির বিষয়ে সচেতন হন এবং এর প্রভাবগুলি হ্রাস করার চেষ্টা করুন:
class SumAccumulator:
def __init__(self):
self.values = [0]
self.count = 0
def add( self, val ):
self.values.append( val )
self.count = self.count + 1
i = self.count
while i & 0x01:
i = i >> 1
v0 = self.values.pop()
v1 = self.values.pop()
self.values.append( v0 + v1 )
def get_total(self):
return sum( reversed(self.values) )
def get_size( self ):
return self.count
আপনার সমস্ত মান যদি মোটামুটি একই পরিমাণের ক্রম হয়, তবে এটি সর্বদা মোটামুটি অনুরূপ দৈর্ঘ্যের মান যুক্ত করে নির্ভুলতা রক্ষা করতে সহায়তা করবে।