Как создать гистограмму для заданного распределения вероятностей (для функционального тестирования сервера)?

Я пытаюсь автоматизировать функциональное тестирование сервера, используя реалистичное частотное распределение запросов. (своего рода нагрузочное тестирование, своего рода симуляция)

Я выбрал распределение Weibull, поскольку оно "в некотором роде" соответствует распределению, которое я наблюдал (быстро увеличивается, быстро спадает, но не мгновенно)

Я использую это распределение для генерации количества запросов, которые должны отправляться каждый день между заданной начальной и конечной датой.

Я собрал алгоритм на Python, который вроде бы работает, но он кажется неуклюжим:

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

Какие есть способы сделать это лучше?

Этот алгоритм всегда возвращает ожидаемое количество ответов, но обычно он не помещает их точно между датами начала и окончания, я не уверен, что это возможно, если я вручную не изменю частоты?

Jacob Rigby 10.09.2008 15:18

Их соответствие между датами начала и окончания не гарантируется, потому что вы используете распределение вероятностей с бесконечной поддержкой. Пока вы используете в качестве ключа случайное число, возвращаемое из дистрибутива без изменений, у вас будет эта проблема.

Kai 11.09.2008 14:06
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
4
2
1 775
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Почему бы вам не попробовать Точильщик 3 для нагрузочного тестирования вашего сервера, он поставляется со всем этим и многим другим предварительно собранным, и он поддерживает python в качестве языка сценариев

К сожалению, эта функция также будет использоваться в некоторых функциональных тестах, поэтому я хотел бы сохранить все это в семье, насколько это возможно. Может быть, моделирование - лучшее описание, чем нагрузочное тестирование

Jacob Rigby 10.09.2008 15:23

Вместо того, чтобы указывать количество запросов как фиксированное значение, почему бы вместо этого не использовать коэффициент масштабирования? В настоящий момент вы обрабатываете запросы как ограниченное количество и случайным образом выбираете дни, в которые эти запросы попадают. Было бы разумнее рассматривать ваши ежедневные запросы как независимые.

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

Эта функция, похоже, не создает ту форму, которую я ищу. Если вы посмотрите статью в Википедии, я выбрал красную кривую, которая быстро нарастает, а затем затухает со временем, как будто моделирует просмотры страниц, изначально высокие, но затем люди со временем теряют интерес к новому контенту.

Jacob Rigby 11.09.2008 13:04

На самом деле все дело (с моей точки зрения :-) в том, что количество запросов зависит от дня. Я не просто пытаюсь моделировать случайные нагрузки в течение определенного периода времени.

Jacob Rigby 11.09.2008 13:07

Хорошо, но то, что вы делаете сейчас, просто приближает распределение. Почему бы не использовать сам раздачу, или раздачу плюс немного шума? В нынешнем виде вы моделируете процесс, зависящий от истории, без использования истории.

Kai 11.09.2008 14:41

Ну, это в значительной степени мой вопрос, как мне сгенерировать распределение + шум, предпочтительно с использованием функций stdlib? Я мог бы написать свою собственную функцию PDF и оценивать + возмущение в каждой точке ... но это кажется сложнее, чем написать это приближение.

Jacob Rigby 11.09.2008 15:27

Я переписал приведенный выше код, чтобы он был короче (но, может быть, он сейчас слишком запутан?)

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)

Это импорт для функции выше: from datetime import datetime, timedelta from random import weibullvariate from itertools import imap, count, groupby how_many_responses = 100 start_date = date (2008, 5, 1) end_date = date (2008, 6, 1)

Jacob Rigby 11.09.2008 13:17

Чуть более длинная, но, вероятно, более читаемая переработка ваших последних четырех строк:

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)

Это всегда отбрасывает выборки в пределах диапазона дат, но вы получаете соответствующий удар в конце временной шкалы для всех выборок, которые находятся выше диапазона [0, 1].

Прекрасно, мне это нравится. Я всегда стараюсь набивать итераторы, но это определенно легче читать :-)

Jacob Rigby 11.09.2008 15:19
Ответ принят как подходящий

Это быстро и, вероятно, не так точно, но если вы рассчитываете PDF самостоятельно, то, по крайней мере, вам будет проще разместить несколько меньших / больших на одной временной шкале. dev - это стандартное отклонение в гуассианском шуме, которое контролирует шероховатость. Обратите внимание, что это нет - «правильный» способ сгенерировать то, что вы хотите, но это просто.

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)

Отлично, распределение выглядит намного лучше, чем созданное с помощью моделирования.

Jacob Rigby 12.09.2008 06:36

Другое решение - использовать Rpy, который легко помещает всю мощь R (включая множество инструментов для дистрибутивов) в Python.

Другие вопросы по теме