Como faço para gerar um histograma para uma determinada distribuição de probabilidade (para testar funcional um servidor)?
-
09-06-2019 - |
Pergunta
Estou tentando automatizar o teste funcional de um servidor usando uma distribuição de frequência realista de solicitações.(uma espécie de teste de carga, uma espécie de simulação)
Eu escolhi o Weibull distribuição, pois "mais ou menos" corresponde à distribuição que observei (aumenta rapidamente, diminui rapidamente, mas não instantaneamente)
Eu uso esta distribuição para gerar o número de solicitações que devem ser enviadas a cada dia entre uma determinada data de início e término
Eu criei um algoritmo em Python que funciona, mas parece confuso:
how_many_days = (end_date - start_date).days
freqs = defaultdict(int)
for x in xrange(how_many_responses):
freqs[int(how_many_days * weibullvariate(0.5, 2))] += 1
timeline = []
day = start_date
for i,freq in sorted(freqs.iteritems()):
timeline.append((day, freq))
day += timedelta(days=1)
return timeline
Que melhores maneiras existem de fazer isso?
Solução
Isso é rápido e provavelmente não tão preciso, mas se você mesmo calcular o PDF, pelo menos será mais fácil colocar vários PDFs menores/maiores em uma única linha do tempo. dev
é o desvio padrão do ruído Guassiano, que controla a rugosidade.Observe que isso é não a maneira 'certa' de gerar o que você deseja, mas é fácil.
import math
from datetime import datetime, timedelta, date
from random import gauss
how_many_responses = 1000
start_date = date(2008, 5, 1)
end_date = date(2008, 6, 1)
num_days = (end_date - start_date).days + 1
timeline = [start_date + timedelta(i) for i in xrange(num_days)]
def weibull(x, k, l):
return (k / l) * (x / l)**(k-1) * math.e**(-(x/l)**k)
dev = 0.1
samples = [i * 1.25/(num_days-1) for i in range(num_days)]
probs = [weibull(i, 2, 0.5) for i in samples]
noise = [gauss(0, dev) for i in samples]
simdata = [max(0., e + n) for (e, n) in zip(probs, noise)]
events = [int(p * (how_many_responses / sum(probs))) for p in simdata]
histogram = zip(timeline, events)
print '\n'.join((d.strftime('%Y-%m-%d ') + "*" * c) for d,c in histogram)
Outras dicas
Por que você não tenta O Moedor 3 para testar a carga do seu servidor, ele vem com tudo isso e muito mais pré-construído e suporta python como linguagem de script
Retrabalho um pouco mais longo, mas provavelmente mais legível, de suas últimas quatro linhas:
samples = [0 for i in xrange(how_many_days + 1)]
for s in xrange(how_many_responses):
samples[min(int(how_many_days * weibullvariate(0.5, 2)), how_many_days)] += 1
histogram = zip(timeline, samples)
print '\n'.join((d.strftime('%Y-%m-%d ') + "*" * c) for d,c in histogram)
Isso sempre elimina as amostras dentro do intervalo de datas, mas você obtém um aumento correspondente no final da linha do tempo de todas as amostras que estão acima do intervalo [0, 1].
Em vez de fornecer o número de solicitações como um valor fixo, por que não usar um fator de escala?No momento, você está tratando as solicitações como uma quantidade limitada e randomizando os dias em que essas solicitações ocorrem.Pareceria mais razoável tratar suas solicitações por dia como independentes.
from datetime import *
from random import *
timeline = []
scaling = 10
start_date = date(2008, 5, 1)
end_date = date(2008, 6, 1)
num_days = (end_date - start_date).days + 1
days = [start_date + timedelta(i) for i in range(num_days)]
requests = [int(scaling * weibullvariate(0.5, 2)) for i in range(num_days)]
timeline = zip(days, requests)
timeline
Reescrevi o código acima para ser mais curto (mas talvez esteja muito ofuscado agora?)
timeline = (start_date + timedelta(days=days) for days in count(0))
how_many_days = (end_date - start_date).days
pick_a_day = lambda _:int(how_many_days * weibullvariate(0.5, 2))
days = sorted(imap(pick_a_day, xrange(how_many_responses)))
histogram = zip(timeline, (len(list(responses)) for day, responses in groupby(days)))
print '\n'.join((d.strftime('%Y-%m-%d ') + "*" * c) for d,c in histogram)
Outra solução é usar Rpy, que coloca todo o poder do R (incluindo muitas ferramentas para distribuições) facilmente no Python.