【问题标题】:What's the fastest way to remove or change large number of entries in arrays in MATLAB?在 MATLAB 中删除或更改数组中大量条目的最快方法是什么?
【发布时间】:2023-03-18 23:27:01
【问题描述】:

我想使用 MATLAB 将 4D 数组 M_ ijkl 中的多个值更改为 NaN。 我使用find 来获取满足 k = 2 和 l特定条件的索引 ij > = 4(在我的情况下,它是 t_4 时间位置的 y 分量)。我现在想将这些 ij 组合以及所有 kl 的所有条目设置为 NaN .

我用这个方法来做(nkjt的例子):

% initialise
M = zeros(10,10,2,4);

% set two points in (:,:,2,4) to be above threshold. 
M(2,4,2,4)=5; 
M(6,8,2,4)=5; 

% find and set to NaN
[i,j] = find(M(:,:,2,4) > 4);
M(i,j,:,:)= NaN;

% count NaNs
sum(isnan(M(:)))   % returns 32

如本例所示,此方法非常慢:

M = rand(360,360,2,4);
threshold = 0.5;

% slow and wrong result
[i,j] = find(M(:,:,2,4) > threshold);
tic;
M(i,j,:,:) = NaN;
toc;

Elapsed time is 54.698449 seconds.

请注意,tictoc 不会为 find 计时,所以这不是问题。

在 Rody 和 njkt 的帮助下,我也意识到我的方法实际上并没有达到我想要的效果。我只想使用find 找到的组合 ij 更改条目(适用于所有 kl em>),即[2,4,:,:][6,8,:,:],但不是 [2,8,:,:][6,4,:,:]。在第一个示例中,sum(isnan(M(:))) 应该返回 16。

【问题讨论】:

    标签: arrays performance matlab nan


    【解决方案1】:

    通过重塑 M 对我来说更快:

    M = rand(360,360,2,4);
    M = reshape(M,[360*360,2,4]);
    maximum = 0.05;
    n = find(M(:,2,4) > maximum);
    
    tic;
    M(n,:,:) = NaN;
    M = reshape(M,[360, 360, 2, 4]);
    toc;
    

    预计到达时间:

    M(i,j,:,:)= NaN;将所有 k,l 的 i, j 的所有组合设置为 NaN(如罗迪的回答中所述)。

    例如:

    % initialise
    M = zeros(10,10,2,4);
    
    % set two points in (:,:,2,4) to be above threshold. 
    M(2,4,2,4)=5; 
    M(6,8,2,4)=5; 
    
    % find and set to NaN
    [i,j] = find(M(:,:,2,4) > 4);
    M(i,j,:,:)= NaN;
    
    % count NaNs
    sum(isnan(M(:)))   % returns 32
    

    例如'(2,4,l,k) = NaN' 还有'(4,2,l,k) = NaN'。

    如果这是您想要的,请在find 之后使用唯一值减小 i,j 的大小。


    就逻辑索引而言,基本上,最好使用A(A>2)=NaN; 而不是n = find(A>2); A(n)=NaN;。在重塑的情况下,您可以使用M(M(:,2,4)>maximum,:,:) = NaN;。我没有 tic/toc 它所以我不知道在这种情况下它是否会更快。

    【讨论】:

    • 我真的不明白为什么,但这与我的代码不同。我通过克隆M 并使用这两种方法对此进行了测试。两个结果数组上的isequal 返回0
    • 我稍微调查了一下。您的解决方案将较少的条目设置为 NaN。它不会更改列 (i,:,k,l)。
    • 这很奇怪;它适用于您给出的玩具问题(包括当我将它带到 M = 3 x 2 x 2 x 4 时)。您是否希望给定 i 的所有 j 也都是 NaN?我的印象是,对于给定的 (i,j),您想要所有的 l,k。注意:如果比较包含 NaN 的数组,isequal 将永远不会返回 1,因为 isequal(NaN,NaN) 为 false。
    • 我以为我希望给定 i 的所有 j 也是 NaN,但我认为这实际上是错误的。所以我认为我的原始代码并没有像我想象的那样做。我认为你的解决方案实际上正在做我想要完成的事情......我现在无法访问 MATLAB,所以我稍后将不得不比较罗迪和你的解决方案。我可能不得不重新提出我的问题。到目前为止谢谢!
    • 你的代码实际上做了我想要的。谢谢! MATLAB 仍然警告我使用逻辑索引而不是 fin
    【解决方案2】:

    你检查过你的结果吗?因为我认为他们错了。例如,如果您有

    A = [...
        1 2 3
        4 5 6
        7 8 9];
    

    并且您想将元素 A(1,1)A(2,3) 设置为 NaN。你正在做的是

    A([1 2], [1 3]) = NaN
    

    但这给了

    A =
       NaN     2   NaN
       NaN     5   NaN
         7     8     9
    

    解决这个问题的最简单和最快的方法是不使用find,而是使用逻辑索引:

    M = rand(360,360,2,4);
    maximum = 0.05;
    tic;
    M(M(:,:,2,4) > maximum) = NaN;
    toc
    

    在我的电脑上提供:

    Elapsed time is 0.003547 seconds.
    

    【讨论】:

    • 这是我尝试过的尝试之一。但是,它与我的代码不同。请注意,我的代码删除了所有索引 kl 的条目,您的代码只是删除了带有 *k*=2 和 *l*=4 的条目。
    • 对不起,我还没有阅读你的答案的第一部分...是的,我想设置索引为 kl的所有条目> 到 NaN。这是所有四次(索引 l)和 xy 组件(索引 k)的位置应设置为 NaN。
    • @frankundfrei:对不起,我误会了。而且我仍然不太确定我是否理解......你能提供一个输入和预期输出的小例子吗?
    • 我将包含一个类似问题的示例。使用 4D 数组有点复杂......
    • 我希望我的插图有助于理解我的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    • 2016-09-29
    • 2011-06-28
    • 1970-01-01
    • 2018-04-27
    • 1970-01-01
    相关资源
    最近更新 更多