20

さらに処理する前に外れ値を削除するために、データセットのおおよそのパーセンタイル(順序統計量)を繰り返し計算する必要があるプログラムがあります。私は現在、値の配列を並べ替えて適切な要素を選択することでこれを行っています。これは実行可能ですが、プログラムのかなりマイナーな部分であるにもかかわらず、プロファイルの目立ったブリップです。

より詳しい情報:

  • データセットには最大100000の浮動小数点数が含まれ、「合理的に」分散されていると想定されます。特定の値の近くで密度が重複したり、大きなスパイクが発生したりする可能性はほとんどありません。また、何らかの奇妙な理由で分布が奇妙な場合は、データがとにかく混乱し、さらに処理が疑わしいため、近似の精度が低くても問題ありません。ただし、データは必ずしも均一または正規分布しているとは限りません。退化する可能性は非常に低いです。
  • 近似解は問題ありませんが、それが有効であることを確認するには、近似がどのようにエラーを引き起こすかを理解する必要があります。
  • 外れ値を削除することが目的なので、常に同じデータに対して2つのパーセンタイルを計算しています。たとえば、1つは95%、もう1つは5%です。
  • アプリはC#であり、C++では少し手間がかかります。擬似コードまたはいずれかの既存のライブラリで問題ありません。
  • 外れ値を削除するまったく異なる方法も、合理的である限り問題ありません。
  • 更新:おおよその選択アルゴリズムを探しているようです。

これはすべてループで実行されますが、データは毎回(わずかに)異なるため、この質問で行ったようにデータ構造を再利用するのは簡単ではありません。

実装されたソリューション

Gronimが提案したウィキペディア選択アルゴリズムを使用すると、実行時間のこの部分が約20分の1に短縮されました。

C#の実装が見つからなかったので、これが私が思いついたものです。Array.Sortよりも小さな入力でも高速です。そして1000要素でそれは25倍速くなります。

public static double QuickSelect(double[] list, int k) {
    return QuickSelect(list, k, 0, list.Length);
}
public static double QuickSelect(double[] list, int k, int startI, int endI) {
    while (true) {
        // Assume startI <= k < endI
        int pivotI = (startI + endI) / 2; //arbitrary, but good if sorted
        int splitI = partition(list, startI, endI, pivotI);
        if (k < splitI)
            endI = splitI;
        else if (k > splitI)
            startI = splitI + 1;
        else //if (k == splitI)
            return list[k];
    }
    //when this returns, all elements of list[i] <= list[k] iif i <= k
}
static int partition(double[] list, int startI, int endI, int pivotI) {
    double pivotValue = list[pivotI];
    list[pivotI] = list[startI];
    list[startI] = pivotValue;

    int storeI = startI + 1;//no need to store @ pivot item, it's good already.
    //Invariant: startI < storeI <= endI
    while (storeI < endI && list[storeI] <= pivotValue) ++storeI; //fast if sorted
    //now storeI == endI || list[storeI] > pivotValue
    //so elem @storeI is either irrelevant or too large.
    for (int i = storeI + 1; i < endI; ++i)
        if (list[i] <= pivotValue) {
            list.swap_elems(i, storeI);
            ++storeI;
        }
    int newPivotI = storeI - 1;
    list[startI] = list[newPivotI];
    list[newPivotI] = pivotValue;
    //now [startI, newPivotI] are <= to pivotValue && list[newPivotI] == pivotValue.
    return newPivotI;
}
static void swap_elems(this double[] list, int i, int j) {
    double tmp = list[i];
    list[i] = list[j];
    list[j] = tmp;
}

パフォーマンスグラフ

グロニム、私を正しい方向に向けてくれてありがとう!

4

10 に答える 10

9

Henrikのヒストグラムソリューションが機能します。選択アルゴリズムを使用して、O(n)のn個の要素の配列からk個の最大または最小の要素を効率的に見つけることもできます。これを95パーセンタイルに使用するには、k = 0.05nを設定し、k個の最大要素を見つけます。

参照:

http://en.wikipedia.org/wiki/Selection_algorithm#Selecting_k_smallest_or_largest_elements

于 2010-09-23T15:29:24.767 に答える
6

その作成者によると、 SoftHeapは次の目的で使用できます。

