গড় বা চলমান গড় চলমান


192

পাইথনের জন্য কি কোনও সায়পি ফাংশন বা নম্পপি ফাংশন বা মডিউল রয়েছে যা একটি নির্দিষ্ট উইন্ডো প্রদত্ত 1D অ্যারের চলমান গড় গণনা করে?

উত্তর:


24

একটি সংক্ষিপ্ত, দ্রুত সমাধানের জন্য যা পুরোপুরি এক লুপে করে, নির্ভরতা ছাড়াই, নীচের কোডটি দুর্দান্ত কাজ করে।

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)

44
ফাস্ট ?! এই সমাধানটি নম্পির সাথে সমাধানগুলির চেয়ে ধীর গতির অর্ডার।
বার্ট

3
যদিও এই নেটিভ সমাধানটি দুর্দান্ত তবে ওপি একটি অসাড় / স্কিপি ফাংশন চেয়েছিল - সম্ভবত এগুলি যথেষ্ট দ্রুত হবে।
ডেমিস

254

ইউপিডি: আরও দক্ষ সমাধানের প্রস্তাব দেওয়া হয়েছে আলেও এবং জাসারিমের দ্বারা


আপনি এটির 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()

রানিং মানে কনভলভ মোডগুলি


4
আমি এই সমাধানটি পছন্দ করি কারণ এটি পরিষ্কার (এক লাইন) এবং তুলনামূলকভাবে দক্ষ (আঙ্গুলের মধ্যে কাজ করা)। তবে অ্যালিয়োর "দক্ষ সমাধান" ব্যবহারের numpy.cumsumক্ষেত্রে আরও জটিলতা রয়েছে।
উলিখ স্টার্ন

2
@ এডনফ্রোমুফা, আমি বিশ্বাস করি যে ডকুমেন্টেশন প্রয়োগের যথেষ্ট পরিমাণে কভার করে, এবং এটি উইকিপিডিয়ায় লিঙ্ক করে যা গণিতগুলি ব্যাখ্যা করে। প্রশ্নের ফোকাস বিবেচনা করে, আপনি কি মনে করেন যে এই উত্তরটি সেগুলি অনুলিপি করা দরকার?
lapis

@ ল্যাপিস চলমান গড়ের জন্য কনভলভ ব্যবহার বেশ অস্বাভাবিক এবং স্পষ্ট নয়। এখানে আমি খুঁজে পেয়েছি সেরা দর্শনীয় ব্যাখ্যা: matlabtricks.com/post-11/moving-average-by- কনভোলিউশন
denfromufa

ষড়যন্ত্র এবং সম্পর্কিত কাজের জন্য এটি কোনও মান সহ পূরণ করা সহায়ক হবে। আমার (এত সুন্দর নয় তবে সংক্ষিপ্ত) পরামর্শ: `` `ডিফ মুভিং_ভেরেজ (এক্স, এন, ফিল = সত্য) * পূরণ, এনপি.কনভলভ (এক্স, এনপি.নেস ((এন,)) / এন, মোড = 'বৈধ'), [কিছুই নয়] * (এন // ২) * পূরণ,] যদি লেন (এক্স)]) ` S O কোডটি এতটাই কুৎসিত দেখাচ্ছে যাতে কমেন্টস xD আমি আরও একটি উত্তর যুক্ত করতে চাইনি কারণ এখানে অনেকগুলি রয়েছে তবে আপনি সম্ভবত এটি অনুলিপি করে আপনার আইডিইতে আটকান।
বিশ্রামের

143

দক্ষ সমাধান

