統計的中央値、最頻値、歪度、尖度を推定するための「オンライン」(イテレーター)アルゴリズム?


86

値のセットの中央値、最頻値、歪度、および/または尖度を推定するアルゴリズムはありますが、すべての値を一度にメモリに保存する必要はありませんか?

基本的な統計を計算したいのですが:

  • 平均:算術平均
  • 分散:平均からの偏差の2乗の平均
  • 標準偏差:分散の平方根
  • 中央値:数値の大きい方の半分を小さい方の半分から分離する値
  • モード:セットで見つかった最も頻繁な値
  • 歪度:tl; 博士
  • 尖度:tl; 博士

これらのいずれかを計算するための基本的な式は、小学校の算数であり、私はそれらを知っています。それらを実装する多くの統計ライブラリもあります。

私の問題は、処理しているセット内の値の数が多い(数十億)ことです。Pythonで作業していると、数十億の要素でリストやハッシュを作成することはできません。これをCで書いたとしても、10億要素の配列はあまり実用的ではありません。

データはソートされていません。他のプロセスによって、オンザフライでランダムに生成されます。各セットのサイズは非常に可変であり、サイズは事前にわかりません。

セット内の各値を任意の順序で反復して、平均と分散をかなりうまく処理する方法をすでに理解しました。(実際、私の場合は、生成された順序でそれらを取得します。)これが私が使用しているアルゴリズムです。礼儀http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm

  • count、sum、sum_of_squaresの3つの変数を初期化します
  • 各値について:
    • インクリメントカウント。
    • 合計に値を追加します。
    • 値の2乗をsum_of_squaresに追加します。
  • 合計をカウントで除算し、変数の平均として保存します。
  • sum_of_squaresをカウントで除算し、変数mean_of_squaresとして格納します。
  • 二乗平均、square_of_meanとして保存。
  • mean_of_squaresからsquare_of_meanを減算し、分散として保存します。
  • 出力の平均と分散。

この「オンライン」アルゴリズムには弱点があります(たとえば、sum_of_squaresが整数範囲または浮動小数点精度よりも急速に大きくなるための精度の問題)が、基本的に、各セットにすべての値を格納する必要がなく、必要なものが得られます。

しかし、追加の統計(中央値、最頻値、歪度、尖度)を推定するための同様の手法が存在するかどうかはわかりません。N値を処理するために必要なメモリがO(N)よりも大幅に少ない限り、偏りのある推定量、またはある程度精度を損なう方法でさえ生きることができます。

ライブラリにこれらの操作の1つ以上を「オンライン」で計算する関数がある場合は、既存の統計ライブラリを指すことも役立ちます。


データはソートされて渡されますか?また、入力の数を事前に知っていますか?
chillysapien 2009年

StackOverflowの上の便利な既存のリンク:stackoverflow.com/questions/895929/...
dmckee ---元司会者の子猫

それは整数データですか、それとも浮動小数点データですか?最大値または最小値はありますか?
ステファン2009年

dmckee:私は実際に標準偏差にウェルフォードの方法を使用しています。しかし、そのリンクには、最頻値、中央値、尖度、または歪度について何も表示されません...何かが足りませんか?
ライアンB.リンチ

ステファン:一部のデータセットは整数であり、その他は浮動小数点数です。人口分布は正規分布(ガウス分布)にかなり近いため、信頼区間を確立できますが、ハードレンジの境界はありません(場合によってはx> 0を除く)。
ライアンB.リンチ

回答:


53

歪度と尖度

歪度と尖度のオンラインアルゴリズム(分散の線に沿って)については、同じwikiページを参照してください。高モーメント統計のための並列アルゴリズムを。

中央値

中央値は、ソートされたデータがないと厳しいです。知っている場合、データポイントの数は、理論的には、たとえば選択アルゴリズムを使用して、部分的に並べ替えるだけで済みます。しかし、それは何十億もの価値観にはあまり役立ちません。頻度カウントを使用することをお勧めします。次のセクションを参照してください。

頻度カウントを使用した中央値と最頻値

それが整数の場合、頻度を数え ます。おそらく、関連性がなくなったと確信できる値を超えて、最高値と最低値を切り取ります。浮動小数点数(または整数が多すぎる)の場合、おそらくバケット/間隔を作成してから、整数の場合と同じアプローチを使用します。(概算)モードと中央値の計算は、頻度テーブルに基づいて簡単になります。

正規分布確率変数

