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.
3 comentários:
Muito legal, Tiago!
Adoro linguagens que permitem alteração de classes pré-existentes, como Ruby, Python, Smalltalk e Lua. =)
[]'s
Cacilhas, La Batalema
Que tal o Enumerable#inject? ;-)
http://ruby-doc.org/core/classes/Enumerable.html#M001147
Que bom que tá gostando! Eu sabia! haha
@Fabio Kung
Boa 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
Postar um comentário