2013-02-11 28 views
5

आरएक्स में आप अनुक्रम के एक सरल, राज्यव्यापी परिवर्तन कैसे कर सकते हैं?आरएक्स: अनुक्रम का राज्यगत परिवर्तन, उदा। घातीय चलती औसत

कहें कि हम एक IObservable शोर की आवश्यकता का एक घातीय चलती औसत परिवर्तन करना चाहते हैं।

जब भी noisySequence टिक्स, emaSequence टिकटिक और वापसी मूल्य (previousEmaSequenceValue * (1-लैम्ब्डा) + latestNoisySequenceValue * लैम्ब्डा)

मुझे लगता है कि हम विषय का उपयोग करें, लेकिन कैसे वास्तव में होना चाहिए?

public static void Main() 
    { 

     var rand = new Random(); 

     IObservable<double> sequence = Observable 
      .Interval(TimeSpan.FromMilliseconds(1000)) 
      .Select(value => value + rand.NextDouble()); 

     Func<double, double> addNoise = x => x + 10*(rand.NextDouble() - 0.5); 

     IObservable<double> noisySequence = sequence.Select(addNoise); 

     Subject<double> exponentialMovingAverage = new Subject<double>(); // ??? 


     sequence.Subscribe(value => Console.WriteLine("original sequence "+value)); 
     noisySequence.Subscribe(value => Console.WriteLine("noisy sequence " + value)); 
     exponentialMovingAverage.Subscribe(value => Console.WriteLine("ema sequence " + value)); 

     Console.ReadLine(); 
    } 
+1

स्पष्ट करने के लिए, मुझे औसत करने के लिए एक विशिष्ट विधि में दिलचस्पी नहीं है, बल्कि राज्यव्यापी परिवर्तन करने के सामान्य तरीकों से मुझे कोई रूचि नहीं है। – Sputnik2513

उत्तर

3

गणना के इन प्रकार के कई के लिए, Buffer सबसे आसान तरीका है

var movingAverage = noisySequence.Buffer(/*last*/ 3, /*move forward/* 1 /*at a time*/) 
    .Select(x => (x[0] + x[1] + x[2])/3.0); 

आप के चारों ओर ले जाने के लिए राज्य, Scan ऑपरेटर, जो सिवाय यह मान हर पैदावार कि Aggregate की तरह है का उपयोग की जरूरत है है यात्रा।

+0

यह औसत के इस विशिष्ट उदाहरण में काम करता है। अधिक आम तौर पर, अगर हमें आंतरिक राज्यों की आवश्यकता है, तो आरएक्स में इसे कैसे करना है? – Sputnik2513

+0

इसके अलावा इसमें कोई राज्य नहीं है। एक घातीय चलती औसत को लागू करने के लिए, आपको ईएमए के अंतिम मूल्य को जानने की आवश्यकता है। – Sputnik2513

+0

जैसा पौलुस ने कहा था, आप स्कैन का उपयोग कर सकते हैं जो आपको बीज "राज्य" से शुरू करके और प्रत्येक ऑननेक्स्ट के लिए उस स्थिति पर कुछ कार्रवाई करने के लिए उड़ान भरने की अनुमति देता है। फिर आप राज्य से उस मूल्य का चयन कर सकते हैं जिसे आप अनुक्रम से प्रकाशित करना चाहते हैं। यदि आपको वर्तमान कुल और नवीनतम मूल्य से अधिक तक पहुंच की आवश्यकता है, तो विंडो ऑपरेटर का उपयोग शायद हो सकता है। –

7

इस प्रकार आप एक अनुक्रम में राज्य को जोड़ सकते हैं। इस मामले में यह पिछले 10 मानों के औसत की गणना करता है।

var movingAvg = noisySequence.Scan(new List<double>(), 
(buffer, value)=> 
{ 
    buffer.Add(value); 
    if(buffer.Count>MaxSize) 
    { 
     buffer.RemoveAt(0); 
    } 
    return buffer; 
}).Select(buffer=>buffer.Average()); 

लेकिन आप अपना औसत प्राप्त करने के लिए विंडो (जो बफर एक सामान्यीकरण का प्रकार है) का उपयोग कर सकते हैं।

noisySequence.Window(10) 
    .Select(window=>window.Average()) 
    .SelectMany(averageSequence=>averageSequence); 
+0

टेंगेंशियल: 'विंडो', 'बफर', 'जॉइन' और 'ग्रुपजॉइन' के बारे में आपके लेख बेहद रोशनी वाले थे - वास्तव में, मेरा मानना ​​है कि मैंने आपको कई बार आरएक्स से संबंधित प्रश्नों का उत्तर देने के लिए उद्धृत किया है। :) – JerKimball

1

धन्यवाद! स्कैन

const double lambda = 0.99; 
    IObservable<double> emaSequence = noisySequence.Scan(Double.NaN, (emaValue, value) => 
     { 
      if (Double.IsNaN(emaValue)) 
      { 
       emaValue = value; 
      } 
      else 
      { 
       emaValue = emaValue*lambda + value*(1-lambda); 
      } 
      return emaValue; 
     }).Select(emaValue => emaValue);