【问题标题】:How to get mean values of certain regions in each slice in 3d matrix using logical indexing MATLAB如何使用逻辑索引MATLAB获取3d矩阵中每个切片中某些区域的平均值
【发布时间】:2015-05-15 16:31:15
【问题描述】:

在 Matlab 中,

如果我有一个如下所示的 3d 矩阵,我想知道每个切片中值大于 5 的区域的平均值。请问如何使用逻辑索引来做到这一点,没有循环?

我希望得到一个 3 x 1 的数组,每个元素表示其对应切片中区域的平均值。

m3d = randi(10,[3,3,3])

m3d(:,:,1) =

 7     7     8
 1     9     8
 9     7     6

m3d(:,:,2) =

10    10     5
 9     7     8
 5     3     3

m3d(:,:,3) =

 9     7     5
 4     1     9
 5     9     1

获取索引

3d_index = m3d > 5;

我的决赛

result = mean(m3d(3d_index));

我不想得到所有地区的平均值

【问题讨论】:

  • 为什么要避免循环?可以很方便地解决您的问题,而且速度也很快。
  • 嗨 CST-Link 44,我必须把它放在一个 while 循环中,我说的是一个 256*256*100 矩阵。所以我尽量避免循环。我认为 Divakar 有一个很好的解决方案。谢谢

标签: matlab matrix vectorization


【解决方案1】:

一种方法 -

%// 3d mask of elements greater than 5
mask = m3d>5

%// Sum of all elements greater than 5 in each slice
sumvals = sum(reshape(m3d.*mask,[],size(m3d,3)))

%// Count of elements great than 5 in each slice
counts = sum(reshape(mask,[],size(m3d,3)))

%// Final output of mean values for the regions with >5 only
out = sumvals./counts

基准测试

这里有一些运行时测试,以了解所有发布的方法的位置。对于测试,我们采用了大小为1500 x 1500 x 100 的随机3D 数组,其值在[1,255] 区间内。接下来列出了基准测试代码 -

m3d = randi(255,1500,1500,100); %// Input 3D array

%// Warm up tic/toc.
for k = 1:50000
    tic(); elapsed = toc();
end

disp('------------------------ With SUMMING and COUNTING ')
tic
%// .... Proposed approach in this solution
toc, clear out counts sumvals mask

disp('------------------------ With FOR-LOOP ')
tic
N   = size(m3d, 3);
out = zeros(N, 1);
for k = 1:size(m3d,3)
        val    = m3d(:,:,k);
        lix    = val>5;
        out(k) = mean(val(lix));
end;
toc, clear out lix val k N

disp('----------------------- With ACCUMARRAY')
tic
ind = m3d>5;
result = accumarray(ceil(find(ind)/size(m3d,1)/size(m3d,2)), m3d(ind), [], @mean);
toc, clear ind result

disp('----------------------- With NANMEAN')
tic
m3d(m3d<5) = NaN; %// Please note: This is a bad practice to change input
out = nanmean(nanmean(m3d,1),2);
toc

运行时

------------------------ With SUMMING and COUNTING 
Elapsed time is 0.904139 seconds.
------------------------ With FOR-LOOP 
Elapsed time is 2.321151 seconds.
----------------------- With ACCUMARRAY
Elapsed time is 4.350005 seconds.
----------------------- With NANMEAN
Elapsed time is 1.827613 seconds.

【讨论】:

  • 只是为了澄清..所有解决方案都给你同样的结果吗?
  • @SanthanSalai 不,我没有检查,如果有兴趣,我会将值正确性部分留给 OP 检查。
【解决方案2】:

您可以使用掩码数组来执行此操作,如下所示,

m3d = randi(10,[3,3,3]);

%Set values less than 5 to NaN
m3d(m3d<5) = NaN
nanmean(nanmean(m3d,1),2)

【讨论】:

  • 使用nanmean的好主意!
  • nanmean 是一个很好知道的函数 :) 您也可以使用 squeeze 使其类似于 OP 所需的输出。此外,您可能不会在nanmean 中使用12,因为它们是默认值。说到这里,你不能使用 nested nanmean,因为它是误导。您可以手动测试它们以了解它。或者您可以尝试将其用于整个切片。只有当所有列具有相同数量的非 NaN 值时,它才会给出正确的结果。
  • 次要注意:nanmean 需要统计工具箱。如果您想实现自己的nanmean 版本,只需计算您正在处理的每行/列或维度有多少NaNs,将NaN 值设置为零,然后执行平均值,只需从维度中的元素总数中减去该数字即可。
【解决方案3】:

这可以通过accumarray 轻松完成:

ind = m3d>5;
result = accumarray(ceil(find(ind)/size(m3d,1)/size(m3d,2)), m3d(ind), [], @mean);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-16
    • 1970-01-01
    • 1970-01-01
    • 2018-03-02
    • 2012-07-10
    • 1970-01-01
    • 2020-01-23
    • 2023-03-04
    相关资源
    最近更新 更多