কনভলিউশন সোজা পদ্ধতির চেয়ে অনেক ভাল, তবে (আমার ধারণা) এটি এফএফটি ব্যবহার করে এবং এইভাবে বেশ ধীর হয়। তবে বিশেষ করে চলমান গণনার জন্য নিম্নলিখিত পদ্ধতির সূক্ষ্ম কাজ করে

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)
  • বৃহত্তর ভাসমান বিন্দু ত্রুটির উপরে আপনি যে পরিমাণে বেশি পরিমাণে জমা হন (তাই 1e5 পয়েন্টগুলি লক্ষণীয়, 1e6 পয়েন্টগুলি আরও তাত্পর্যপূর্ণ, 1e6 এর চেয়ে বেশি এবং আপনি আহরণকারীকে পুনরায় সেট করতে চাইতে পারেন)
  • আপনি ব্যবহার করে প্রতারণা করতে পারেন np.longdouble তবে আপনার ভাসমান পয়েন্ট ত্রুটিটি এখনও তুলনামূলকভাবে বড় সংখ্যক পয়েন্টের জন্য গুরুত্বপূর্ণ হবে (প্রায়> 1e5 তবে আপনার ডেটার উপর নির্ভর করে)
  • আপনি ত্রুটিটি চক্রান্ত করতে পারেন এবং তুলনামূলকভাবে দ্রুত বাড়তে দেখছেন
  • কনভলভ দ্রবণটি ধীর গতিতে রয়েছে তবে নির্ভুলতার এই ভাসমান বিন্দুটি নেই
  • ইউনিফর্ম_ফিল্টার 1 ডি দ্রবণটি এই চামচিক দ্রবণটির চেয়ে দ্রুততর এবং নির্ভুলতার এই ভাসমান বিন্দুটির ক্ষতি নেই

3
চমৎকার সমাধান! আমার কুণ্ডলী হ'ল numpy.convolveও (এমএন); এর দস্তাবেজগুলিscipy.signal.fftconvolve এফএফটি ব্যবহার করে উল্লেখ করে ।
উলিরিচ স্টার্ন

3
এই পদ্ধতিটি অ্যারের কিনারাগুলি নিয়ে কাজ করে না, তাই না?
জোভ

6
দুর্দান্ত সমাধান, তবে নোট করুন যে এটি বড় অ্যারেগুলির জন্য সংখ্যাগত ত্রুটিতে ভুগতে পারে, যেহেতু অ্যারের শেষের দিকে, আপনি একটি ছোট ফলাফল পেতে দুটি বৃহত সংখ্যাকে বিয়োগ করতে পারেন।
বাস সুইঙ্কসেলস

1
এটি ফ্লোট বিভাগের পরিবর্তে পূর্ণসংখ্যা বিভাগ ব্যবহার করে: running_mean([1,2,3], 2)দেয় array([1, 2])xদ্বারা প্রতিস্থাপন [float(value) for value in x]কৌশলটি করে।
ক্রিসডাব্লু

4
এই সমাধানের সংখ্যাগত স্থিতিশীলতা একটি সমস্যা হয়ে উঠতে পারে যদি 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
মিলন

79

আপডেট: নীচের উদাহরণে পুরানো 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

প্রান্তের মানগুলি কীভাবে মোকাবেলা করা যায় সে সম্পর্কেও দুর্দান্ত বিকল্প রয়েছে।


6
পান্ডস রোলিং_মাইন চাকরির জন্য একটি দুর্দান্ত সরঞ্জাম তবে নাদারেরীদের জন্য হতাশ হয়েছে। ভবিষ্যতে পান্ডাস প্রকাশিত হয় এটি কেবল পান্ডাস সিরিজেই কাজ করবে। নন-পান্ডাস অ্যারে ডেটার জন্য আমরা এখন কোথায় ঘুরব?
মাইক

5
@ মাইকের রোলিং_মিয়ান () অবমূল্যায়ন করা হয়েছে তবে এখন আপনি রোলিংটি ব্যবহার করতে পারেন এবং আলাদাভাবে বলতে পারবেন: df.rolling(windowsize).mean()এখন পরিবর্তে কাজ করে (খুব দ্রুত আমি যুক্ত করতে পারি)। 6,000 সারি সিরিজের জন্য 1000 লুপগুলি%timeit test1.rolling(20).mean() ফিরেছে , 3
টির মধ্যে

5
@ ভ্লাক্স df.rolling()যথেষ্ট ভাল কাজ করে, সমস্যাটি হ'ল এমনকি এই ফর্মটি ভবিষ্যতেও নাদরাদের সমর্থন করবে না। এটি ব্যবহারের জন্য আমাদের প্রথমে একটি পান্ডাস ডেটাফ্রেমে আমাদের ডেটা লোড করতে হবে। আমি এই ফাংশনটি হয় numpyবা এর সাথে যুক্ত দেখতে চাই scipy.signal
মাইক

