Взвешенные случайные числа в MATLAB

Как случайным образом поднять числа N с вектора a с весом, присвоенным каждому числу?

Скажем:

a = 1:3; % possible numbers
weight = [0.3 0.1 0.2]; % corresponding weights

В этой вероятности случая для взятия 1 должно быть в 3 раза выше, чем взять 2.

Сумма всех весов может быть чем-либо.

17
задан Luuklag 19 May 2019 в 08:02
поделиться

2 ответа

R = randsample([1 2 3], N, true, [0.3 0.1 0.2])

randsample включен в панель инструментов статистики


В противном случае вы можете использовать какой-то процесс выбора колеса рулетки . См. Этот аналогичный вопрос (хотя и не специфичный для MATLAB). Вот моя однострочная реализация:

a = 1:3;             %# possible numbers
w = [0.3 0.1 0.2];   %# corresponding weights
N = 10;              %# how many numbers to generate

R = a( sum( bsxfun(@ge, rand(N,1), cumsum(w./sum(w))), 2) + 1 )

Пояснение:

Рассмотрим интервал [0,1]. Мы назначаем каждому элементу в списке ( 1: 3 ) подинтервал длины, пропорциональной весу каждого элемента; поэтому 1 get и интервал длины 0,3 / (0,3 + 0,1 + 0,2) , то же самое для других.

Теперь, если мы сгенерируем случайное число с равномерным распределением по [0,1], тогда любое число в [0,1] будет с равной вероятностью быть выбранным, поэтому длина подинтервалов определяет вероятность случайного число, попадающее в каждый интервал.

Это соответствует тому, что я делаю выше: выберите число X ~ U [0,1] (больше похоже на N числа), затем найдите, в какой интервал оно попадает в векторизованном виде .. [


​​Вы можете проверить результаты двух описанных выше методов, сгенерировав достаточно большую последовательность N = 1000 :

>> tabulate( R )
  Value    Count   Percent
      1      511     51.10%
      2      160     16.00%
      3      329     32.90%

, которая более или менее соответствует нормализованным весам w./sum (w) [0,5 0,16667 0,33333]

39
ответ дан 30 November 2019 в 10:19
поделиться

amro дает хороший ответ (который я оценил), но он будет очень интенсивным, если вы хотите сгенерировать много чисел из большого набора. Это связано с тем, что операция bsxfun может создать огромный массив, который затем суммируется. Например, предположим, что у меня есть набор из 10000 значений для выборки, все с разным весом? Теперь сгенерируйте 1000000 чисел из этого образца.

Это потребует некоторой работы, так как он внутренне сгенерирует массив размером 10000x1000000, содержащий в нем 10 ^ 10 элементов. Это будет логический массив, но даже в этом случае необходимо выделить 10 гигабайт оперативной памяти.

Лучшее решение - использовать histc. Таким образом ...

a = 1:3
w = [.3 .1 .2];
N = 10;

[~,R] = histc(rand(1,N),cumsum([0;w(:)./sum(w)]));
R = a(R)
R =
     1     1     1     2     2     1     3     1     1     1

Однако для большой задачи такого размера, который я предложил выше, это быстро.

a = 1:10000;
w = rand(1,10000);
N = 1000000;

tic
[~,R] = histc(rand(1,N),cumsum([0;w(:)./sum(w)]));
R = a(R);
toc
Elapsed time is 0.120879 seconds.

По общему признанию, моя версия требует для написания 2 строчки. Операция индексации должна выполняться во второй строке, поскольку она использует второй вывод histc. Также обратите внимание, что я использовал возможности новой версии Matlab с оператором тильды (~) в качестве первого аргумента histc. Это приводит к тому, что первый аргумент немедленно выгружается в битовое ведро.

16
ответ дан 30 November 2019 в 10:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: