6

如何在 RX 中对序列进行简单的、有状态的转换?

假设我们想要对 IObservable 噪声序列进行指数移动平均变换。

每当噪声序列滴答时,emaSequence 应该滴答并返回值 (previousEmaSequenceValue*(1-lambda) + latestNoisySequenceValue*lambda)

我想我们使用主题,但究竟如何?

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

3 回答 3

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

但是您也可以使用 Window (其中 Buffer 是一种概括)来获得您的平均值。

noisySequence.Window(10)
   .Select(window=>window.Average())
   .SelectMany(averageSequence=>averageSequence);
于 2013-02-11T14:20:27.960 回答
4

对于许多这些类型的计算,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它每次迭代都会产生值一样。

编辑:固定评论语法

于 2013-02-11T03:32:45.700 回答
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);
于 2013-02-11T15:16:09.493 回答