How to "filter" an N-D array with matrix indexing?
12 visualizzazioni (ultimi 30 giorni)
Mostra commenti meno recenti
Antoine Purier
il 15 Nov 2017
Modificato: Antoine Purier
il 15 Nov 2017
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 Commenti
Risposta accettata
Stephen23
il 15 Nov 2017
Modificato: Stephen23
il 15 Nov 2017
>> 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 Commenti
Più risposte (1)
José-Luis
il 15 Nov 2017
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);
Vedere anche
Categorie
Scopri di più su Matrices and Arrays in Help Center e File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!