MATLAB Answers

Translated by

このページのコンテンツは英語から自動翻訳されています。自動翻訳をオフにする場合は「<a class="turn_off_mt" href="#">ここ</a>」をクリックしてください。

0

How to "filter" an N-D array with matrix indexing?

Antoine Purier さんによって質問されました 2017 年 11 月 15 日
最新アクティビティ Antoine Purier さんによって 編集されました 2017 年 11 月 15 日
Hi Matlab users,
First post on Mathworks!
I am creating a generic function to calculate percentiles and confidence intervals for N-D input arrays. And that is where the problem is, because I want it to be able to deal with any array dimensions.
To explain the problem, I will take a simple 3D case. I want to avoid loops for this type of operation.
Basically I have an input 3D array like the following: a = randn(10,3,3)
a(:,:,1) =
1.3514 -0.8655 0.1837
-0.2248 -0.1765 -0.4762
-0.5890 0.7914 0.8620
-0.2938 -1.3320 -1.3617
-0.8479 -2.3299 0.4550
-1.1201 -1.4491 -0.8487
2.5260 0.3335 -0.3349
1.6555 0.3914 0.5528
0.3075 0.4517 1.0391
-1.2571 -0.1303 -1.1176
a(:,:,2) =
1.2607 0.4669 -0.9415
0.6601 -0.2097 -0.1623
-0.0679 0.6252 -0.1461
-0.1952 0.1832 -0.5320
-0.2176 -1.0298 1.6821
-0.3031 0.9492 -0.8757
0.0230 0.3071 -0.4838
0.0513 0.1352 -0.7120
0.8261 0.5152 -1.1742
1.5270 0.2614 -0.1922
a(:,:,3) =
-0.2741 0.2761 -3.0292
1.5301 -0.2612 -0.4570
-0.2490 0.4434 1.2424
-1.0642 0.3919 -1.0667
1.6035 -1.2507 0.9337
1.2347 -0.9480 0.3503
-0.2296 -0.7411 -0.0290
-1.5062 -0.5078 0.1825
-0.4446 -0.3206 -1.5651
-0.1559 0.0125 -0.0845
Everything is always calculated along the x dimensions (permutation step realized beforehand). I calculate previously in my script the index of the values I want to keep, my confidence intervals lower boundaries. ciLowerInd
ciLowerInd =
1
3
5
I want to keep the 1st, 3rd and 5th values of each columns in all the other dimensions than the first one, to end up with an output array of dimensions 3x3x3.
So the output would be :
b(:,:,1)
1.3514 -0.8655 0.1837
-0.5890 0.7914 0.8620
-0.8479 -2.3299 0.4550
b(:,:,2)
1.2607 0.4669 -0.9415
-0.0679 0.6252 -0.1461
-0.2176 -1.0298 1.6821
b(:,:,3)
-0.2741 0.2761 -3.0292
-0.2490 0.4434 1.2424
1.6035 -1.2507 0.9337
So I repmat these 3 index values to get a 3x3x3 dimensions array :
ciLowerInd(:,:,1) =
1 1 1
3 3 3
5 5 5
ciLowerInd(:,:,2) =
1 1 1
3 3 3
5 5 5
ciLowerInd(:,:,3) =
1 1 1
3 3 3
5 5 5
So my question is : Is there a way to kind of filter the input array ("a" in this case") to get an output array of same size as indexing matrix ciLowerInd and keeping only the 1st, 3rd and 5th values of each columns of a, to end up with something like array "b"? All this without looping to be able to deal with N dimensions.
I hope it was clear enough.
Thanks for your help
Antoine

  0 件のコメント

サインイン to comment.

2 件の回答

回答者: Stephen Cobeldick
2017 年 11 月 15 日
編集済み: Stephen Cobeldick
2017 年 11 月 15 日
 採用された回答

One efficient way to achieve this for any ND array is to call subsref directly:
>> C = repmat({':'},1,ndims(a)); % colons for all trailing dimensions
>> C{1} = [1,3,5]; % indices for first dimension
>> b = subsref(a,substruct('()',C))
b(:,:,1) =
1.35140 -0.86550 0.18370
-0.58900 0.79140 0.86200
-0.84790 -2.32990 0.45500
b(:,:,2) =
1.260700 0.466900 -0.941500
-0.067900 0.625200 -0.146100
-0.217600 -1.029800 1.682100
b(:,:,3) =
-0.27410 0.27610 -3.02920
-0.24900 0.44340 1.24240
1.60350 -1.25070 0.93370
Or you can use C directly into a (thank you Andrei Bobrov):
>> b = a(C{:})
b(:,:,1) =
1.35140 -0.86550 0.18370
-0.58900 0.79140 0.86200
-0.84790 -2.32990 0.45500
b(:,:,2) =
1.260700 0.466900 -0.941500
-0.067900 0.625200 -0.146100
-0.217600 -1.029800 1.682100
b(:,:,3) =
-0.27410 0.27610 -3.02920
-0.24900 0.44340 1.24240
1.60350 -1.25070 0.93370

  4 件のコメント

Andrei Bobrov
2017 年 11 月 15 日
ndim = repmat({':'},1,ndims(a));
ndim{1} = 1:2:5;
b = a(ndim{:});
Stephen Cobeldick
2017 年 11 月 15 日
@Andrei Bobrov: true, I forgot that one can pass the char ':' as an index. Very neat.
Antoine Purier 2017 年 11 月 15 日
Thanks Stephen and Andrei!
Now if one of my indices is below one (less than the first rank) or above the x-dimension size (11th rank on only 10 data), I would like to set the value of "b" to either -Inf or +Inf. And still keep the same output array size.
If I put a Nan or Inf in the C cell array it is not working obviously, so do I need to refilter after or is there a simpler way?

サインイン to comment.


回答者: José-Luis
2017 年 11 月 15 日

data = rand(10,3,3);
idx = (1:2:5)';
dims = size(data);
to_add = cumprod(dims);
for ii = 2:numel(dims)
shape = ones(1,ii);
shape(end) = dims(ii);
idx = bsxfun(@plus,idx,reshape((0:dims(ii)-1).*to_add(ii-1),shape));
end
result = data(idx);

  1 件のコメント

Antoine Purier 2017 年 11 月 15 日
Thanks for your post Jose-Luis! It seems that Stephens answer is the one that suits the best for what I want to achieve, in only 3 lines of code.

サインイン to comment.



Translated by