【问题标题】:How can I use randsample in Matlab without running out of memory?如何在 Matlab 中使用 randsample 而不会耗尽内存?
【发布时间】:2020-11-20 07:24:00
【问题描述】:

我想在 Matlab 中对1n 之间的m 整数进行采样不替换,其中

m=10^6;
p=13^5;
n=p*(p-1)/2;

我尝试使用randsample如下

random_indices_pairs=randsample(n,m);

但是,我遇到了内存问题

    Error using zeros
    Requested 1x68929060278 (513.6GB) array exceeds maximum array size preference. Creation of arrays greater than this
    limit may take a long time and cause MATLAB to become unresponsive. See array size limit or preference panel for more
    information.

Error in randsample (line 149)
                x = zeros(1,n); % flags

有没有办法避免这种情况?这里的问题是因为n 很大。

【问题讨论】:

  • 一种方法是随机抽样替换,然后查找重复项,并抽样新值以替换它们。这可能只有在 n >> m 时才合理。替换采样的常规算法需要创建一个包含所有要采样的值的数组。
  • 谢谢。这是我根据你的评论写的:A=randi(n,m,1);[U, I] = unique(A, 'stable');A=A(I);m_to_add=m-size(A,1);while m_to_add>0B=randi(n,m_to_add,1);A=[A;B];[U, I] = unique(A, 'stable');[U, I] = unique(A, 'stable');m_to_add=m-size(A,1);@987654
  • 请用您的代码发布答案!这对未来的访客很有用。我不会重复unique(避免代码重复!),而是重复while true,然后在循环结束时if m_to_add==0, break。另外,A=[A;B] 非常慢,因为它需要复制所有A,最好替换A 中的非唯一元素。不知道代码会是什么样子......
  • 还有一个小问题,即您请求的数组是 abso-effing-lutely humongous (513.6GB)。您确定您的计算机将有足够的内存来允许将 > 500G 的数字加载到内存中吗?不能将其拆分为不太占用内存的较小操作吗?

标签: matlab random


【解决方案1】:

randperm 的双输入版本相当于randsample 无需替换,并且不存在内存问题:

random_indices_pairs = randperm(n, m);

【讨论】:

    【解决方案2】:

    下面的脚本应该可以满足您的需求。

    • 它首先在1n 范围内选择m 随机整数。
    • 然后检查是否有重复条目
    • 如果不是,则脚本停止
    • 如果有重复条目:
      • 它通过所有这些
      • 1n 之间找到另一个随机数
      • 检查整数数组中是否存在新的随机数
        • 如果是,它会找到另一个随机数
        • 如果没有,它会替换数组中的副本并移动到下一个副本
    %% Initialize
    clearvars;
    clc;
    
    m = 10e6;
    p = 13e5;
    n = p*(p-1)/2;
    
    %% Create m random integers between 1 and n
    randomInt = randi(n, m, 1);
    
    %% Find indices where duplicate random integers are
    % Find indices of unique values, take the index of the first occurrence
    [~, I] = unique(randomInt, 'first');
    % Generate an array of all indices
    dupIdx = 1:length(randomInt);
    % Drop indices which point to the first occurrence of the duplicate
    % This leaves indices that point to the duplicate
    dupIdx(I) = [];
    % Free up some memory
    clear I;
    
    if isempty(dupIdx)
        disp('Done!')
    else
        % For those indices find another random number, not yet in randomInt
        disp('Found duplicates, finding new random numbers for those')
        counter = 0;
        for ii = dupIdx
            counter = counter + 1;
            disp(strcat("Resolving duplicate ", num2str(counter), "/", num2str(length(dupIdx))))
            dupe = true;
            % While the replacement is already in the randomInt array, keep
            % looking for a replacement
            while dupe
                replacement = randi(n, 1);
                if ~ismember(replacement, randomInt)
                    % When replacement is unique in randomInt
                    % Put replacement in the randomInt array at the right index
                    randomInt(ii) = replacement;
                    dupe = false;
                end
            end
        end
    end
    
    

    【讨论】:

      【解决方案3】:

      基于其中一个 cmets(评论还暗示了可能的改进)。

      A=randi(n,m,1);
      [U, I] = unique(A, 'stable');
      A=A(I);
      m_to_add=m-size(A,1);
      
      while m_to_add>0
            B=randi(n,m_to_add,1);
            A=[A;B];
            [U, I] = unique(A, 'stable');
            A=A(I);
            m_to_add=m-size(A,1);
      end
      

      【讨论】:

      • 很高兴你找到了方法!如果您需要更快的速度,我发布的答案几乎快了一秒(即使使用disp 语句):)
      猜你喜欢
      • 1970-01-01
      • 2021-02-10
      • 1970-01-01
      • 2010-11-06
      • 2022-11-11
      • 2011-04-05
      • 1970-01-01
      • 1970-01-01
      • 2019-12-26
      相关资源
      最近更新 更多