2012-04-09 11 views
2

私は、アウトライアを定義したり除外したりするために、約4百万行のデータセットが急激に増加しています(統計/解析用)このデータセットでしかし、これはあまりにも多くのデータをメモリにロードして、私のシステムはチョークします。私は現在、データを収集し処理するために、これを使用しています:データセットが大きすぎて処理のためにメモリにロードできない

@scoreInnerFences = innerFence Post.where(:source => 1). 
            order(:score). 
            pluck(:score) 

を典型的な分割統治法は動作しません使用して、すべてのエントリは、正確な私の外れ値の計算を維持するために考慮しなければならないので、私は考えていません。どのようにこれを効率的に達成することができますか?

innerFenceは、データセットの下位四分位および上四分位を識別し、これらの結果を使用して異常値を計算します。大きなデータセットについて

def q1(s) 
    q = s.length/4 

    if s.length % 2 == 0 
    return (s[ q ] + s[ q - 1 ])/2 
    else 
    return s[ q ] 
    end 
end 

def q2(s) 
    q = s.length/4 

    if s.length % 2 == 0 
    return (s[ q * 3 ] + s[ (q * 3) - 1 ])/2 
    else 
    return s[ q * 3 ] 
    end 
end 

def innerFence(s) 
    q1 = q1(s) 
    q2 = q2(s) 

    iq = (q2 - q1) * 3 

    if1 = q1 - iq 
    if2 = q2 + iq 

    return [if1, if2] 
end 
+1

'innerFence'とは何ですか?明らかな答えは、Rubyではなくデータベース内の 'innerFence'で何をしているのかを行うことですが、それが可能かどうかは' innerFence'の実際の実装に依存します。 –

+0

これは、私のデータセットの下位および上位の四分位数を特定して、外れ値を計算しています。最後の編集でソースを追加しました。 –

答えて

1

これが最善の方法ではありませんが、それは簡単な方法です:

には、いくつかのquerysを行います。

Q = Post.where(:ソース=> 1)あなたは、あなたの計算 を行い、その後、あなたが

Q1 = Post.whereスコアをフェッチ

を.countまず、スコアの数がカウント(:source => 1)。 reverse_order(:score) select( "スコアとしての平均(score)")。 オフセット(q).limit((q%2)+1)

q2 = Post.where(:source => 1)。 reverse_order(:score) select( "スコアとしての平均(score)")。 オフセット(q * 3).limit((q%2)+1)

コードは間違っているかもしれませんが、私はあなたがそのアイデアを得ると確信しています。

+0

このルートははるかに良く機能し、すべてのデータをレールに読み込むのではなく、カウントに基づいて四分円を選択することで動作させることができました。ありがとう! –

+0

うれしかったよ!誰かがこれを行うのと同時にデータを挿入している場合は、おそらくトランザクションでそれをラップしたいと思うでしょう。 –

0

、私は時々のActiveRecordの下のドロップダウン:ここで、このため(まだリファクタリングされるように、非乾燥)コードです。それは私が想像しても、豚を使用してメモリ豚です。もちろん移植性は低いですが、時にはその価値があります。

スコア= Post.connection.execute(「スコアによってスコア> 1つのオーダーの記事からスコアを選択」)マップ(&:最初)。その400万レコードの十分に役立つ場合

が知ってはいけません。そうでない場合は、ストアドプロシージャを参照してください。

+0

ARをスキップするのは間違いですが、多くの人のように、足で早く自分を撃つのに役立ちます。 ;)この問題は、何百万という数をレールにロードするよりもずっと簡単に解決できます。 –

関連する問題