2

J'ai un ensemble de données croissant de 4 millions de lignes environ, afin de définir et d'exclure les valeurs aberrantes (pour l'utilisation de statistiques/analytiques) J'ai besoin que l'algorithme considère toutes les entrées dans cet ensemble de données. Cependant, c'est trop de données à charger dans la mémoire et mon système étouffe. J'utilise actuellement ce pour recueillir et traiter les données:Les données sont trop volumineuses pour être chargées en mémoire

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

En utilisant la fracture typique et la conquête de méthode ne fonctionnera pas, je ne pense pas parce que chaque entrée doit être considéré comme garder mon calcul précis des valeurs aberrantes . Comment cela peut-il être réalisé efficacement?

innerFence identifie le quartile inférieur et le quartile supérieur de l'ensemble de données, puis utilise ces résultats pour calculer les valeurs aberrantes. Voici (encore refondus, non-DRY) code pour ceci:

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

Que fait 'innerFence'? La réponse évidente est de faire ce que vous faites dans 'innerFence' dans la base de données plutôt que dans Ruby - mais cela dépend de l'implémentation de' innerFence'. –

+0

Il identifie les quartiles inférieur et supérieur de mon ensemble de données, puis calcule les valeurs aberrantes. J'ai ajouté la source dans ma dernière édition. –

Répondre

1

Ce n'est pas la meilleure façon, mais il est un moyen facile:

Est-ce que plusieurs querys. D'abord, vous comptez le nombre de notes:

q = Post.where (: source => 1) .Count

alors vous faites vos calculs alors vous allez chercher les scores

= q1 Post.where (: source => 1). reverse_order (: score). select ("moy (score) en score"). décalage (q) .limit ((q% 2) +1)

q2 = Post.where (: source => 1). reverse_order (: score). select ("moy (score) en score"). décalage (q * 3) .limit ((q% 2) +1)

Le code est probablement faux, mais je suis sûr que vous avez l'idée.

+0

Cette route a fonctionné beaucoup mieux et j'ai réussi à le faire fonctionner en sélectionnant mes quartiles w/offset en fonction du nombre plutôt que de charger toutes les données dans des rails. Merci! –

+0

Heureux que ça a aidé! Vous souhaitez probablement l'inclure dans une transaction si quelqu'un insère des données en même temps que vous le faites. –

0

Pour les grands ensembles de données, je laisse tomber parfois en bas ActiveRecord. C'est un cochon de la mémoire, même j'imagine, en utilisant le pinceau. Bien sûr, c'est moins portable, mais parfois ça vaut le coup.

scores = Post.connection.execute ('score de sélection de messages où partition> 1 ordre par le score') carte. (&: premier)

Je ne sais pas si cela peut aider suffisant pour 4 millions de disque . Si non, peut-être regarder une procédure stockée?

+0

Il est parfois correct de sauter AR, mais dans ce cas, comme beaucoup d'autres, il vous aide simplement à vous tirer dans le pied plus rapidement. ;) Ce problème peut être résolu beaucoup plus simplement que de charger des millions de numéros dans des rails. –

Questions connexes