1
@ মাইক সম্পূর্ণরূপে একমত। আমি পান্ডের সাথে ম্যাচ করার জন্য বিশেষত লড়াই করছি .ewm ()। (মানে।) আমার নিজের অ্যারের গতি (তাদের পরিবর্তে প্রথমে ডিএফ-এ লোড করার পরিবর্তে)। আমার অর্থ, এটি দুর্দান্ত যে এটি দ্রুত, তবে খুব ঘন ঘন ডেটাফ্রেমে কিছুটা আড়মোড়া চলাচল করে।
ভ্লাক্স

6
%timeit bottleneck.move_mean(x, N)আমার পিসিতে চামসাম এবং পান্ডাস পদ্ধতির চেয়ে 3 থেকে 15 গুণ বেশি গতিযুক্ত। রেপোর README এ তাদের মানদণ্ডটি একবার দেখুন
মাব

50

আপনি এটির সাথে একটি চলমান গড় গণনা করতে পারেন:

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'মোড অন্তর্ভুক্ত করে যা মনে হয় এটির শুরু ক্ষণস্থায়ী সমস্যার সমাধান করা উচিত তবে এটি এটি শুরু এবং শেষের মধ্যে বিভক্ত হয়।


মনে রাখবেন যে প্রথম এন -1 পয়েন্টগুলি অপসারণ করা এখনও শেষ পয়েন্টগুলিতে একটি সীমানা প্রভাব ফেলে। সমস্যা সমাধানের একটি সহজ উপায় হ'ল ব্যবহার mode='valid'করা convolveযাতে কোনও পোস্ট-প্রসেসিংয়ের প্রয়োজন হয় না।
ল্যাপিস

1
@ সাইকো - mode='valid'উভয় প্রান্ত থেকে ক্ষণস্থায়ী সরান, তাই না? যদি len(x)=10এবং N=4, একটি চলমান গড়ের জন্য আমি 10 ফলাফল চাইব তবে ফলাফল valid7.
mtrw

1
এটি শেষ থেকে ক্ষণস্থায়ীটিকে সরিয়ে দেয় এবং প্রারম্ভের একটিও নেই। ঠিক আছে, আমি অনুমান করি এটি অগ্রাধিকারের বিষয়, ডাটার মধ্যে শূন্যের দিকে aালু ব্যয়ের জন্য আমার একই সংখ্যার ফলাফলের দরকার নেই। বিটিডাব্লু, এখানে মোডের মধ্যে পার্থক্যটি দেখানোর জন্য একটি আদেশ রয়েছে: 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)]ডান পাশের জন্য অ্যারের বাইরে চলে যান তখন আমার শূন্যের সাথে গড়ের পার্শ্বপ্রতিক্রিয়া থাকতে হবে?
mrgloom

runningMeanFastএছাড়াও এই সীমান্ত প্রভাব সমস্যা আছে।
mrgloom

21

বা পাইথনের জন্য মডিউল যা গণনা করে

ট্রেডওয়েভ.নেট আমার পরীক্ষায় টিএ-লাইব সর্বদা জিততে থাকে:

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। আমি এই ত্রুটি পাচ্ছি, স্যার।
মোঃ রেজওয়ানুল হক

1
দেখে মনে হচ্ছে আপনার সময় সিরিজটি মসৃণ করার পরে স্থানান্তরিত হয়েছে, এটি কি পছন্দসই প্রভাব রয়েছে?
mrgloom

@ এমআরগ্লুম হ্যাঁ, চাক্ষুষের উদ্দেশ্যে; অন্যথায় তারা চার্টে এক লাইন হিসাবে উপস্থিত হবে; মোঃ রেজওয়ানুল হক আপনি পেয়ার এবং তথ্য সম্পর্কিত সমস্ত তথ্য সরিয়ে ফেলতে পারেন; সেগুলি এখন অদৃশ্য ট্রেডওয়েভ নেট.কমের অভ্যন্তরীণ স্যান্ডবক্সযুক্ত পদ্ধতি ছিল
লিপি উপস্থিতি

21

ব্যবহারের জন্য প্রস্তুত সমাধানের জন্য 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)

1
এই পদ্ধতিটি নির্ভর করে numpy.convolve, কেবল ক্রম পরিবর্তন করতে পার্থক্য।
অ্যালোও

