2013-02-11 2 views
5

Bạn có thể làm như thế nào trong RX một biến đổi đơn giản, trạng thái của một chuỗi?RX: Biến đổi trạng thái của chuỗi, ví dụ: trung bình di động theo cấp số nhân

Giả sử chúng tôi muốn thực hiện chuyển đổi trung bình chuyển động theo hàm mũ của IObservable noisySequence.

Bất cứ khi nào noisySequence ve, emaSequence nên đánh dấu vào và trả về giá trị (previousEmaSequenceValue * (1-lambda) + latestNoisySequenceValue * lambda)

Tôi đoán chúng tôi sử dụng Đối tượng, nhưng làm thế nào chính xác?

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

Để làm rõ, tôi ít quan tâm đến một phương pháp cụ thể để thực hiện một cách trung bình, nhưng thay vì chung chung để thực hiện chuyển đổi trạng thái. – Sputnik2513

Trả lời

3

Đối với nhiều người của các loại tính toán, Buffer là cách dễ nhất

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

Nếu bạn cần để thực hiện nhà nước xung quanh, sử dụng Scan điều hành, mà là giống như Aggregate ngoại trừ việc nó mang lại giá trị mỗi lặp lại.

+0

Hoạt động trong ví dụ cụ thể này về mức trung bình. Nói chung, nếu chúng ta cần các trạng thái bên trong, cách tốt nhất để thực hiện nó trong RX? – Sputnik2513

+0

Ngoài ra không có trạng thái. Để thực hiện trung bình di động theo hàm mũ, bạn cần biết giá trị cuối cùng của EMA. – Sputnik2513

+0

Như Paul đã nói, bạn có thể sử dụng tính năng Quét cho phép bạn tổng hợp liên tục bằng cách bắt đầu bằng "trạng thái" giống và thực hiện một số hành động trên trạng thái đó cho mỗi OnNext. Sau đó, bạn có thể chọn từ trạng thái giá trị bạn muốn xuất bản ra khỏi chuỗi. Tuy nhiên, nếu bạn cần truy cập nhiều hơn chỉ tổng hợp hiện tại và giá trị mới nhất, thì các toán tử Window có thể sử dụng. –

7

Đây là cách bạn có thể đính kèm trạng thái vào chuỗi. Trong trường hợp này, nó tính giá trị trung bình của 10 giá trị cuối cùng.

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()); 

Nhưng bạn có thể sử dụng Window (bộ đệm là loại tổng quát) để đạt được mức trung bình.

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

Tiếp tuyến: các bài viết của bạn về 'Window',' Buffer', 'Join' và' GroupJoin' cực kỳ sáng - trên thực tế, tôi tin rằng tôi đã 'trích dẫn' bạn một số lần trả lời các câu hỏi liên quan đến Rx. :) – JerKimball

1

Cảm ơn! Đây là giải pháp sử dụng Quét

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