正確または近似の中央値とパーセンタイルを最適に計算します。おおよその並べ替えにも役立ちます...

于 2010-09-23T16:00:58.913 に答える
5

以前は、標準偏差を計算して外れ値を特定していました。平均からの標準偏差の2(または3)倍を超える距離を持つものはすべて外れ値です。2回=約95%。

平均を計算しているので、標準偏差の計算も非常に簡単です。

データのサブセットのみを使用して数値を計算することもできます。

于 2010-09-23T15:23:41.817 に答える
4

最初の数千ポイントのように、データセットの一部からパーセンタイルを推定できます。

Glivenko–Cantelliの定理は、データポイントが独立していると仮定できる場合、これがかなり適切な推定値になることを保証します。

于 2010-09-23T15:22:57.927 に答える
3

データの最小値と最大値の間の間隔を(たとえば)1000のビンに分割し、ヒストグラムを計算します。次に、部分的な合計を作成し、それらが最初に5000または95000を超える場所を確認します。

于 2010-09-23T15:16:19.540 に答える
1

私が考えることができるいくつかの基本的なアプローチがあります。最初に、範囲を計算し(最大値と最小値を見つけることによって)、各要素をパーセンタイル((x --min)/範囲)に投影し、.05未満または.95より高いと評価されたものをすべて破棄します。

2つ目は、平均と標準偏差を計算することです。平均からの2標準偏差のスパン(両方向)は、正規分布のサンプル空間の95%を囲みます。つまり、外れ値は<2.5および>97.5パーセンタイルになります。級数の平均の計算は、標準偏差(各要素の差と平均の合計の平方根)と同様に線形です。次に、平均から2シグマを減算し、平均に2シグマを加算すると、外れ値の制限が得られます。

これらは両方ともほぼ線形の時間で計算されます。最初のパスには2つのパスが必要で、2番目のパスには3つのパスが必要です(制限がある場合でも、外れ値を破棄する必要があります)。これはリストベースの操作であるため、対数または一定の複雑さを持つものは見つからないと思います。さらにパフォーマンスを向上させるには、反復と計算を最適化するか、サブサンプル(3つおきの要素など)で計算を実行してエラーを発生させる必要があります。

于 2010-09-23T15:23:19.943 に答える
1

データが正規分布していない場合でも、2または3の標準偏差を除外できます。少なくとも、それは一貫した方法で行われるので、それは重要なはずです。

外れ値を削除すると、std devが変更されます。これは、stddevの変更が最小限になるまでループで実行できます。これを実行するかどうかは、データをこのように操作する理由によって異なります。一部の統計家は、外れ値を削除することについて大きな懸念を抱いています。ただし、データがかなり正規分布していることを証明するために外れ値を削除するものもあります。

于 2010-09-23T18:28:37.613 に答える
1

あなたの問題に対する良い一般的な答えはRANSACのようです。モデルといくつかのノイズの多いデータが与えられると、アルゴリズムはモデルのパラメーターを効率的に回復します。
データをマッピングできる単純なモデルを選択する必要があります。スムーズなものなら何でも問題ありません。少数のガウス分布が混在しているとしましょう。RANSACは、モデルのパラメーターを設定し、同時に一連のインライナーを推定します。次に、モデルに適切に適合しないものはすべて破棄します。

于 2010-09-23T17:00:26.877 に答える
0

専門家ではありませんが、私の記憶は次のことを示唆しています。

  • パーセンタイルポイントを正確に決定するには、並べ替えてカウントする必要があります
  • データからサンプルを取得してパーセンタイル値を計算することは、適切なサンプルを取得できれば、適切な近似の適切な計画のように思えます。
  • そうでない場合は、Henrikが提案しているように、バケットを実行してカウントすると、完全な並べ替えを回避できます。
于 2010-09-23T15:22:19.880 に答える
0

10万要素の1セットのデータはソートにほとんど時間がかからないので、これを繰り返し行う必要があると思います。データセットがわずかに更新された同じセットである場合は、ツリーを構築し(O(N log N))、新しいポイントが入ってくるときに削除および追加することをお勧めします(ポイントO(K log N)K数は変更されます)。それ以外の場合は、kすでに説明した3番目に大きい要素ソリューションがO(N)各データセットに対して提供します。

于 2010-09-23T17:30:58.690 に答える