10
আমি সর্বদা সংকেত প্রক্রিয়াকরণ ফাংশন থেকে বিরক্ত হই যে ইনপুট সংকেতগুলির চেয়ে আলাদা আকারের আউটপুট সংকেতগুলি ফেরত দেয় যখন উভয় ইনপুট এবং আউটপুট একই প্রকৃতির হয় (যেমন, উভয় স্থায়ী সংকেত)। এটি সম্পর্কিত স্বাধীন ভেরিয়েবলের (যেমন, সময়, ফ্রিকোয়েন্সি) সাথে চিঠিপত্রের সম্পর্ককে ভেঙে দেয় বা ষড়যন্ত্রের তুলনা সরাসরি বিষয় নয় ... যাইহোক, আপনি যদি অনুভূতি ভাগ করে নেন তবে আপনি প্রস্তাবিত ফাংশনের শেষ লাইনগুলি y = np হিসাবে পরিবর্তন করতে চাইতে পারেন .convolve (W / w.sum (), গুলি, মোড = 'একই'); ফিরতি y [উইন্ডো_লেন -১ :-( উইন্ডো_লেন -১)]
খ্রিস্টান ও'রিলি

@ ক্রিশ্চিয়ানো'রিলি, আপনার আলাদা পোস্টের উত্তর হিসাবে পোস্ট করা উচিত- ঠিক আমি যা খুঁজছিলাম ঠিক তেমনই আমার কাছে অন্য দুটি অ্যারে রয়েছে যেগুলি স্মুথড ডেটার দৈর্ঘ্যের সাথে মেলে থাকতে পারে, প্লট করার জন্য ইত্যাদি। আমি জানতে চাই ঠিক কীভাবে আপনি এটি করেছিলেন - wউইন্ডোর আকার এবং sডেটা?
ডেমিস

মন্তব্য ডেমিস খুশী হয়েছে। Numpy বিভিন্ন বস্তু একত্র পাকান ফাংশন আরো তথ্য এখানে docs.scipy.org/doc/numpy-1.15.0/reference/generated/... একটি সংবর্তন ফাংশন ( en.wikipedia.org/wiki/Convolution ) একে অপরের সাথে দুটি সংকেত convolves। এই ক্ষেত্রে এটি আপনার সিগন্যাল (গুলি) কে একটি সাধারণীকরণের (যেমন একক ক্ষেত্রের) উইন্ডো (ডাব্লু / ডাব্লু.সুম ()) দিয়ে সংহত করে।
খ্রিস্টান ও'রিলি

18

আপনি 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)]

1
এটিই একমাত্র উত্তর যা মনে হয় সীমান্ত সম্পর্কিত বিষয়গুলি বিবেচনা করে নেবে (বরং গুরুত্বপূর্ণ, বিশেষত চক্রান্ত করার সময়)। ধন্যবাদ!
গ্যাব্রিয়েল

1
আমি প্রোফাইল uniform_filter1d, np.convolve, একটি আয়তক্ষেত্র ও np.cumsumঅনুসরণ np.subtract। আমার ফলাফল: (১.) কনভলভ করা সবচেয়ে ধীর। (২) চামসাম / বিয়োগ প্রায় 20-30x দ্রুত। (3.) ইউনিফর্ম_ফিল্টার 1 ডি চামসাম / বিয়োগফলের চেয়ে প্রায় 2-3x গতিযুক্ত। বিজয়ী অবশ্যই ইউনিফর্ম_ফিল্টার 1 ডি।
ট্রেভর বয়েড স্মিথ

ব্যবহার uniform_filter1dকরা সমাধানের চেয়ে দ্রুতcumsum (প্রায় 2-5x দ্বারা)। এবং সমাধানের uniform_filter1d মতো বিশাল ভাসমান পয়েন্ট ত্রুটিcumsum পায় না।
ট্রেভর বয়েড স্মিথ

15

আমি জানি এটি একটি পুরানো প্রশ্ন, তবে এখানে একটি সমাধান রয়েছে যা কোনও অতিরিক্ত ডেটা স্ট্রাকচার বা লাইব্রেরি ব্যবহার করে না। এটি ইনপুট তালিকার উপাদানগুলির সংখ্যার মধ্যে লিনিয়ার এবং আমি এটিকে আরও দক্ষ করে তোলার জন্য অন্য কোনও উপায়ের কথা ভাবতে পারি না (আসলে যদি কেউ ফলাফল বরাদ্দ দেওয়ার আরও ভাল উপায় সম্পর্কে জানে তবে দয়া করে আমাকে জানান)।

