61 votes

Comment puis-je faire de l'écart type dans Ruby?

J'ai plusieurs enregistrements avec un attribut donné, et je veux trouver l'écart type.

Comment dois-je faire?

99voto

tolitius Points 9816
module Enumerable

    def sum
      self.inject(0){|accum, i| accum + i }
    end

    def mean
      self.sum/self.length.to_f
    end

    def sample_variance
      m = self.mean
      sum = self.inject(0){|accum, i| accum +(i-m)**2 }
      sum/(self.length - 1).to_f
    end

    def standard_deviation
      return Math.sqrt(self.sample_variance)
    end

end 

Tester:

a = [ 20, 23, 23, 24, 25, 22, 12, 21, 29 ]
a.standard_deviation  
# => 4.594682917363407

01/17/2012:

fixation "sample_variance" merci à Dave Sag

37voto

eprothro Points 357

Il semble que Angela peut avoir envie d'une bibliothèque existante. Après avoir joué avec statsample, array-statisics, et quelques autres, je vous recommande la descriptive_statistics gem si vous êtes en essayant d'éviter de réinventer la roue.

gem install descriptive_statistics
$ irb
1.9.2p290 :001 > require 'descriptive_statistics'
 => true 
1.9.2p290 :002 > samples = [1, 2, 2.2, 2.3, 4, 5]
 => [1, 2, 2.2, 2.3, 4, 5] 
1.9.2p290 :003 > samples.sum
 => 16.5 
1.9.2p290 :004 > samples.mean
 => 2.75 
1.9.2p290 :005 > samples.variance
 => 1.7924999999999998 
1.9.2p290 :006 > samples.standard_deviation
 => 1.3388427838995882 

Je ne peux pas parler pour elle de statistique de l'exactitude, ou de votre confort avec le singe de correction Énumérable; mais il est facile à utiliser et facile à contribuer.

31voto

Dave Sag Points 2652

La réponse donnée ci-dessus est élégant, mais a une légère erreur. N'étant pas des stats de la tête moi-même je m'assis et lire en détail un certain nombre de sites web et trouvé celui-ci a donné la plus compréhensible explication de comment calculer un écart-type. http://sonia.hubpages.com/hub/stddev

L'erreur dans la réponse ci-dessus est dans l' sample_variance méthode.

Voici ma version corrigée, avec une simple unité de test qui montre que cela fonctionne.

en ./lib/enumerable/standard_deviation.rb

#!usr/bin/ruby

module Enumerable

  def sum
    return self.inject(0){|accum, i| accum + i }
  end

  def mean
    return self.sum / self.length.to_f
  end

  def sample_variance
    m = self.mean
    sum = self.inject(0){|accum, i| accum + (i - m) ** 2 }
    return sum / (self.length - 1).to_f
  end

  def standard_deviation
    return Math.sqrt(self.sample_variance)
  end

end

en ./test de l'utilisation des nombres dérivés à partir d'une simple feuille de calcul.

Screen Snapshot of a Numbers spreadsheet with example data

#!usr/bin/ruby

require 'enumerable/standard_deviation'

class StandardDeviationTest < Test::Unit::TestCase

  THE_NUMBERS = [1, 2, 2.2, 2.3, 4, 5]

  def test_sum
    expected = 16.5
    result = THE_NUMBERS.sum
    assert result == expected, "expected #{expected} but got #{result}"
  end

  def test_mean
    expected = 2.75
    result = THE_NUMBERS.mean
    assert result == expected, "expected #{expected} but got #{result}"
  end

  def test_sample_variance
    expected = 2.151
    result = THE_NUMBERS.sample_variance
    assert result == expected, "expected #{expected} but got #{result}"
  end

  def test_standard_deviation
    expected = 1.4666287874
    result = THE_NUMBERS.standard_deviation
    assert result.round(10) == expected, "expected #{expected} but got #{result}"
  end

end

10voto

marcgg Points 25599

Je ne suis pas un grand fan de l'ajout de méthodes d' Enumerable car il pourrait y avoir des effets secondaires indésirables. Il donne également des méthodes de vraiment spécifique à un tableau de nombres à toute classe héritant de Enumerable, ce qui n'a pas de sens dans la plupart des cas.

Tout cela est très bien pour des tests, des scripts ou des petites applis, c'est risqué pour des applications plus importantes, alors voici une alternative basée sur @tolitius réponse qui était déjà parfait. C'est plus pour les référence qu'autre chose:

module MyApp::Maths
  def self.sum(a)
    a.inject(0){ |accum, i| accum + i }
  end

  def self.mean(a)
    sum(a) / a.length.to_f
  end

  def self.sample_variance(a)
    m = mean(a)
    sum = a.inject(0){ |accum, i| accum + (i - m) ** 2 }
    sum / (a.length - 1).to_f
  end

  def self.standard_deviation(a)
    Math.sqrt(sample_variance(a))
  end
end

Et puis vous l'utilisez en tant que tel:

2.0.0p353 > MyApp::Maths.standard_deviation([1,2,3,4,5])
=> 1.5811388300841898

2.0.0p353 :007 > a = [ 20, 23, 23, 24, 25, 22, 12, 21, 29 ]
 => [20, 23, 23, 24, 25, 22, 12, 21, 29]

2.0.0p353 :008 > MyApp::Maths.standard_deviation(a)
 => 4.594682917363407

2.0.0p353 :043 > MyApp::Maths.standard_deviation([1,2,2.2,2.3,4,5])
 => 1.466628787389638

Le comportement est le même, mais il évite les frais généraux et les risques d'ajouter des méthodes à l' Enumerable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X