正規分布の場合、母集団のサンプル平均分散歪度尖度を小さなサブセットの最尤推定量として使用します。それらを計算するための(オンライン)アルゴリズム、あなたはすでに今です。たとえば、推定誤差が十分に小さくなるまで、数十万または数百万のデータポイントを読み込みます。セットからランダムに選択するようにしてください(たとえば、最初の100,000の値を選択することによってバイアスを導入しないようにします)。同じアプローチを使用して、通常の場合の最頻値と中央値を推定することもできます(両方のサンプル平均が推定量です)。

さらなるコメント

上記のすべてのアルゴリズム(QuickSortやQuickSelectなどの多くの並べ替えおよび選択アルゴリズムを含む)は、これが役立つ場合は並行して実行できます。

私は常に(正規分布のセクションを除いて)、既知の分布が与えられた場合の理論モーメントの推定量ではなく、サンプルモーメント、中央値、および最頻値について話すと想定してきました。

一般に、すべての観測値が同じ確率変数(同じ分布を持つ)とモーメント、最頻値、およびモーメントの実現である限り、データの量を考えると、データのサンプリング(つまり、サブセットのみを見る)はかなり成功するはずです。この分布の中央値は実際に存在します。最後の警告は無害ではありません。たとえば、コーシー分布の平均(およびすべてのより高いモーメント)は存在しません。この場合、「小さな」サブセットのサンプル平均は、サンプル全体のサンプル平均から大幅に外れている可能性があります。


57

私はこれらの増分/再帰平均および中央値推定量を使用します。どちらも一定のストレージを使用します。

mean += eta * (sample - mean)
median += eta * sgn(sample - median)

ここで、etaは小さな学習率パラメーター(例:0.001)であり、sgn()は{-1、0、1}のいずれかを返す符号関数です。(データが非定常であり、時間の経過に伴う変化を追跡する場合は、定数etaを使用します。それ以外の場合、定常ソースの場合、平均推定量にeta = 1 / nのようなものを使用できます。ここで、nは見られるサンプルの数です。はるかに...残念ながら、これは中央値推定量では機能しないようです。)

このタイプの増分平均推定量は、教師なしニューラルネットワーク学習ルールなど、あらゆる場所で使用されているようですが、中央値バージョンは、その利点(外れ値に対するロバスト性)にもかかわらず、あまり一般的ではないようです。中央値バージョンは、多くのアプリケーションで平均推定量の代わりに使用できるようです。

同様の形式のインクリメンタルモード推定器が見たいです...

更新

任意の分位数を推定するように増分中央値推定量を変更しました。一般に、分位関数(http://en.wikipedia.org/wiki/Quantile_function)は、データをpと1-pの2つの分数に分割する値を示します。以下では、この値を段階的に見積もります。

quantile += eta * (sgn(sample - quantile) + 2.0 * p - 1.0)

値pは[0,1]以内である必要があります。これにより、基本的にsgn()関数の対称出力{-1,0,1}が片側に傾くようにシフトし、データサンプルが2つの等しくないサイズのビンに分割されます(データの分数pと1-pはより小さい/より大きい)それぞれ、分位数の推定値)。p = 0.5の場合、これは推定量の中央値に減少することに注意してください。


3
この中央値推定量は素晴らしいです。0.25 / 0.75分位数に同様の推定量があるかどうか知っていますか?
Gacek 2010年

1
@Gacek、確かに:入力ストリームをLohalf <中央値とHihalf>中央値に分割し、各半分でrunning-medianを使用します。
denis 2010年

2
@Gacek:pを0.25、0.75、または[0,1]内の任意の値に設定できる、任意の分位数を推定するためのインクリメンタルメソッドで回答を更新しました。
タイラーストリーター2011

10
これは平均的にはうまく機能しますが、中央値に近いものがどのように生成されるかはわかりません。たとえば、ミリ秒のタイムスタンプのシーケンス[1328083200000, 981014400000, -628444800000, 318240000000, 949392000000]を考えてみましょう318240000000。中央値は。です。この式etaは、推奨値がであった前の中央値を+/-だけシフトします0.001。これは、このような大きな数には何の効果もありません。実際に小さな数には大きすぎる可能性があります。eta先験的に答えを知らなくても、実際に正しい答えが得られたものをどのように選びますか?
mckamey 2012年

9
数値にミリメートルなどの単位があると想像してください。次に、(中央値の推定のための)etaが測定値と同じ単位を持っている必要があることは明らかです。したがって、0.001のような一般的な値はまったく意味がありません。一見良いアプローチは、絶対偏差の実行中の推定値からetaを設定sampleすることcumadev += abs(sample-median)です。新しい値ごとに、を更新します。次に、を設定しますeta = 1.5*cumadev/(k*k)。ここで、kはこれまでに見られたサンプルの数です。
tholy 2013

12

