実行中の中央値を計算するアルゴリズム?


18

小さいウィンドウサイズでは、n log nソートが機能する場合があります。これを達成するためのより良いアルゴリズムはありますか?


1
これがスタックオーバーフローに移行する最初の候補だと思います。

おそらく、しかし、SOについてもっと多くの説明が必要でしょう。
walkytalky

2
ほとんどのプログラマーは「中央値」を知っています。(sort(array))[length / 2]は、忘れた人にとっては十分に大きなヒントです。また、あなただけのアレイの半分の二分/挿入を行う必要があり、各新しいポイントのための最も基本的で...
ポール・


2
コメントよりも簡単ですが、中央値3のコードはa + b + c-max(a、b、c)-min(a、b。c)です。関係が存在していても問題ありません。他の誰かのコードから考えてみたら(この場合、彼は中央値を得るために加算と減算を行うのはなぜですか?)max()およびmin()は、しばしば超高速関数として実装されます。悲しいことに、一般的にそのようなトリックはありません。
ニックコックス

回答:


11

中央値を計算するために配列をソートするのは悪い形式です。中央値(および他の変位値)は、通常、複雑さを持つクイック選択アルゴリズムを使用して計算されます。On

また、最近の関連する質問への私の答えもご覧ください


7

ここでは一つの可能なアルゴリズムを説明した記事です。ソースコードが含まれており、非常に深刻なアプリケーション(レーザー干渉法に基づく重力波検出)であるため、十分にテストされることが期待できます。


1
リンクが壊れており、タイトルや著者の情報がないと、参照先を見つけるのが困難です。
クリストファージョンソン


6

近似値を許容する場合は、他の方法があります。たとえば、1つの近似値は、ランクが真の中央値から(ユーザー指定の)距離内にある値です。たとえば、中央値のランクは(正規化された)ランク0.5であり、10%のエラー項を指定した場合、ランクが0.45〜0.55の回答が必要になります。

そのような答えが適切な場合、データのスライディングウィンドウで機能する多くのソリューションがあります。基本的な考え方は、特定のサイズ(ほぼ1 /エラー項)のデータのサンプルを維持し、このサンプルの中央値を計算することです。入力の性質に関係なく、高い確率で、結果の中央値が上記の特性を満たすことが示されます。

したがって、主な問題は、特定のサイズのデータ​​の実行中のサンプルをどのように維持するかということであり、そのための多くのアプローチがあります。たとえば、このペーパー:http : //citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.24.7136


4

データの長さkのウィンドウをソートされた二重リンクリストとして維持する場合、バイナリ検索(ウィンドウにシフトされるたびに新しい要素を挿入する)とポインターの循環配列(すぐに要素を見つける削除する必要があります)、ウィンドウの各シフトには、1つの要素を挿入するためのO(log(k))努力、ウィンドウからシフトした要素を削除するためのO(1)努力、および見つけるためのO(1)努力のみが必要です中央値(1つの要素がリストに挿入または削除されるたびに、O(1)時間で中央値へのポインタを更新できます)。したがって、長さNの配列を処理するための総労力はO((nk)log(k))<= O(n log(k))です。これはこれまでに提案された他のどの方法よりも優れており、近似ではなく、正確です。


1
ソートされた二重リンクリストでバイナリ検索を行うことを提案する方法について詳しく説明していただけますか?
NPE

1つの「リンク」により、リストをソート順にトラバースできます。もう1つは、要素が現れる順序でトラバースすることを可能にします。しかし、@ aixの質問のように、ポインターを使用してこれを行う方法は明確ではありません。
シャビーシェフ

2
@aixあなたの暗示は正しいと思います。並べ替えられた二重リンクリストだけでなく、インデックス付け可能なスキップリストが必要です。アイデアは、1つの要素の挿入、1つの要素の削除、および予想されるO(log(n))時間(またはそれ以上)での中央値の検出を許可するデータ構造を持つことです。
whuber

3

あなたが述べたように、ソートはO(n·log n)長さのウィンドウのためのものnです。この移動をするl=vectorlengthことは、総費用を作る別を追加しますO(l·n·log n)

これをプッシュする最も簡単な方法は、あるウィンドウから次のウィンドウに移動するときに、メモリ内の最後のn個の要素の順序付きリストを保持することです。1つの要素を順序付きリストから削除したり、リストに挿入したりすると、両方のO(n)コストが発生しますO(l·n)

擬似コード:

l = length(input)
aidvector = sort(input(1:n))
output(i) = aid(n/2)
for i = n+1:l
    remove input(i-n) from aidvector
    sort aid(n) into aidvector
    output(i) = aid(n/2)


2

真の中央値の代わりに推定値で生きることができる場合、Remedian Algorithm(PDF)は、ストレージ要件が低く、正確に定義されたワンパスです。

基数bのレメディアンは、b個の観測値のグループの中央値を計算し、次にこれらの中央値の中央値を、単一の推定値のみが残るまで計算します。このメソッドは、サイズbのk個の配列(n = b ^ k)を必要とします...


0

このRunningStats C ++ライブラリを組み込みアプリケーションで使用しました。これは、私がこれまでに見つけた中で最も単純な実行統計ライブラリです。

リンクから:

このコードは、データの1回のパスで標準偏差を計算するためのKnuth and Welfordのメソッドの拡張です。同様のインターフェースで歪度と尖度も計算します。データを1回だけ通過するだけでなく、アルゴリズムは数値的に安定しており、正確です。


そのページは中央値について何か言っていますか?
ムシフィル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.