整数の配列のヒストグラムを作成するにはどうすればよいですか?例えば:
data = [0,1,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,5,5,6,6,6,7,7,7,7,7,8,9,9,10]
0
、1
、2
などのエントリ数に基づいてヒストグラムを作成したいと思います。 Rubyでそれを行う簡単な方法はありますか?
出力は2つの配列である必要があります。最初の配列にはグループ(ビン)が含まれ、2番目の配列には出現回数(頻度)が含まれている必要があります。
上記のdata
の場合、次の出力が期待されます。
bins # => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
frequencies # => [1, 1, 5, 6, 4, 2, 3, 5, 1, 2, 1]
" histogram "を使用します。
data = [0,1,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,5,5,6,6,6,7,7,7,7,7,8,9,9,10]
(bins, freqs) = data.histogram
これにより、ヒストグラムのビンを含む配列bins
と、頻度を含む配列freqs
が作成されます。このgemは、さまざまなビニング動作と重み/分数もサポートしています。
お役に立てれば。
Rubyの配列は group_by
from Enumerable を継承します。これは、これをうまく実行します。
Hash[*data.group_by{ |v| v }.flat_map{ |k, v| [k, v.size] }]
どちらが返されますか:
{
0 => 1,
1 => 1,
2 => 5,
3 => 6,
4 => 4,
5 => 2,
6 => 3,
7 => 5,
8 => 1,
9 => 2,
10 => 1
}
それはただの素敵な 'nクリーンハッシュです。各ビンと周波数ペアの配列が必要な場合は、それを短くして使用できます。
data = [0,1,2,2,3,3,3,4]
data.group_by{ |v| v }.map{ |k, v| [k, v.size] }
# => [[0, 1], [1, 1], [2, 2], [3, 3], [4, 1]]
コードとgroup_by
が小さいデータセットで行っていることは次のとおりです。
data.group_by{ |v| v }
# => {0=>[0], 1=>[1], 2=>[2, 2], 3=>[3, 3, 3], 4=>[4]}
data.group_by{ |v| v }.flat_map{ |k, v| [k, v.size] }
# => [0, 1, 1, 1, 2, 2, 3, 3, 4, 1]
Telmo Costaがコメントで述べたように、Rubyはv2.7.0で tally
を導入しました。クイックベンチマークを実行すると、tally
約3倍高速です:
require 'fruity'
puts "Ruby v#{Ruby_VERSION}"
data = [0,1,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,5,5,6,6,6,7,7,7,7,7,8,9,9,10]
data.group_by{ |v| v }.map{ |k, v| [k, v.size] }.to_h
# => {0=>1, 1=>1, 2=>5, 3=>6, 4=>4, 5=>2, 6=>3, 7=>5, 8=>1, 9=>2, 10=>1}
data.group_by { |v| v }.transform_values(&:size)
# => {0=>1, 1=>1, 2=>5, 3=>6, 4=>4, 5=>2, 6=>3, 7=>5, 8=>1, 9=>2, 10=>1}
data.tally
# => {0=>1, 1=>1, 2=>5, 3=>6, 4=>4, 5=>2, 6=>3, 7=>5, 8=>1, 9=>2, 10=>1}
data.group_by{ |v| v }.keys.sort.map { |key| [key, data.group_by{ |v| v }[key].size] }.to_h
# => {0=>1, 1=>1, 2=>5, 3=>6, 4=>4, 5=>2, 6=>3, 7=>5, 8=>1, 9=>2, 10=>1}
compare do
gb { data.group_by{ |v| v }.map{ |k, v| [k, v.size] }.to_h }
rriemann { data.group_by { |v| v }.transform_values(&:size) }
telmo_costa { data.tally }
CBK {data.group_by{ |v| v }.keys.sort.map { |key| [key, data.group_by{ |v| v }[key].size] }.to_h }
end
その結果:
# >> Ruby v2.7.0
# >> Running each test 1024 times. Test will take about 2 seconds.
# >> telmo_costa is faster than rriemann by 2x ± 0.1
# >> rriemann is similar to gb
# >> gb is faster than CBK by 8x ± 1.0
したがって、 tally
を使用します。