Выбор стандартного отклонения (или дисперсии) для ограниченного распределения может выполняться только с учетом ограничений, которые зависят от выбранного распределения и границ (min, max)
вашего интервала. В некоторых дистрибутивах вы можете сделать дисперсию сколь угодно малой (например, Beta distribution), другие дистрибутивы (например, Uniform distribution) не допускают гибкости после того, как были установлены границы (min, max)
. В любом случае вы можете никогда не делать, чтобы сделать дисперсию произвольно большой - границы этого не мешают (они всегда будут вводить выражение для дисперсии распределения).
Я проиллюстрирую это на очень простой пример, который может быть реализован без каких-либо сторонних библиотек. Предположим, что вы хотите симметричное распределение на интервале (min, max)
, симметрию, подразумевающую, что среднее E (X) распределения расположено в середине интервала: E(X) = (min + max)/2
.
Использование Рэндом nextDouble
как в x = a + (b - a) * rnd.nextDouble()
даст вам равномерно распределенную случайную величину в интервале a <= x < b
, который имеет фиксированную дисперсию Var(X) = (b - a)^2/12
(не то, что мы хотим).
OTH, имитируя симметричную triangular distribution на том же интервале (a, b)
даст нам случайную мерный ти то же среднее значение, но только половина дисперсии: Var(X) = (b - a)^2/24
(также фиксированной, так и не то, что мы хотим).
A симметричный trapezoidal distribution с параметрами (a < b < c < d)
лежит где-то посередине равномерного и треугольного распределения на интервале (a, d)
. Условие симметрии влечет d - c = b - a
, в следующем я буду ссылаться на расстояние b - a
как x
или как «смещение» (я составил это имя, это не технический термин).
Если вы позволите x
приблизиться к 0.0 сверху, трапеция начнет выглядеть очень похожей на равномерное распределение, и ее дисперсия будет стремиться к максимально возможному значению (d - a)^2/12
. Если вы дадите x
приблизительное значение (d - a)/2
снизу, трапеция будет очень похожа на симметричное распределение треугольника, и ее дисперсия приблизится к минимально возможному значению (d - a)^2/24)
(но обратите внимание, что нам следует немного держаться от этих экстремальных значений в чтобы не нарушить формулу дисперсии или наш алгоритм для трапеции).
Таким образом, идея заключается в том, чтобы построить распределение трапециевидного со значением для x
, что дает стандартное отклонение вы хотите, учитывая условие, что ваше целевое стандартное отклонение должно лежать в открытом диапазоне (примерно), заданной (0.2041(d - a), 0.2886(d - a))
. Для удобства предположим, что a = min = 2.0
и d = max = 10.0
, который дает нам этот диапазон возможных stddevs: (1.6328, 2.3088)
.Предположим далее, что мы хотим построить распределение с stddev 2.0
(что, конечно, должно быть в допустимом диапазоне).
Решение этого требует 3 шага:
1) мы должны иметь формулу для дисперсии данного min, max
и допустимого значения для смещения x
2) нам необходимо каким-то образом «инвертирует» это выражение чтобы дать нам значение x
для целевой дисперсии
3), как только мы знаем значение x
мы должны построить случайную переменную, которая имеет симметричное распределение трапеций с параметрами (min, max, x)
Шаг 1:
/**
* Variance of a symmetric trapezoidal distribution with parameters
* {@code a < b < c < d} and the length of {@code d - c = b - a}
* (by symmetry) identified by {@code x}.
*
* @param a support lower bound
* @param d support upper bound
* @param x length of {@code d - c = b - a}, constrained to lie in the open
* interval {@code (0, (d-a)/2)}
* @return variance of the symmetric trapezoidal distribution defined by
* the triple {@code (a, d, x)}
*/
static double varSymTrapezoid(double a, double d, double x) {
if (a <= 0.0 || d <= 0.0 || a >= d) {
throw new IllegalArgumentException();
}
if (x <= 0.0 || x >= (d - a)/2) {
throw new IllegalArgumentException();
}
double b = a + x;
double c = d - x;
double b3 = pow(b, 3);
double c3 = pow(c, 3);
double ex2p1 = pow(b, 4)/4 - a * b3/3 + pow(a, 4)/12;
double ex2p2 = (c3/3 - b3/3) * (d - c);
double ex2p3 = pow(c, 4)/4 - d * c3/3 + pow(d, 4)/12;
double ex2 = (ex2p1 + ex2p2 + ex2p3)/((d - b) * (d - c));
return ex2 - pow((a + d)/2, 2);
}
Обратите внимание, что эта формула справедлива только для симметричных распределений трапециевидных. В качестве примера, если вы вызовете этот метод со смещением 2,5 (varSymTrapezoid(2.0, 10.0, 2.5)
), это вернет вам отклонение приблизительно 3.0416
, которое слишком низкое (нам нужно 4.0), что означает, что смещение 2,5 слишком велико (более высокие перемещения дают более низкие отклонения).
Выражение дисперсии - это многочлен 4-го порядка в x
, который я бы не хотел аналитически решать. Однако для целевого x
в допустимом диапазоне это выражение монотонно убывает, поэтому мы можем построить функцию, которая пересекает нуль для нашей целевой дисперсии и решает эту задачу простым bisection. Это
Шаг 2:
/**
* Find the displacement {@code x} for the given {@code stddev} by simple
* bisection.
* @param min support lower bound
* @param max support upper bound
* @param stddev the standard deviation we want
* @return the length {@code x} of {@code d - c = b - a} that yields a
* standard deviation roughly equal to {@code stddev}
*/
static double bisect(double min, double max, double stddev) {
final double eps = 1e-4;
final double var = pow(stddev, 2);
int iters = 0;
double a = eps;
double b = (max - min)/2 - eps;
double x = eps;
double dx = b - a;
while (abs(dx) > eps && iters < 150 && eval(min, max, x, var) != 0.0) {
x = ((a + b)/2);
if ((eval(min, max, a, var) * eval(min, max, x, var)) < 0.0) {
b = x;
dx = b - a;
} else {
a = x;
dx = b - a;
}
iters++;
}
if (abs(eval(min, max, x, var)) > eps) {
throw new RuntimeException("failed to find solution");
}
return x;
}
/**
* Function whose root we want to find.
*/
static double eval(double min, double max, double x, double var) {
return varSymTrapezoid(min, max, x) - var;
}
Вызов bisect
метода с желаемым значением 2,0 для стандартного отклонения (bisect(2.0, 10.0, 2.0)
) дает нам необходимое смещение: ~ 1.1716
. Теперь, когда значение x
известно, последнее, что нам нужно сделать, это построить соответствующим образом распределенная случайная величина, которая
Шаг 3:
Это хорошо известный факт теории вероятностей сумма двух независимых равномерно распределенных случайных величин X1 ~ U[a1, b1]
и X2 ~ U[a2, b2]
является симметричной трапецеидально распределенной случайной величиной на интервале [a1 + a2, b1 + b2] при условии, что либо a1 + b2 < a2 + b1
(случай 1), либо a2 + b1 < a1 + b2
(случай 2). Мы должны избегать случая a2 + b1 = a1 + b2
(случай 3), так как тогда сумма имеет симметричное треугольное распределение, которое мы не хотим.
Мы выберем случай 1 (a1 + b2 < a2 + b1
). В этом случае длина b2 - a2
будет равна «смещению» x
.
Таким образом, все, что мы должны сделать, это выбрать границах интервала a1, a2, b1 и b2, такие, что a1 + a2 = min
, b1 + b2 = max
, b2 - a2 = x
и выше неравенство fullfilled:
/**
* Return a pseudorandom double for the symmetric trapezoidal distribution
* defined by the triple {@code (min, max, x)}
* @param min support lower bound
* @param max support upper bound
* @param x length of {@code max - c = b - min}, constrained to lie in the
* open interval {@code (0, (max-min)/2)}
*/
public static double symTrapezoidRandom(double min, double max, double x) {
final double a1 = 0.5 * min;
final double a2 = a1;
final double b1 = max - a2 - x;
final double b2 = a2 + x;
if ((a1 + b2) >= (a2 + b1)) {
throw new IllegalArgumentException();
}
double u = a1 + (b1 - a1) * rnd.nextDouble();
double v = a2 + (b2 - a2) * rnd.nextDouble();
return u + v;
}
Вызов symTrapezoidRandom(2.0, 10.0, 1.1716)
неоднократно дает вам которые имеют требуемое распределение.
Вы можете сделать очень похожие вещи с другими, более сложными, дистрибутивами, такими как Beta. Это даст вам другие (как правило, более гибкие) ограничения на допустимые отклонения, но для этого вам понадобится сторонняя библиотека, например commons.math.
abs
, pow
, sqrt
в коде относится к статический импортируемым методам java.lang.Math и rnd
является экземпляром java.util.Random.
Не могли бы вы помочь? ... http://stackoverflow.com/questions/31754209/can-random-nextgaussian-sample-values-from-a-distribution-with-different-mean –
Подсказка: мне потребовалось меньше времени, чтобы найти "дублированный" вопрос, чем прочитать ваш вопрос. Думаю: писать ваш вопрос занял еще больше времени. Так пожалуйста; сделайте некоторые предварительные исследования в следующий раз. – GhostCat
@GhostCat «дублированный» ответ не решает мою проблему, потому что мне нужны номера в диапазоне. – statboy