3

時系列の移動中央値を計算する方法があります。移動平均と同様に、固定ウィンドウまたは期間 (ルックバック期間と呼ばれることもあります) を使用します。期間が 10 の場合、最初の 10 個の値 (0 ~ 9) の配列を作成し、それらの中央値を見つけます。これを繰り返し、ウィンドウを 1 ステップ (現在は 1 ~ 10 の値) ずつインクリメントします... したがって、これの可動部分です。これは、移動平均とまったく同じプロセスです。

中央値は次のように求められます。

  1. 配列の値のソート
  2. 配列に奇数個の値がある場合は、中央の値を取ります。5 つの値の並べ替えられた配列の中央値は、3 番目の値になります。
  3. 配列に偶数の値がある場合は、中央の両側にある 2 つの値を取り、それらを平均します。6 つの値の並べ替えられた配列の中央値は、(2 番目 + 3 番目) / 2 になります。

List<double>にデータを入力し、 を呼び出しList<>.Sort()、適切な値を見つけることで、これを計算する関数を作成しました。

計算上は正しいですが、この計算のパフォーマンスを向上させる方法があるかどうか疑問に思っていました。double[]おそらく、リストを使用するのではなく、手動で並べ替えを行うことによって。

私の実装は次のとおりです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Moving_Median_TimeSeries
{
    class Program
    {
        static void Main(string[] args)
        {
            // created a a sample test time series of 10 days
            DateTime Today = DateTime.Now;
            var TimeSeries = new SortedList<DateTime, double>();
            for (int i = 0; i < 10; i++)
                TimeSeries.Add(Today.AddDays(i), i * 10);

            // write out the time series
            Console.WriteLine("Our time series contains...");
            foreach (var item in TimeSeries) 
                Console.WriteLine("   {0}, {1}", item.Key.ToShortDateString(), item.Value);

            // calculate an even period moving median 
            int period = 6;
            var TimeSeries_MovingMedian = MovingMedian(TimeSeries, period);

            // write out the result of the calculation
            Console.WriteLine("\nThe moving median time series of {0} periods contains...", period);
            foreach (var item in TimeSeries_MovingMedian)
                Console.WriteLine("   {0}, {1}", item.Key.ToShortDateString(), item.Value);

            // calculate an odd period moving median 
            int period2 = 5;
            var TimeSeries_MovingMedian2 = MovingMedian(TimeSeries, period);

            // write out the result of the calculation
            Console.WriteLine("\nThe moving median time series of {0} periods contains...", period2);
            foreach (var item in TimeSeries_MovingMedian2)
                Console.WriteLine("   {0}, {1}", item.Key.ToShortDateString(), item.Value);
        }

        public static SortedList<DateTime, double> MovingMedian(SortedList<DateTime, double> TimeSeries, int period)
        {
            var result = new SortedList<DateTime, double>();

            for (int i = 0; i < TimeSeries.Count(); i++)
            {
                if (i >= period - 1)
                {
                    // add all of the values used in the calc to a list... 
                    var values = new List<double>();
                    for (int x = i; x > i - period; x--)
                        values.Add(TimeSeries.Values[x]);

                    // ... and then sort the list <- there might be a better way than this
                    values.Sort();

                    // If there is an even number of values in the array (example 10 values), take the two mid values
                    // and average them.  i.e. 10 values = (5th value + 6th value) / 2. 
                    double median;
                    if (period % 2 == 0) // is any even number
                        median = (values[(int)(period / 2)] + values[(int)(period / 2 - 1)]) / 2;
                    else // is an odd period
                    // Median equals the middle value of the sorted array, if there is an odd number of values in the array
                        median = values[(int)(period / 2 + 0.5)];

                    result.Add(TimeSeries.Keys[i], median);
                }
            }
            return result;
        }

    }
}
4

2 に答える 2

0

N 個のアイテムのリストと期間 P の場合、すべてのアイテムのリストを再ソートするアルゴリズムは O(N * P lgP) です。2ヒープを使用する O(N * lg P) アルゴリズムがあります。

中央値より上の P/2 アイテムを含む最小ヒープと、それ以下の PP/2 アイテムを含む最大ヒープを使用します。新しいデータ項目を取得するたびに、最も古い項目を新しい項目に置き換えてから、シフトアップまたはシフトダウンを実行して正しい場所に移動します。新しいアイテムがいずれかのヒープのルートに到達した場合は、それを他のヒープのルートと比較し、必要に応じて交換してふるいにかけます。P が奇数の場合、中央値は最大ヒープのルートにあります。偶数 P の場合は、両方の根の平均です。

この質問にはc の実装があります。これを実装する上で難しい部分の 1 つは、最も古いアイテムを効率的に追跡することです。その部分のオーバーヘッドにより、P が小さい場合、速度の向上が取るに足らないものになる場合があります。

于 2011-06-20T20:07:46.753 に答える
0

これよりも良い方法があるかもしれません

これについては正しいです。中央値だけが必要な場合は、リスト全体を並べ替える必要はありません。詳細については、このウィキペディア ページのリンクをたどってください。

于 2011-03-09T12:14:31.930 に答える