LiveStatsと呼ばれるきちんとしたPythonモジュールに、観測値を保存せずに分位数とヒストグラムを動的に計算するためのP-Squareアルゴリズムを実装しました。それはあなたの問題を非常に効果的に解決するはずです。ライブラリは、モードを除いて、言及したすべての統計をサポートします。モード推定のための満足のいく解決策をまだ見つけていません。


参考:p-squareアルゴリズムはC ++ブーストにあります:<boost/accumulators/statistics/weighted_p_square_cumul_dist.hpp>
ニールG

7

ライアン、あなたは平均と分散を正しく行っていないのではないかと思います...これは数週間前にここで起こりました。そして、オンラインバージョン(実際にはウェルフォードの方法の名前で呼ばれています)の長所の1つは、それが特に正確で安定しているという事実ですここでの説明を参照してください。強みの1つは、総平方和または総平方和を格納する必要がないという事実です...

リスト全体を一度に検討する必要があると思われる最頻値と中央値へのオンラインアプローチは考えられません。しかし、分散と平均のアプローチと同様のアプローチが歪度と尖度にも機能する可能性があります...


re:skewness and kurtosisはい。:この記事を参照してくださいjohndcook.com/blog/skewness_kurtosis
ジェシー・チザム

3

質問で引用されているウィキペディアの記事には、歪度と尖度をオンラインで計算するための公式が含まれています。

モードの場合-私は信じています-これをオンラインで行う方法はありません。どうして?前の値と重複する最後の値を除いて、入力のすべての値が異なると想定します。この場合、最後の値が前に見た値と重複し、それが最も頻繁な値になることを検出するために、入力ですでに見られたすべての値を覚えておく必要があります。

中央値の場合、ほぼ同じです。最後の入力まで、すべての入力値が異なる場合、現在の中央値の前後にある可能性があるため、どの値が中央値になるかわかりません。入力の長さがわかっている場合は、すべての値をメモリに保存しなくても中央値を見つけることができますが、入力シーケンスが悪いと中央値が大幅にシフトする可能性があるため、それらの多くを保存する必要があります(おそらく半分程度)。後半はおそらく前半の中央値から任意の値を作成します。

(正確な計算のみを参照していることに注意してください。)


2

数十億のデータポイントがある場合、厳密な回答ではなく、正確な回答が必要になる可能性は低くなります。一般に、数十億のデータポイントがある場合、それらを生成する基礎となるプロセスは、ある種の統計的定常性/エルゴード性/混合特性に従う可能性があります。また、分布が適度に連続的であると期待するかどうかも重要になる場合があります。

このような状況では、正確な答えが必要ない場合は、オンライン、低メモリ、分位数の推定(中央値は0.5分位数の特殊なケース)、およびモードのアルゴリズムが存在します。これは統計のアクティブなフィールドです。

分位数の推定例:http//www.computer.org/portal/web/csdl/doi/10.1109/WSC.2006.323014

モード推定の例:BickelDR。連続データの最頻値と歪度のロバストな推定量。計算統計とデータ分析。2002; 39:153–163。土井:10.1016 / S0167-9473(01)00057-3。

これらは計算統計のアクティブなフィールドです。あなたは、単一の最良の正確なアルゴリズムは存在しないが、それらの多様性(実際には統計的推定量)があり、異なる特性、仮定、およびパフォーマンスを持っている分野に参入しています。それは実験数学です。この主題に関する論文はおそらく数百から数千あります。

最後の質問は、歪度と尖度自体が本当に必要かどうか、または確率分布を特徴付けるのにより信頼できる他のパラメーターが必要かどうかです(確率分布があると仮定します)。ガウス分布を期待していますか?

データをクリーンアップ/前処理して、ほとんどがガウス風にする方法はありますか?(たとえば、金融取引の金額は、対数を取った後、いくらかガウス分布になることがよくあります)。有限の標準偏差を期待していますか?あなたは太った尾を期待しますか?気になる量は尻尾ですか、それとも大量ですか?


2

オンラインでモードを実行することはできないと誰もが言い続けていますが、それは単に真実ではありません。これは、1982年にイェール大学のMichael E.FischerとStevenL.Salzbergによって発明されたまさにこの問題を実行するためのアルゴリズムを説明する記事です。記事から:

