😺

[Feature #21518] Enumerable に統計を扱うメソッドを追加する提案

に公開

[Feature #21518] Statistical helpers to Enumerable

  • Enumerable に統計を扱うメソッドを追加する提案
  • このチケットだと Enumerable#averageEnumerable#median の2つのメソッドを追加する提案がされている
  • 動作イメージは以下の通り
# Enumerable#average -> Float or nil
# Enumerable#median  -> Numeric or nil

[1, 2, 3, 4].average      # => 2.5
(1..4).average            # => 2.5
[].average                # => nil

[1, 3, 2].median          # => 2
[1, 2, 3, 10].median      # => 2.5
(1..6).median             # => 3.5
[].median                 # => nil
  • このあたりのメソッドは再定義されがちなので本体に定義されている方がよい、ってあたりがモチベーションみたいですね
  • これ系の提案は過去にもあったと思うんですが Ruby はこのあたりのメソッドを追加するに慎重で Enumerable#sum も比較的最近(2016年)追加された、というコメントがされていますね
  • 慎重になる背景としてはこれらのメソッドはすべての要素が Float / Integer である前提となっており、そういうメソッドを追加することに抵抗があるみたい
    • 配列の要素が文字列や数値以外のオブジェクトの場合は意味のないメソッドになってしまうのでそういうメソッドを追加することが適切かどうか、みたいな問題がある
  • このあたりは Enumerable#sum も同じ課題があったみたいなんですが当時、和を計算する Kahan-Babuska Summation Algorithm というアルゴリズムが注目されていた、みたいな背景があったみたいですね
  • 実際に単純に Float 値を加算した場合と #sum を利用した場合だと結果が異なるので #sum を利用する有用性があるみたいですね
ary = [1.12, 1.23, 1.34, 1.45, 1.56]

# 単純に Float 値を加算した場合は誤差が発生する
pp ary.inject(:+) # => 6.700000000000001

# こっちは誤差が出ずに正しい結果が取得できる
pp ary.sum # => 6.7
  • 今回提案されている #average#median もこのあたりの有用性が説明できると入りやすかったりするんですかねー
  • また別の目線として Math::Statistics のクラスメソッドとして定義する案もコメントされていますね
Math::Statistics.average(some_enumerable)
  • 確かにこっちのほうが適切な気もする
GitHubで編集を提案

Discussion