দ্রষ্টব্য: তালিকার পরিবর্তে একটি অদ্ভুত অ্যারে ব্যবহার করা এটি আরও দ্রুত হবে তবে আমি সমস্ত নির্ভরতা দূর করতে চেয়েছিলাম। মাল্টি-থ্রেড এক্সিকিউশন দ্বারা কর্মক্ষমতা উন্নত করাও সম্ভব হবে

ফাংশন ধরে নেয় যে ইনপুট তালিকাটি একটি মাত্রিক, তাই সাবধানতা অবলম্বন করুন।

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


12

আমি মনে করি এটি খুব সুন্দরভাবে বাধা ব্যবহার করে সমাধান করা যেতে পারে

নীচে বেসিক নমুনা দেখুন:

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)
  • "মিমি" হ'ল "ক" এর চলন্ত গড়।

  • "উইন্ডো" হল চলন্ত গড়ের জন্য বিবেচনার জন্য সর্বাধিক সংখ্যা।

  • "মিনি_কাউন্ট" হ'ল চলমান গড়ের জন্য বিবেচ্য ন্যূনতম এন্ট্রি (উদাহরণস্বরূপ প্রথম কয়েকটি উপাদানগুলির জন্য বা অ্যারের যদি ন্যানের মান থাকে)।

ভাল অংশ হ'ল বোতলেনেক ন্যান মানগুলি মোকাবেলা করতে সহায়তা করে এবং এটি খুব দক্ষ।


এই lib সত্যিই দ্রুত। খাঁটি পাইথন মুভিং এভারেজ ফাংশনটি ধীর। বুটলেনেক একটি পাইডাটা লাইব্রেরি, যা আমি মনে করি স্থিতিশীল এবং পাইথন সম্প্রদায়ের ক্রমাগত সমর্থন পেতে পারে, তবে কেন এটি ব্যবহার করবেন না?
GoingMyWay

6

এটি এখনও কত দ্রুত তা আমি এখনও পরীক্ষা করে দেখিনি, তবে আপনি চেষ্টা করতে পারেন:

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)

1
এই আমি কি করতে যাচ্ছিলাম। কেউ কেন সমালোচনা করে দয়া করে কেন এটি খারাপ পথে যেতে পারে?
staggart

1
এই সাধারণ পাইথন সলিউশনটি নাম্পের প্রয়োজন ছাড়াই আমার পক্ষে ভাল কাজ করেছে। আমি এটি আবার ব্যবহারের জন্য ক্লাসে ঘূর্ণায়মান শেষ করেছি।
ম্যাথু শ্যাচিগ

6

এই উত্তরে তিনটি পৃথক দৃশ্যের জন্য পাইথন স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করে সমাধান রয়েছে ।


সঙ্গে গড় রানিং 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

5

পার্টিতে কিছুটা দেরি হয়ে গেছে, তবে আমি আমার নিজের একটি ছোট্ট ফাংশন তৈরি করেছি যা গড়গুলি বা প্যাডগুলি প্রায় জিরো দিয়ে মুড়ে দেয় না যা পরে গড়গুলি খুঁজে পাওয়ার জন্য ব্যবহৃত হয়। আরও চিকিত্সা হিসাবে, এটি রৈখিক ব্যবধানযুক্ত পয়েন্টগুলিতে সিগন্যালটিকে পুনরায় নমুনা দেয়। অন্যান্য বৈশিষ্ট্য পেতে কোডটি কাস্টমাইজ করুন।

পদ্ধতিটি হ'ল একটি সাধারণ গাউসীয় কর্নেল সহ একটি সাধারণ ম্যাট্রিক্স গুণ।

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

সাধারণ বিতরণকৃত আওয়াজের সাথে সাইনোসয়েডাল সিগন্যালের একটি সাধারণ ব্যবহার: এখানে চিত্র বর্ণনা লিখুন


এটি আমার পক্ষে কাজ করে না (অজগর 3.6)। 1 কোন ফাংশন নামে নেই sumব্যবহার np.sumপরিবর্তে 2@ অপারেটর (কোন ধারণা যে কি) একটি ত্রুটি ছোঁড়ার। আমি পরে এটি সন্ধান করতে পারি তবে এখনই আমার অভাব হচ্ছে
বাসটিয়ান