多数決アルゴリズムは、そのレジスタの1つを使用して、ストリームからの単一アイテムを一時的に保存します。このアイテムは、多数決要素の現在の候補です。2番目のレジスタは0に初期化されたカウンタです。ストリームの各要素について、アルゴリズムに次のルーチンを実行するように依頼します。カウンタが0を示している場合は、現在のストリーム要素を新しい多数決候補としてインストールします(すでにレジスタにある可能性のある他の要素を置き換えます)。次に、現在の要素が過半数の候補と一致する場合は、カウンターをインクリメントします。それ以外の場合は、カウンターをデクリメントします。サイクルのこの時点で、これまでに確認されたストリームの一部に多数決要素がある場合、その要素は候補レジスタにあり、カウンタは0より大きい値を保持します。多数決要素がない場合はどうなりますか?ストリーム環境では不可能な、データの2回目のパスを行わないと、この状況でアルゴリズムが常に明確な答えを出すとは限りません。多数決要素がある場合は、それを正しく識別することを約束するだけです。

より多くのメモリを備えた上位Nを見つけるように拡張することもできますが、これでモードが解決するはずです。


4
これは興味深いアルゴリズムですが、何かが足りない場合を除いて、すべての多数決値がモードになりますが、すべてのモードが多数決値になるわけではありません。
jkebinger 2013

リンクが切れたので、説明が入っていてよかったです。ただし、説明したように、カウンターは、多数派候補の2番目のオカレンスが1番目のオカレンスに隣接している場合にのみ増加します。どのIMPLIESがデータをソートしたか。これは、オンライン(ストリーミング)データの場合には保証されません。ランダムに順序付けられたデータでは、これがモードを見つける可能性はほとんどありません。
ジェシーチザム

1

最終的に、分布に関する事前のパラメトリック知識がない場合は、すべての値を保存する必要があると思います。

とは言うものの、ある種の病的状況に対処しているのでない限り、救済策(Rousseuw and Bassett 1990)はあなたの目的には十分かもしれません。

非常に簡単に言えば、中央値のバッチの中央値を計算する必要があります。


0

中央値と最頻値は、利用可能な一定のスペースのみを使用してオンラインで計算することはできません。ただし、中央値と最頻値は「定量的」よりも「記述的」であるため、データセットをサンプリングするなどして推定できます。

データが長期的に正規分布している場合は、平均を使用して中央値を推定できます。

次の手法を使用して中央値を推定することもできます。たとえば、データストリーム内の1,000,000エントリごとに中央値推定M [i]を確立して、M [0]が最初の100万エントリの中央値M [1]になるようにします。 2番目の100万エントリの中央値など。次に、M [0] ... M [k]の中央値を中央値推定値として使用します。もちろん、これによりスペースが節約され、パラメーター1,000,000を「調整」することで、スペースを使用する量を制御できます。これは再帰的に一般化することもできます。


0

OK男はこれらを試してみてください:

C ++の場合:

double skew(double* v, unsigned long n){
    double sigma = pow(svar(v, n), 0.5);
    double mu = avg(v, n);

    double* t;
    t = new double[n];

    for(unsigned long i = 0; i < n; ++i){
        t[i] = pow((v[i] - mu)/sigma, 3);
    }

    double ret = avg(t, n);

    delete [] t;
    return ret;
}

double kurt(double* v, double n){
    double sigma = pow(svar(v, n), 0.5);
    double mu = avg(v, n);

    double* t;
    t = new double[n];

    for(unsigned long i = 0; i < n; ++i){
        t[i] = pow( ((v[i] - mu[i]) / sigma) , 4) - 3;
    }

    double ret = avg(t, n);

    delete [] t;
    return ret;
}

ここで、サンプル分散(svar)と平均(avg)をすでに計算できると言う場合は、それらを関数にポイントしてそれを実行します。

また、ピアソンの近似値もご覧ください。このような大きなデータセットでは、かなり似ています。3(平均-中央値)/中央値が最大-最小/ 2の標準偏差

フロートモードの場合は意味がありません。通常、それらをかなりのサイズのビンに貼り付けます(1/100 *(最大-最小)など)。



-1

私は、適応性のあるバケットを使用する傾向があります。バケットサイズは、必要な精度である必要があります。次に、各データポイントが到着したら、関連するバケットの数に1を追加します。これらは、各バケットをそのカウントで重み付けされた値としてカウントすることにより、中央値と尖度の簡単な概算を提供するはずです。

1つの問題は、数十億回の操作後の浮動小数点の解像度の低下である可能性があります。つまり、1を追加しても、値はそれ以上変更されません。これを回避するには、最大バケットサイズが制限を超えている場合、すべてのカウントから多数を削除できます。


-1
for j in range (1,M):
    y=np.zeros(M) # build the vector y
    y[0]=y0

    #generate the white noise
    eps=npr.randn(M-1)*np.sqrt(var)

    #increment the y vector
    for k in range(1,T):
        y[k]=corr*y[k-1]+eps[k-1]

    yy[j]=y

list.append(y)

これを元の質問によりよく結び付けるために、いくつかの説明を使用できます。
エリカ2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.