No blog
Kodumaro foi publicado uma comparação de cálculos estatísticos entre linguagens imperativas, como C, e linguagens funcionais, no caso o Lisp. Os cálculos utilizados como exemplificação foram os de
variância da população e variância da amostra. Como estou estudando ruby, me empolguei e resolvi fazer a versão desses cálculos nessa linguagem.
Veja como o código ficou:
class Array
def acumula()
acc = 0
each { |a| acc += yield(a) }
acc
end
def media()
total = acumula { |a| a }
total / length
end
def numerador_de_variancia()
m = media
acumula { |a| (a - media)**2 }
end
def variancia_populacional()
numerador_de_variancia / length
end
def variancia_da_amostra()
numerador_de_variancia / (length-1)
end
end
O que fiz foi criar novos métodos na classe Array para fazer todos os cálculos necessários. O interessante é que não encontrei na documentação do Ruby nenhum método que iterasse sobre um array e retornasse um acumulo dos valores calculados por um bloco. Para suprir isso criei então o método
acumula.
Apesar do código ter ficado um pouco mais verboso que o
código em lisp exibido no Kodumaro, o uso ficou mais simples. Como são novos métodos, para obter a variância da amostra em um array basta por exemplo fazer
[2,4,6].variancia_da_amostra. Veja abaixo um exemplo de uso desses métodos:
array = [2,4,6]
puts "Media: #{array.media}"
puts "Numerador de variancia: #{array.numerador_de_variancia}"
puts "Variancia populacional: #{array.variancia_populacional}"
puts "Variancia da amostra: #{array.variancia_da_amostra}"
Mas é importante ressaltar o perigo dessa alteração de classe. Veja que não faço nenhum tratamento sobre o tipo de dado do array. No caso, estou assumindo que todo array que vá utilizar esses métodos tenham sempre todos os indices preenchidos por numeros.
Muito legal, Tiago!
ResponderExcluirAdoro linguagens que permitem alteração de classes pré-existentes, como Ruby, Python, Smalltalk e Lua. =)
[]'s
Cacilhas, La Batalema
Que tal o Enumerable#inject? ;-)
ResponderExcluirhttp://ruby-doc.org/core/classes/Enumerable.html#M001147
Que bom que tá gostando! Eu sabia! haha
@Fabio Kung
ResponderExcluirBoa Kung! Brigado pela dica, segue como fica o programa atualizado utilizando inject ao invés do método acumula que eu havia criado:
class Array
def media()
total = inject { |total,atual| total += atual }
total / length
end
def numerador_de_variancia()
m = media
inject { |total,atual| total += (atual - media)**2 }
end
def variancia_populacional()
numerador_de_variancia / length
end
def variancia_da_amostra()
numerador_de_variancia / (length-1)
end
end
Mais simples ainda