Генератор случайных чисел, который дает степенное распределение?

Я пишу несколько тестов для Linux-приложения командной строки С++. Я хотел бы создать кучу целых чисел с распределением полномочий/длинного хвоста. Смысл, я получаю некоторые цифры очень часто, но большинство из них относительно нечасто.

В идеале были бы только некоторые магические уравнения, которые я мог бы использовать с помощью rand() или одной из случайных функций stdlib. Если нет, простой в использовании кусок C/С++ будет большим.

Спасибо!

Ответ 1

Эта страница

Ответ 2

Если вам известно распределение, которое вы хотите (называемое функцией распределения вероятностей (PDF)) и правильно ли оно нормализовано, вы можете интегрировать его для получения функции кумулятивного распределения (CDF), а затем инвертировать CDF (если возможно), чтобы получить преобразование, которое вам нужно, от равномерного распределения [0,1] к вашему желаемому.

Итак, вы начинаете с определения необходимого вам дистрибутива.

P = F(x)

(для x в [0,1]), затем интегрируется, чтобы дать

C(y) = \int_0^y F(x) dx

Если это можно инвертировать, вы получите

y = F^{-1}(C)

Итак, вызовите rand() и подключите результат как C в последней строке и используйте y.

Этот результат называется фундаментальной теоремой выборки. Это хлопот из-за требования нормализации и необходимости аналитической инвертирования функции.

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

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


Настоящая стерва здесь состоит в том, что простые дистрибутивы x^-n не нормируются в диапазоне [0,1], поэтому вы не можете использовать теорему выборки. Попробуйте (x + 1) ^ - n вместо этого...

Ответ 3

Я не могу прокомментировать математику, необходимую для создания распределения закона власти (у других сообщений есть предложения), но я предлагаю вам ознакомиться с возможностями случайных номеров стандартной библиотеки TR1 С++ в <random>. Они обеспечивают большую функциональность, чем std::rand и std::srand. Новая система определяет модульный API для генераторов, движков и дистрибутивов и предоставляет набор пресетов.

Включенные пресеты распространения:

  • uniform_int
  • bernoulli_distribution
  • geometric_distribution
  • poisson_distribution
  • binomial_distribution
  • uniform_real
  • exponential_distribution
  • normal_distribution
  • gamma_distribution

Когда вы определяете распределение мощности по закону, вы должны подключить его к существующим генераторам и двигателям. В книге "Стандартные расширения библиотек С++" Пита Беккера есть замечательная глава в <random>.

Вот статья о том, как создавать другие дистрибутивы (примеры для Коши, Chi-squared, Student t и Snedecor F)

Ответ 4

Я просто хотел провести фактическое симуляцию в качестве дополнения к (по праву) принятому ответу. Хотя в R код настолько прост, как быть (псевдо) -pseudo-code.

Одно небольшое различие между формулой Wolfram MathWorld в принятом ответе и другими, возможно, более распространенными уравнениями - это тот факт, что степенной закон степени n (который обычно обозначается как альфа) не несет явного отрицательного знака. Таким образом, выбранное значение альфа должно быть отрицательным и обычно между 2 и 3.

x0 и x1 обозначают нижний и верхний пределы распределения.

Итак, вот оно:

x1 = 5           # Maximum value
x0 = 0.1         # It can't be zero; otherwise X^0^(neg) is 1/0.
alpha = -2.5     # It has to be negative.
y = runif(1e5)   # Number of samples
x = ((x1^(alpha+1) - x0^(alpha+1))*y + x0^(alpha+1))^(1/(alpha+1))
hist(x, prob = T, breaks=40, ylim=c(0,10), xlim=c(0,1.2), border=F, 
col="yellowgreen", main="Power law density")
lines(density(x), col="chocolate", lwd=1)
lines(density(x, adjust=2), lty="dotted", col="darkblue", lwd=2)

введите описание изображения здесь

или построено в логарифмическом масштабе:

h = hist(x, prob=T, breaks=40, plot=F)
     plot(h$count, log="xy", type='l', lwd=1, lend=2, 
     xlab="", ylab="", main="Density in logarithmic scale")

введите описание изображения здесь

Вот сводка данных:

> summary(x)
   Min.   1st Qu.  Median    Mean   3rd Qu.    Max. 
  0.1000  0.1208  0.1584    0.2590  0.2511   4.9388