MATLAB:使用 sub2ind 3d 在给定的行和列索引处从 3d 矩阵中提取值
MATLAB: extract values from 3d matrix at given row and column indcies using sub2ind 3d
我有一个包含我的数据的 3d 矩阵 A
。在由行和列索引定义的多个位置,如矩阵 row_col_idx
所示,我想提取沿三维的所有数据,如下所示:
A = cat(3,[1:3;4:6], [7:9;10:12],[13:15;16:18],[19:21;22:24]) %matrix(2,3,4)
row_col_idx=[1 1;1 2; 2 3];
idx = sub2ind(size(A(:,:,1)), row_col_idx(:,1),row_col_idx(:,2));
out=nan(size(A,3),size(row_col_idx,1));
for k=1:size(A,3)
temp=A(:,:,k);
out(k,:)=temp(idx);
end
out
这段代码的输出结果如下:
A(:,:,1) =
1 2 3
4 5 6
A(:,:,2) =
7 8 9
10 11 12
A(:,:,3) =
13 14 15
16 17 18
A(:,:,4) =
19 20 21
22 23 24
out =
1 2 6
7 8 12
13 14 18
19 20 24
输出符合预期。然而,实际的 A
和 row_col_idx
是巨大的,因此这段代码的计算量很大。是否可以对这段代码进行 vertorize 处理以避免循环和 temp
矩阵?
一种更有效的方法是使用 row_col_idx
向量的条目从 A
中选择元素。我已经针对大型矩阵比较了这两种方法,如您所见,计算速度要快得多。
对于问题中给出的A
,它给出了相同的输出
A = rand([2,3,10000000]);
row_col_idx=[1 1;1 2; 2 3];
idx = sub2ind(size(A(:,:,1)), row_col_idx(:,1),row_col_idx(:,2));
out=nan(size(A,3),size(row_col_idx,1));
tic;
for k=1:size(A,3)
temp=A(:,:,k);
out(k,:)=temp(idx);
end
time1 = toc;
%% More efficient method:
out2 = nan(size(A,3),size(row_col_idx,1));
tic;
for jj = 1:size(row_col_idx,1)
out2(:,jj) = [A(row_col_idx(jj,1),row_col_idx(jj,2),:)];
end
time2 = toc;
fprintf('Time calculation 1: %d\n',time1);
fprintf('Time calculation 2: %d\n',time2);
给出输出:
Time calculation 1: 1.954714e+01
Time calculation 2: 2.998120e-01
这可以使用linear indexing and implicit expansion向量化:
out = A( row_col_idx(:,1) + ...
(row_col_idx(:,2)-1)*size(A,1) + ...
(0:size(A,1)*size(A,2):numel(A)-1) ).';
以上构建了一个与输出一样大的索引矩阵。如果由于内存限制这是不可接受的,可以通过重塑 A
:
来避免
sz = size(A); % store size A
A = reshape(A, [], sz(3)); % collapse first two dimensions
out = A(row_col_idx(:,1) + (row_col_idx(:,2)-1)*sz(1),:).'; % linear indexing along
% first two dims of A
A = reshape(A, sz); % reshape back A, if needed
我有一个包含我的数据的 3d 矩阵 A
。在由行和列索引定义的多个位置,如矩阵 row_col_idx
所示,我想提取沿三维的所有数据,如下所示:
A = cat(3,[1:3;4:6], [7:9;10:12],[13:15;16:18],[19:21;22:24]) %matrix(2,3,4)
row_col_idx=[1 1;1 2; 2 3];
idx = sub2ind(size(A(:,:,1)), row_col_idx(:,1),row_col_idx(:,2));
out=nan(size(A,3),size(row_col_idx,1));
for k=1:size(A,3)
temp=A(:,:,k);
out(k,:)=temp(idx);
end
out
这段代码的输出结果如下:
A(:,:,1) =
1 2 3
4 5 6
A(:,:,2) =
7 8 9
10 11 12
A(:,:,3) =
13 14 15
16 17 18
A(:,:,4) =
19 20 21
22 23 24
out =
1 2 6
7 8 12
13 14 18
19 20 24
输出符合预期。然而,实际的 A
和 row_col_idx
是巨大的,因此这段代码的计算量很大。是否可以对这段代码进行 vertorize 处理以避免循环和 temp
矩阵?
一种更有效的方法是使用 row_col_idx
向量的条目从 A
中选择元素。我已经针对大型矩阵比较了这两种方法,如您所见,计算速度要快得多。
对于问题中给出的A
,它给出了相同的输出
A = rand([2,3,10000000]);
row_col_idx=[1 1;1 2; 2 3];
idx = sub2ind(size(A(:,:,1)), row_col_idx(:,1),row_col_idx(:,2));
out=nan(size(A,3),size(row_col_idx,1));
tic;
for k=1:size(A,3)
temp=A(:,:,k);
out(k,:)=temp(idx);
end
time1 = toc;
%% More efficient method:
out2 = nan(size(A,3),size(row_col_idx,1));
tic;
for jj = 1:size(row_col_idx,1)
out2(:,jj) = [A(row_col_idx(jj,1),row_col_idx(jj,2),:)];
end
time2 = toc;
fprintf('Time calculation 1: %d\n',time1);
fprintf('Time calculation 2: %d\n',time2);
给出输出:
Time calculation 1: 1.954714e+01
Time calculation 2: 2.998120e-01
这可以使用linear indexing and implicit expansion向量化:
out = A( row_col_idx(:,1) + ...
(row_col_idx(:,2)-1)*size(A,1) + ...
(0:size(A,1)*size(A,2):numel(A)-1) ).';
以上构建了一个与输出一样大的索引矩阵。如果由于内存限制这是不可接受的,可以通过重塑 A
:
sz = size(A); % store size A
A = reshape(A, [], sz(3)); % collapse first two dimensions
out = A(row_col_idx(:,1) + (row_col_idx(:,2)-1)*sz(1),:).'; % linear indexing along
% first two dims of A
A = reshape(A, sz); % reshape back A, if needed