@ম্যাট্রিক্স গুণ অপারেটর যা কার্যকরী হয় np.matmul । আপনার y_inঅ্যারেটি একটি নম্র অ্যারে কিনা তা পরীক্ষা করুন , এটাই সমস্যা হতে পারে।
xyzzyqed

5

নোংরা বা ছদ্মবেশীর পরিবর্তে আমি পান্ডাদের আরও দ্রুততার সাথে এটি করার পরামর্শ দিচ্ছি:

df['data'].rolling(3).mean()

এটি "ডেটা" কলামের 3 পিরিয়ডের চলমান গড় (এমএ) নেয়। আপনি স্থানান্তরিত সংস্করণগুলিও গণনা করতে পারেন, উদাহরণস্বরূপ, বর্তমান সেলটি বাদ দেয় এমন একটি (একটি পিছনে স্থানান্তরিত) সহজে গণনা করা যায়:

df['data'].shift(periods=1).rolling(3).mean()


2
২০১ proposed সালে প্রস্তাবিত সমাধানটি pandas.rolling_meanখনি ব্যবহারের সময় ব্যবহার করে pandas.DataFrame.rolling। আপনি চলন min(), max(), sum()ইত্যাদির পাশাপাশি mean()এই পদ্ধতির সাহায্যে সহজেই গণনা করতে পারেন।
গুরসেল করাকর

পূর্বেরগুলিতে আপনার আলাদা পদ্ধতি ব্যবহার করা দরকার pandas.rolling_min, pandas.rolling_maxetc. ইত্যাদি They এগুলি একই রকম হলেও অন্যরকম।
গুরসেল করাকর

4

উপরের উত্তরগুলির মধ্যে একটিতে মাবুর দ্বারা একটি মন্তব্য রয়েছে যার মধ্যে এই পদ্ধতি রয়েছে has হয়েছে যা সিম্পল মুভিং এভারেজ হয়:bottleneckmove_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


3

নম্পি, পান্ডা ব্যবহার না করে চলমান গড় সন্ধান করার জন্য আরেকটি পদ্ধতি

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] মুদ্রণ করবে


itertools.accumulate পাইথন ২.7 এ বিদ্যমান নেই তবে পাইথন ৩.৪-এ রয়েছে
গ্রেইয়াই

3

এই প্রশ্নটি এখন আরও পুরানো যখন নেক্সুএস গত মাসে এটি সম্পর্কে লিখেছিল, তবে আমি পছন্দ করি তার কোডটি কীভাবে কেস কেসগুলি নিয়ে কাজ করে। তবে এটি "সরল চলমান গড়" বলে এর ফলাফলগুলি তারা প্রয়োগ করা ডেটা থেকে পিছিয়ে। আমি ভেবেছিলাম 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()সেগুলি ব্যবহার করে এবং সত্যিকারের পাইথনিস্টার দ্বারা সম্ভবত এটি অনেকাংশে বেড়ে যায়। তবে আমি বিশ্বাস করি যে ধারণাটি দাঁড়িয়েছে।


3

একটি চলমান গড় গণনা সম্পর্কে উপরে অনেক উত্তর রয়েছে। আমার উত্তর দুটি অতিরিক্ত বৈশিষ্ট্য যুক্ত করে:

  1. ন্যান মানগুলিকে উপেক্ষা করে
  2. N এর জন্য প্রতিবেশী মানগুলির স্বার্থের মান সহ নয় গণনা করে

এই দ্বিতীয় বৈশিষ্ট্যটি নির্দিষ্ট পরিমাণে সাধারণ ট্রেন্ডের থেকে কোন মানগুলি পৃথক করে তা নির্ধারণের জন্য বিশেষভাবে কার্যকর।

আমি 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)

এই কোডটি এমনকি এনএসের জন্যও কাজ করে। প্যাডে_এক্স এবং এন_নানের এনপি ইন্ডিট পরিবর্তন করে এটি বিজোড় সংখ্যার জন্য সামঞ্জস্য করা যেতে পারে।

উদাহরণস্বরূপ আউটপুট (কালো রঙের কাঁচা, নীল রঙের মুভাভ): কাঁচা ডেটা (কালো) এবং মুভিং এভারেজ (নীল) প্রতিটি মানকে ঘিরে 10 পয়েন্টের সাথে মানটি অন্তর্ভুক্ত নয়।  ন্যান মান অগ্রাহ্য করা হয়।

