在MATLAB中从一个非常大的数组中按索引选择n个加权元素

时间:2012-02-24 14:54:56

标签: matlab matrix random-sample weighted

假设我有一个非常大的方阵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循环也需要很长时间。有更有效的方法吗?也许如果我以某种方式对矩阵进行矢量化?

*编辑我应该提到我无法访问统计工具箱

非常感谢提前。

3 个答案:

答案 0 :(得分:1)

randsampledocs)是你的朋友。我会使用以下方法转换为索引然后返回下标:

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)

我想我实际上是通过取消矢量化来解决这个问题。也就是说,删除所有高级调用和昂贵的操作,并使用预定义的数组和简单的操作将其剥离到基本要素。

算法的核心是:

  1. 确定权重之和

  2. 在0和权重之和中选择n个随机数,对它们进行排序。

  3. 手动实现cumsum循环。但是,不是存储所有累积总和,而是将索引存储在从当前随机数小于当前随机数的位置跳过的索引。

  4. 在代码中(有一些时间装备),看起来像这样:

    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值,因此您不需要重新计算。

      • 针对randIndexes0检查total的最低和最高值。如果randIndexes(1) is larger than total-randIndexes(结束), then increment ixM from次数(M)to 1 , rather than from 1 to次数(M)`。