Matlab 复制/索引3D矩阵可变部分的最快方法

Matlab 复制/索引3D矩阵可变部分的最快方法,matlab,performance,Matlab,Performance,我有大量的3D数据,包括在2D空间采集的一维信号。 处理这些数据的第一步是对所有信号进行阈值化,以找到高振幅脉冲的到达。该脉冲存在于所有信号中,并在不同时间到达。 阈值化后,3D数据集应重新排序,以便每个信号在脉冲到达时开始,之前的信号被丢弃(信号的结尾不重要,到目前为止,我将零连接到所有信号的结尾,以便数据保持相同的大小) 现在,我以以下方式实施了这一点: 首先,我首先计算所有信号中超过阈值的第一个样本的样本数 M = randn(1000,500,500); % example matrix

我有大量的3D数据,包括在2D空间采集的一维信号。 处理这些数据的第一步是对所有信号进行阈值化,以找到高振幅脉冲的到达。该脉冲存在于所有信号中,并在不同时间到达。 阈值化后,3D数据集应重新排序,以便每个信号在脉冲到达时开始,之前的信号被丢弃(信号的结尾不重要,到目前为止,我将零连接到所有信号的结尾,以便数据保持相同的大小)

现在,我以以下方式实施了这一点:

首先,我首先计算所有信号中超过阈值的第一个样本的样本数

M = randn(1000,500,500); % example matrix of realistic size
threshold = 0.25*max(M(:,1,1)); % 25% of the maximum in the first signal as threshold
[~,index] = max(M>threshold); % indices of first sample exceeding threshold in all signals
接下来,我希望所有的信号都被移位,以便它们都从脉冲开始。目前,我已通过以下方式实施:

outM = zeros(size(M));     % preallocation for speed           
for i = 1:size(M,2)
    for j = 1:size(M,3)
        outM(1:size(M,1)+1-index(1,i,j),i,j) = M(index(1,i,j):end,i,j);  
    end
end

这很好,我知道for循环不再那么慢了,但是对于我机器上的数据集,这很容易需要几秒钟的时间。for循环的一次迭代大约需要0.05-0.1秒,对于我来说,仅仅复制一个包含500-2000个双倍值的向量似乎很慢

因此,我已经研究了解决这个问题的最佳方法,但目前我还没有找到更好的方法。 我试过几种方法:3D蒙版、线性索引和并行循环(parfor)

对于3D遮罩,我检查了是否有任何改进。因此,我首先构造一个逻辑掩码,然后比较逻辑掩码索引/复制与双嵌套for循环的速度

%% set up for logical mask copying
AA = logical(ones(500,1));  % only copy the first 500 values after the threshold value
Mask = logical(zeros(size(M)));
Jepla = zeros(500,size(M,2),size(M,3));
for i = 1:size(M,2)
    for j = 1:size(M,3)
        Mask(index(1,i,j):index(1,i,j)+499,i,j) = AA;
    end
end

%% speed comparison
tic
Jepla = M(Mask);
toc

tic
for i = 1:size(M,2)
    for j = 1:size(M,3)
        outM(1:size(M,1)+1-index(1,i,j),i,j) = M(index(1,i,j):end,i,j);  
    end
end
toc
for循环每次都更快,即使复制的内容更多

接下来,线性索引

%% setup for linear index copying

%put all indices in 1 long column
LongIndex = reshape(index,numel(index),1);
% convert to linear indices and store in new variable
linearIndices = sub2ind(size(M),LongIndex,repmat(1:size(M,2),1,size(M,3))',repelem(1:size(M,3),size(M,2))');

% extend linear indices with those of all values to copy
k = zeros(numel(M),1);
count = 1;
for i = 1:numel(LongIndex)
    values = linearIndices(i):size(M,1)*i;
    k(count:count+length(values)-1) = values;
    count = count + length(values);
end
k = k(1:count-1);

% get linear indices of locations in new matrix
l = zeros(length(k),1);
count = 1;
for i = 1:numel(LongIndex) 
    values = repelem(LongIndex(i)-1,size(M,1)-LongIndex(i)+1);
    l(count:count+length(values)-1) = values;
    count = count + length(values);
end
l = k-l;

% create new matrix
outM = zeros(size(M));

%% speed comparison
tic
outM(l) = M(k);
toc

tic
for i = 1:size(M,2)
    for j = 1:size(M,3)
        outM(1:size(M,1)+1-index(1,i,j),i,j) = M(index(1,i,j):end,i,j);  
    end
end
toc
同样,另一种方法,线性索引,速度要慢得多。 失败后,我学习了并行化,尽管这肯定会加快我的代码速度。 通过阅读parfor的一些文档并尝试一下,我将代码更改为:

gcp;
outM = zeros(size(M));      
inM = mat2cell(M,size(M,1),ones(size(M,2),1),size(M,3));
tic
parfor i = 1:500
    for j = 1:500
        outM(:,i,j) = [inM{i}(index(1,i,j):end,1,j);zeros(index(1,i,j)-1,1)];  
    end
end
end
toc
我修改了它,以便“outM”和“inM”都是切片变量,因为我读到这是最好的。这仍然非常慢,比最初的for循环慢很多

%% set up for logical mask copying
AA = logical(ones(500,1));  % only copy the first 500 values after the threshold value
Mask = logical(zeros(size(M)));
Jepla = zeros(500,size(M,2),size(M,3));
for i = 1:size(M,2)
    for j = 1:size(M,3)
        Mask(index(1,i,j):index(1,i,j)+499,i,j) = AA;
    end
end

%% speed comparison
tic
Jepla = M(Mask);
toc

tic
for i = 1:size(M,2)
    for j = 1:size(M,3)
        outM(1:size(M,1)+1-index(1,i,j),i,j) = M(index(1,i,j):end,i,j);  
    end
end
toc
那么现在的问题是,我是否应该放弃努力提高这一行动的速度?还是有其他方法可以做到这一点?我已经搜索了很多,现在还不知道如何加快搜索速度。 很抱歉问了这么长的问题,但我想展示一下我的努力。
提前谢谢你

不确定在您的情况下是否有一个选项,但这里的单元阵列实际上更快:

outM2 = cell(size(M,2),size(M,3)); 
tic; 
for i = 1:size(M,2)
  for j = 1:size(M,3)
    outM2{i,j} = M(index(1,i,j):end,i,j);  
  end
end
toc
第二个想法产生得更快,批量处理所有必须按相同值移位的数据:

tic;
for i = 1:unique(index).'
    outM(1:size(M,1)+1-i,index==i) = M(i:end,index==i);
end
toc
这完全取决于您的数据,如果这种方法实际上更快。

不确定在您的情况下是否有一个选项,但看起来这里的单元阵列实际上更快:

outM2 = cell(size(M,2),size(M,3)); 
tic; 
for i = 1:size(M,2)
  for j = 1:size(M,3)
    outM2{i,j} = M(index(1,i,j):end,i,j);  
  end
end
toc
第二个想法产生得更快,批量处理所有必须按相同值移位的数据:

tic;
for i = 1:unique(index).'
    outM(1:size(M,1)+1-i,index==i) = M(i:end,index==i);
end
toc
这完全取决于您的数据,如果这种方法实际上更快。

谢谢!这两个都有帮助,我会调查的谢谢!这两个都会有帮助,我会调查的