এই কোডটি সহজে কাটফ = 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)

কাঁচা ডেটা (কালো) এবং চলমান গড় (নীল) 3 টিরও কম ন্যান-মান সহ কোনও উইন্ডো উপেক্ষা করার সময়


2

কেবল পাইথন স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করুন (মেমরি দক্ষ)

কেবলমাত্র স্ট্যান্ডার্ড লাইব্রেরি ব্যবহারের অন্য একটি সংস্করণ দিন 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

তবে বাস্তবায়ন আমার কাছে মনে হওয়া উচিত এর চেয়ে কিছুটা জটিল। তবে এটি অবশ্যই স্ট্যান্ডার্ড পাইথন ডক্সে একটি কারণে থাকতে হবে, কেউ আমার এবং স্ট্যান্ডার্ড ডক বাস্তবায়নের বিষয়ে মন্তব্য করতে পারে?


2
একটি বড় পার্থক্য যা আপনি প্রতিটি পুনরাবৃত্তিতে উইন্ডো সদস্যদের সংশ্লেষ করে চলেছেন এবং তারা দক্ষতার সাথে যোগটি আপডেট করে (একটি সদস্যকে সরিয়ে অন্য জনকে যোগ করুন)। জটিলতার ক্ষেত্রে আপনি O(n*d) গণনা করছেন ( dউইন্ডোর nআকার, পুনরাবৃত্তের আকার) এবং তারা করছেনO(n)
ইফতাঃ

@ ইফতাঃ সুন্দর, ব্যাখ্যাটির জন্য ধন্যবাদ, আপনি ঠিক বলেছেন।
MaThMaX

2

@ আইকুডের ভেরিয়েবলের সাহায্যে আমি ওয়ান-লাইনার লিখেছি।

import numpy as np

mylist = [1, 2, 3, 4, 5, 6, 7]
N = 3

mean = [np.mean(mylist[x:x+N]) for x in range(len(mylist)-N+1)]
print(mean)

>>> [2.0, 3.0, 4.0, 5.0, 6.0]

1

যদিও এখানে এই প্রশ্নের সমাধান রয়েছে তবে আমার সমাধানটি একবার দেখুন। এটি খুব সাধারণ এবং ভালভাবে কাজ করছে।

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)

1

অন্যান্য উত্তরগুলি পড়া থেকে আমি মনে করি না যে এটিই প্রশ্নটি চেয়েছিল, তবে আকারে বাড়ছে এমন মানগুলির একটি তালিকার চলমান গড় রাখার প্রয়োজনে আমি এখানে এসেছি।

সুতরাং আপনি যদি কোথাও (সাইট, একটি পরিমাপের ডিভাইস ইত্যাদি) অর্জন করছেন এমন মানগুলির একটি তালিকা এবং সর্বশেষ 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()

যা দেয়:

মানগুলির কার্যকারিতা হিসাবে মানগুলি এবং তাদের গড়


1

কেবলমাত্র একটি স্ট্যান্ডার্ড লাইব্রেরি এবং ডিউক ব্যবহার করে অন্য একটি সমাধান:

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

1

শিক্ষাগত কাজের জন্য, আমাকে আরও দুটি নম্পি সমাধান যুক্ত করতে দিন (যা ক্লামসাম দ্রবণের চেয়ে ধীর)

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


1

পূর্বোক্ত সমস্ত সমাধান খুব কম কারণ তাদের অভাব রয়েছে

  • একটি অদ্ভুত ভেক্টরাইজড প্রয়োগের পরিবর্তে দেশীয় অজগরটির কারণে গতি,
  • 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)পঠনযোগ্য এবং সংখ্যাগতভাবে স্থিতিশীল।


1

একটি চলমান গড় ফিল্টার সম্পর্কে কী? এটি একটি ওয়ানলাইনার এবং এর সুবিধাও রয়েছে, আপনি যদি আয়তক্ষেত্রের চেয়ে অন্য কিছু প্রয়োজন, তবে উইন্ডো টাইপটি সহজেই পরিচালনা করতে পারেন। একটি অ্যারের একটি এন-দীর্ঘ সরল চলমান গড়:

lfilter(np.ones(N)/N, [1], a)[N:]

