Я думаю, что на самом деле решил бы это, не векторизация. То есть удалите все высокоуровневые вызовы и дорогостоящие операции и сведите их к основному, используя только предопределенные массивы и простые операции.
Ядром алгоритма будет:
Определить сумму весов
Выберите n случайных чисел между 0 и суммой весов, отсортируйте их.
Вручную реализовать цикл cumsum. Однако вместо сохранения всех накопленных сумм просто храните индексы, в которых сумма перепрыгивает с меньшего, чем текущее случайное число, до большего, чем текущее случайное число.
В коде (с небольшой синхронизацией) это выглядит так:
tic
for ixTiming = 1:1000
M = abs(randn(50));
M_size = size(M, 2);
n = 8;
total = sum(M(:));
randIndexes = sort(rand(n,1) * total);
list = zeros(n,1);
ixM = 1;
ixNextList = 1;
curSum = 0;
while ixNextList<=n && ixM<numel(M)
while curSum<randIndexes(ixNextList) && ixM<=numel(M)
curSum = curSum+M(ixM);
ixM = ixM + 1;
end
list(ixNextList) = ixM;
ixNextList = ixNextList+1;
end
[i_list, j_list] = ind2sub(size(M),list);
end
toc; %0.216 sec. on my computer
Сравните это с кодом в исходном вопросе:
tic
for ixTiming = 1:1000
M = abs(randn(50));
M_size = size(M, 2);
n = 8;
for m = 1:M_size
xMean(m) = mean(M(:, m));
end
[~, j_list] = histc(rand(n, 1), cumsum([0; xMean'./sum(xMean)']));
for c = 1:n
[~, i_list(c)] = ...
histc(rand(1, 1), cumsum([0;, M(:, j_list(c))./sum(M(:, j_list(c)))]));
end
end
toc; %1.10 sec on my computer
Предостережения и оптимизации.
Я не проверял это подробно. Операции со случайными числами трудны для правильного случайного поведения. Проведите несколько тестовых случаев на множестве наборов Монте-Карло, чтобы убедиться, что поведение соответствует ожидаемому. Особенно следите за ошибками типа "один за другим".
Профиль, а затем искать дополнительные улучшения в любых медленных шагах. Некоторые возможности.
Сохраняйте значение total
при изменении M
, поэтому вам не нужно пересчитывать.
Проверьте минимальное и максимальное значение randIndexes
против 0
и total
. Если randIndexes(1) is larger than
total-randIndexes (конец) , then increment
ixM from
цифра (M) to
1 , rather than from
1 to
цифра (M) `.