假设我有一个非常大的方阵M(i,j),这样矩阵中的每个元素代表在加权随机选择中选择元素的概率。我需要从矩阵中采样n个元素(通过(i,j)索引)和替换。权重将在主循环的每次迭代中改变。
目前,我使用的内容如下:
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
但这似乎是一种相当笨重的方法,由于for循环也需要很长时间。有更有效的方法吗?也许如果我以某种方式对矩阵进行矢量化?
*编辑我应该提到我无法访问统计工具箱
非常感谢提前。
答案 0 :(得分:1)
randsample
(docs)是你的朋友。我会使用以下方法转换为索引然后返回下标:
selected_indexes = randsample(1:numel(M), n, true, M(:));
[sub_i, sub_j] = ind2sub(size(M), selected_indexes);
您可能需要在M
上进行一些转置以获得适当的尺寸。
答案 1 :(得分:0)
% M is ixj
xMean = transpose(mean(M,1));
%xMean is jx1, so i hope n == j
[~, j_list] = histc(rand(n, 1), cumsum([0; xMean./sum(xMean)]));
% j_list is not used? but is j x 1
cumsumvals = cumsum([zeros(1,jj);, M(:,j_list(1:n))./kron(sum(M(:,j_list(1:n))),ones(ii,1))],1),1)
% cumsumvals is i+1 x j, so looks like it should work
% but histc won't work with a matrix valued edge parameter
% you'll need to look into hist3 for that
for c = 1:n
[~, i_list(c)] = ...
histc(rand(1, 1), cumsumvals(:,c));
end
所以它更接近,但你需要hist3来完全矢量化。
答案 2 :(得分:0)
我想我实际上是通过取消矢量化来解决这个问题。也就是说,删除所有高级调用和昂贵的操作,并使用预定义的数组和简单的操作将其剥离到基本要素。
算法的核心是:
确定权重之和
在0和权重之和中选择n个随机数,对它们进行排序。
手动实现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
警告和优化。
我没有对此进行过广泛的测试。随机数操作很难用于随机行为。在很多monte carlo集上运行一些测试用例,以确保行为符合预期。特别要注意一个一个类型的错误。
配置文件,然后在任何慢速步骤中寻找其他改进。一些可能性。
在您更改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)`。