এবং ত্রিভুজাকার উইন্ডো প্রয়োগ করে:

lfilter(np.ones(N)*scipy.signal.triang(N)/N, [1], a)[N:]

দ্রষ্টব্য: আমি সাধারণত বোগাস হিসাবে প্রথম এন নমুনাগুলি [N:]শেষ পর্যন্ত বাতিল করে দিই , তবে এটি প্রয়োজনীয় নয় এবং কেবল একটি ব্যক্তিগত পছন্দের বিষয়।


-7

আপনি যদি কোনও বিদ্যমান লাইব্রেরি ব্যবহার না করে নিজের রোলটি বেছে নেন, দয়া করে ভাসমান পয়েন্ট ত্রুটির বিষয়ে সচেতন হন এবং এর প্রভাবগুলি হ্রাস করার চেষ্টা করুন:

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

আপনার সমস্ত মান যদি মোটামুটি একই পরিমাণের ক্রম হয়, তবে এটি সর্বদা মোটামুটি অনুরূপ দৈর্ঘ্যের মান যুক্ত করে নির্ভুলতা রক্ষা করতে সহায়তা করবে।


15
এটি একটি মারাত্মক অস্পষ্ট উত্তর, কমপক্ষে কিছু কোডে বা মন্তব্য কেন এটি ভাসমান পয়েন্ট ত্রুটিটি চমৎকার হতে পারে তার ব্যাখ্যা সম্পর্কে কিছু মন্তব্য।
গাবে

আমার শেষ বাক্যে আমি কেন এটি ভাসমান পয়েন্ট ত্রুটিতে সহায়তা করে তা নির্দেশ করার চেষ্টা করছিলাম। দুটি মান যদি প্রায় একই আকারের মাত্রার হয় তবে আপনি যুক্ত করে খুব সংখ্যক সংখ্যক সংখ্যক সংখ্যক সংখ্যক সংখ্যক সংখ্যক সংক্ষিপ্ত পরিমাণ হ'ল যদি আপনি খুব অল্প সংখ্যক সংখ্যক যুক্ত করে থাকেন তবে তার চেয়ে কম নির্ভুলতা হারাবেন। কোডটি "সংলগ্ন" মানগুলি এমনভাবে একত্রিত করে যে ভাসমান বিন্দু ত্রুটি হ্রাস করতে, মধ্যবর্তী অঙ্কগুলি সর্বদা প্রস্থের যথাযথভাবে কাছাকাছি হওয়া উচিত। কিছুই বোকা প্রমাণ নয় কিন্তু এই পদ্ধতিটি বেশ কয়েকজনকে খুব খারাপভাবে উত্পাদিত প্রকল্পগুলি সংরক্ষণ করেছে।
ময়ূর প্যাটেল

১. মূল সমস্যাটিতে প্রয়োগ করা হচ্ছে, এটি মারাত্মকভাবে ধীর হবে (গণনা গড়), সুতরাং এটি কেবল অপ্রাসঙ্গিক 64৪-বিট সংখ্যার যথার্থতার সমস্যায় ভুগতে, একটিকে যোগ করতে হবে >> প্রায় 2 ^ 30 সমান সংখ্যা
অ্যালোও

@ অ্যালিও: মান অনুসারে একটি সংযোজন করার পরিবর্তে আপনি দু'জন করে যাবেন। বিট-উল্টানো সমস্যার মতো প্রমাণ একই same যাইহোক, এই উত্তরের পয়েন্টটি অগত্যা পারফরম্যান্স নয়, তবে যথার্থতা। 64-বিট মানগুলির গড় গড়ের জন্য মেমরির ব্যবহার ক্যাশেতে 64 টি উপাদানকে অতিক্রম করবে না, সুতরাং এটি মেমরির ব্যবহারেও বন্ধুত্বপূর্ণ।
মায়ুর প্যাটেল

হ্যাঁ, আপনি ঠিক বলেছেন যে এটি সাধারণ অঙ্কের তুলনায় 2x আরও বেশি ক্রিয়াকলাপ গ্রহণ করে তবে মূল সমস্যাটি কেবল যোগফল নয়, গণনা চলমান মানে । যা ও (এন) এ করা যেতে পারে তবে আপনার উত্তরের জন্য ও (এমএন) প্রয়োজন, যেখানে মি উইন্ডোর আকার।
অ্যালোও
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.