2014-07-25 2 views
0

J'essaie de créer un histogramme à partir d'un tableau de nombres dans la plage [0,1].Ruby group par gamme, tableau de nombres?

Existe-t-il un moyen d'utiliser group_by pour séparer le tableau en N groupes/bins par intervalle numérique (ou un autre Ruby one-liner)?

Ceci est mon courant, ennuyeux, solution:

# values == array containing floating point numbers in the range [0,1] 

n = 10 

# EDITED from Array.new(n, 0) to Array.new(n, []), thanks emaillenin! 
histogram = Array.new(n, []) 
values.each do |val| 
    histogram[(val * n).ceil - 1].push(val) 
end 
+0

ce code ne fonctionnerait pas. histogramme [n'importe quoi] est un Fixnum et vous ne pouvez pas appeler pousser dessus – emaillenin

+0

@emaillenin oups vous avez raison! Je voulais dire que c'est un tableau de tableaux, mon mauvais! – cjhin

+0

Doit être 'Array.new (n) {[]}' pour éviter tous les emplacements référençant le même tableau. – tadman

Répondre

3

Je ne sais pas ce que vous essayez de faire, mais peut-être cela aide?

values = [0.0, 0.1, 0.2, 0.3] 
values.group_by { |v| (v * 10).ceil - 1 } 

qui retourne un hachage:

{-1=>[0.0], 0=>[0.1], 1=>[0.2], 2=>[0.3]} 
+0

Gardez à l'esprit que cela peut générer jusqu'à 11 compartiments lorsque les deux valeurs '0.0' et' 1.0' sont présentes en plus des autres valeurs ('0.x'). –

+0

'group_by' le fait très proprement. – tadman

1

C'est une façon de le faire.

code

def freq_by_bin(nbr_bins, *values) 
    nbr_bins.times.to_a.product([0]).to_h.tap { |h| 
    values.each { |v| h.update({ (v*nbr_bins).to_i=>1 }) { |_,o,_| o+1 } } } 
end 

Exemple

values = [0.30, 0.25, 0.63, 0.94, 0.08, 0.94, 0.01, 
      0.41, 0.28, 0.69, 0.61, 0.12, 0.66] 
freq_by_bin(10, *values) 
    #=> {0=>2, 1=>1, 2=>2, 3=>1, 4=>1, 
    # 5=>0, 6=>4, 7=>0, 8=>0, 9=>2} 

def histogram(nbr_bins, *values) 
    h = freq_by_bin(nbr_bins, *values) 
    puts "\nfreq" 
    h.values.max.downto(0) do |n| 
    print "%2d|" % n 
    puts nbr_bins.times.with_object(' ') { |i,row| 
      row << ((h[i]==n) ? ' X ' : ' ') } 
    end 
    puts " __"+"___"*nbr_bins 
    puts nbr_bins.times.each_with_object('  ') { |i,row| row << "%2d " % i } 
end 

histogram(10, *values) 

freq 
4|      X   
3|         
2| X  X     X 
1|  X  X X     
0|     X  X X  
    ________________________________ 
     0 1 2 3 4 5 6 7 8 9 

Remarques

  • Il y a plusieurs façons de construc t le hachage dont les éléments sont bin=>freq. En utilisant Enumerable#group_by, que vous avez mentionné et @diego utilisé est un. J'ai utilisé la forme de Hash#update (aka Hash#merge!) qui prend un bloc. J'ai simplement utilisé Object#tap simplement pour éviter la nécessité de créer une variable temporaire (non bloquante) pour le hachage initialisé.