Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Ruby: 配列のモードとメジアンを算出する方法(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

Ruby: 配列のモードとメジアンを算出する方法(翻訳)

Rubyで配列の平均値を求める方法については以前も別記事『Calculate a mean average from a Ruby array』で取り上げました。しかし、普段あまり目にしませんがそれでも有用な平均が他にも2種類あります。

メジアン(中央値)は次のように求める

a = [1, 3, 2, 4, 6, 5, 7, 8]

sorted = a.sort # required
#=> [1, 2, 3, 4, 5, 6, 7, 8]
midpoint = a.length / 2 # integer division
#=> 4
if a.length.even?
  # メジアンは中間の前後にある2つの値の平均
  sorted[midpoint-1, 2].sum / 2.0
else
  sorted[midpoint]
end
#=> 4.5

モード(最頻値)は次のように求める

Array#tallyを使い、それからソートする。

a = [1, 3, 3, 4, 6, 5, 7, 8]

tallied = a.tally
#=> {1=>1, 3=>2, 4=>1, 6=>1, 5=>1, 7=>1, 8=>1}
top_pair = tallied.sort_by { |_,v| v }.last(2)
#=> [[8, 1], [3, 2]]
if top_pair.size == 1
  top_pair[0][0] # 要素が1個だけなら、それがモード
elsif top_pair[0][1] == top_pair[1][1]
  nil # 個数が同じならモードは存在しない
else
  top_pair[1][0]
end
#=> 3

そうする理由

#tallyメソッドはRuby 2.7でEnumerableに追加されました。injectを用いる実装を見たことがあるかもしれませんが、こちらはパフォーマンスが落ちます。

以前平均値の計算について記事を書いたときに、Rubyのネイティブメソッドを使った場合と、自分で実装した場合のパフォーマンスを比較しました。

他には?

これらの計算をメソッドにまとめておくと良いと思います。

この種の計算を頻繁に行う場合や、パフォーマンスが重要な場合には、enumerable-statistics gemをチェックしてみましょう。これはArrayとEnumerableにミックスインされたいくつかの統計的なサマリー算出のネイティブ実装版です。

これらのメソッドはC言語で実装されていて、Rubyでプログラムされたアルゴリズムよりもはるかに高速です。

関連記事

RubyでISO国名コード2文字を絵文字の国旗に変換する(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。