6

RX でシーケンスの単純なステートフルな変換を行うにはどうすればよいでしょうか?

IObservable noiseSequence の指数移動平均変換を行いたいとします。

NoiseSequence がティックするたびに、emaSequence はティックして値を返す必要があります (previousEmaSequenceValue*(1-lambda) + latestNoisySequenceValue*lambda)

Subjects を使用していると思いますが、具体的にはどうすればよいでしょうか?

    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 に答える