Cálculo da variância em Python
Este post segue uma seqüência iniciada no blog Kodumaro, comparando a implementação de alguns cálculos de estatística usando linguagens como Lisp, C e depois seguido de Ruby no blog Programando sem cafeína, e Smalltalk.
Como estou vendo um pouco de estatística na faculdade agora, me animei para tentar uma implementação em Python também.
Preferi implementar como funções simples pois assim é fácil de aplicar sobre qualquer conjunto de dados iterável como listas, tuplas, dicionários ou sets.
Na função de numerador da variância, um dos parâmetros é a função de média que se deseja utilizar para o cálculo, com o padrão sendo a média aritmética (pois como nota o blog Kodumaro, o uso da função depende de quem pediu o cálculo ;).
Vale notar também o uso de generator expressions para os somatórios, que substituem as mais tradicionais list comprehensions nesse caso por questão de performance, principalmente para grandes conjuntos de dados.
Apliquei ainda doctests simples para validar os resultados das funções.
Como estou vendo um pouco de estatística na faculdade agora, me animei para tentar uma implementação em Python também.
import math
def arithmetic_mean(dataset):
"""
Simple arithmetic mean (average)
Example:
>>> arithmetic_mean([10,100,1000])
370
"""
return sum(dataset) / len(dataset)
def root_mean_square(dataset):
"""
RMS (quadratic mean)
Example:
>>> root_mean_square([10,100,1000])
580.25856305616037
"""
return math.sqrt(sum(x**2 for x in dataset) / len(dataset))
def var_num(dataset, mean_function=arithmetic_mean):
"""
Divisor for variance calculation
"""
mean = mean_function(dataset)
return sum((x - mean)**2 for x in dataset)
def populational_variance(dataset):
"""
Population variance
Example:
>>> populational_variance([10,100,1000])
199800
"""
return var_num(dataset) / len(dataset)
def sample_variance(dataset):
"""
Sample variance
Example:
>>> sample_variance([10,100,1000])
299700
"""
return var_num(dataset) / (len(dataset) - 1)
Preferi implementar como funções simples pois assim é fácil de aplicar sobre qualquer conjunto de dados iterável como listas, tuplas, dicionários ou sets.
Na função de numerador da variância, um dos parâmetros é a função de média que se deseja utilizar para o cálculo, com o padrão sendo a média aritmética (pois como nota o blog Kodumaro, o uso da função depende de quem pediu o cálculo ;).
Vale notar também o uso de generator expressions para os somatórios, que substituem as mais tradicionais list comprehensions nesse caso por questão de performance, principalmente para grandes conjuntos de dados.
Apliquei ainda doctests simples para validar os resultados das funções.
Labels: python
7 Comments:
Ficou muito boa essa versão em Python
Muito legal! Também gostei. =)
Só não entendi por que você usou math.sqrt().
Geralmente faço isso com pow() ou com **.
Qual o motivo de sua escolha? Há alguma diferença de precisão ou desempenho?
[]'s
Cacilhas, La Batalema
Não entendi a dúvida. Como você calcula a raiz usando potência?
Prefiro usar métodos prontos do que reimplementar na maioria dos casos. A biblioteca Python é extensa e "não tenho medo de usar" :D
A operação de "raiz" é uma potenciação, só que com um valor fracionário.
math.pow(10, 0.5) == math.sqrt(10)
Mas é claro que pra raízes quadradas, math.sqrt é muito mais intuitivo ;)
Parabéns pelo post, foi bem interessante!
Tem razão ! *slaps own forehead* :)
Rodei alguns testes aqui, e a versão utilizando multiplicação é mais rápida, como pode ser visto ao rodar este código:
from timeit import Timer
print 'multiply:'
print min(Timer('10**0.5').repeat())
print 'math.sqrt:'
print min(Timer('sqrt(10)', 'from math import sqrt').repeat())
Aqui o resultado é:
multiply:
0.0717430114746
math.sqrt:
0.43367600441
Portanto, para quem quiser otimizar um pouco o código, pode trocar pela multiplicação mesmo.
O custo maior do math.sqrt ocorre por se tratar de uma chamada de função, que envolve busca no namespace:
"Function call overhead in Python is relatively high, especially compared with the execution speed of a builtin function." [1]
e nisso a operação de multiplicação direta leva vantagem.
Bacana ;)
Hm, troque onde eu falei "multiplicação" no comentário anterior por "potenciação", claro... :/
Post a Comment
<< Home