Что будет считаться границей стандартного отклонения для java random?
Я использую java 6 random (java.util.Random,linux 64) для случайного выбора между обслуживанием одной версии страницы и второй (обычное A/B-тестирование), технически я инициализирую класс один раз пустым конструктором по умолчанию и он вводится в боб (Spring) как свойство. В большинстве случаев копии страниц находятся в пределах 8%(+-) друг от друга, но время от времени я вижу отклонения до 20%, например:
Теперь у меня есть две копии, которые разделены: 680 / 570 это нормально? Есть ли лучшая / более быстрая версия для использования, чем java random?
Спасибо
3 ответа
Отклонение в 20% кажется довольно большим, но вам нужно поговорить с обученным статистиком, чтобы выяснить, является ли оно статистически аномальным.
ОБНОВЛЕНИЕ - и ответ в том, что это не обязательно аномально. Статистика предсказывает, что вы получите такой выброс примерно в 0,3% случаев.
Разумеется, что такой результат может быть вызван генератором случайных чисел. Random
Класс использует простой "линейный конгруэнтный" алгоритм, и этот класс алгоритмов строго автокоррелирован. В зависимости от того, как вы используете случайное число, это может привести к аномалиям на уровне приложения.
Если это является причиной вашей проблемы, то вы можете попробовать заменить ее на генератор случайных чисел с криптостойкостью. Смотрите Javadocs для SecureRandom
, SecureRandom
дороже, чем Random
, но вряд ли это будет иметь какое-либо значение в вашем случае использования.
С другой стороны, если эти выбросы на самом деле происходят примерно со скоростью, предсказанной теорией, изменение генератора случайных чисел не должно иметь никакого значения.
Если эти выбросы действительно неприятны, то вам нужно использовать другой подход. Вместо того, чтобы генерировать N случайных выборов, создайте список false / true с точно требуемым отношением, а затем перемешайте список; например, используя Collections.shuffle
,
Я считаю, что это довольно нормально, так как оно предназначено для генерации случайных последовательностей. Если вы хотите повторять шаблоны после определенного интервала, я думаю, что вы можете использовать определенные seed
значение в конструкторе и сбросить случайное с тем же начальным числом после определенного интервала.
например, после каждых 100/500/n звонков Random.next..
, сбросьте семя со старым значением, используя Random.setSeed(long seed)
метод.
java.util.Random.nextBoolean() - это подход для стандартного биномиального распределения, которое имеет стандартное отклонение sqrt(n*p*(1-p)), с p=0,5.
Таким образом, если вы выполните 900 итераций, стандартное отклонение будет равно sqrt(900*.5*.5) = 15, поэтому в большинстве случаев распределение будет в диапазоне 435 - 465.
Тем не менее, это псевдослучайный и имеет ограниченный цикл чисел, которые он пройдет, прежде чем начать заново. Так что, если у вас достаточно итераций, фактическое отклонение будет намного меньше теоретического. Java использует формулу seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1). Вы можете написать другую формулу с меньшими числами, чтобы преднамеренно получить меньшее отклонение, что сделало бы его худшим генератором случайных чисел, но лучше подходящим для вашей цели.
Например, вы можете создать список из 5 истин и 5 ложных значений и использовать Collections.shuffle для рандомизации списка. Затем вы последовательно перебираете их. После 10 итераций вы перетасовываете список и начинаете с начала. Таким образом, вы никогда не отклонитесь больше чем на 5.
См. http://en.wikipedia.org/wiki/Linear_congruential_generator для математики.