Using MATLAB, there are several ways to identify elements from an array for which you wish to perform some action. Depending on how you've chosen the elements, you may either have the list of elements to toss or the list if elements to retain. And you might not have much if any control yourself how the list gets presented to you since the list could be passed to you from another calculation. The lists might be indices, subscripts, or logical arrays (often referred to as masks). Let's look at how you might arrive at such a situation and see what the code looks like to perform one particular action, setting the desired element values to 0.
- General Setup
- Method #1 - Using Subscripts of Keepers
- Method #2 - Using Indices of Keepers
- Method #3 - Using Logical Keepers
- Method #4 - Subscripts for Elements to Set to Zero
- Method #5 - Indices for Elements to Set to Zero
- Method #6 - Using Logical Arrays to Specify Zero Elements
- Which Method(s) Do You Prefer?
Note: I am not discussing efficiency in this article. It is highly dependent on the number of elements in the original array and how many will be retained or thrown out. This article focuses on specifying what to keep or replace.
Here's the setup for this investigation. I will use a fixed matrix for all the methods and always end up with the same final output. The plan is to show you multiple ways to get the result, since different methods may be appropriate under different circumstances.
A = magic(17); Result = A; Result( A < mean(A(:)) ) = 0;
Let's look at the nonzero pattern of Result using spy.
Here's a list of the subscripts for the elements to keep unchanged.
[rA,cA] = find(A > (17^2)/2);
Next we convert the subscripts to indices.
Result1 = zeros(size(A)); indices = sub2ind(size(A),rA,cA); Result1(indices) = A(indices); isequal(Result, Result1)
ans = 1
Why did I convert subscripts to indices? Let me illustrate with a very small example.
matrix = [ -1 1 0; 2 0 -2; 0 3 -3] [rows,cols] = find(matrix==0)
matrix = -1 1 0 2 0 -2 0 3 -3 rows = 3 2 1 cols = 1 2 3
Now let's see what I get if I use the subscripts to address the selected elements:
ans = 0 3 -3 2 0 -2 -1 1 0
I get the full matrix back, even though I selected only 3 elements. This definitely surprised me when I first encountered this. What's happening?
MATLAB matches each row element with each column element. matrix([1 2 3],2) returns the elements from rows 1 through 3 in column 1.
ans = 1 0 3
To learn more about indexing in general, you might want to read these posts or search the MATLAB documentation.
Here we used the single output form of find which returns indices instead of subscripts.
indA = find(A > (17^2)/2); Result2 = zeros(size(A)); Result2(indA) = A(indA); isequal(Result, Result2)
ans = 1
We'll try keeping about half of the elements unchanged.
keepA = (A > (17^2)/2); Result3 = zeros(size(A)); Result3(keepA) = A(keepA); isequal(Result, Result3)
ans = 1
keepA is a logical matrix the same size as A. I use logical indexing to populate Result3 with the chosen values from A.
If instead we have a list of candidates to set to 0, we have an easier time since we don't need to start off with a matrix of zeros. Instead we start with a copy of A.
Result4 = A; [rnotA,cnotA] = find(A <= (17^2)/2);
Convert indices to subscripts, as in method #1.
indices = sub2ind(size(A),rnotA,cnotA);
Now zero out the selected matrix elements.
Result4(indices) = 0; isequal(Result, Result4)
ans = 1
If we're instead given indices, we simply skip the step of converting subscripts and follow similar logic to that in method #4.
Result5 = A; indnotA = find(A <= (17^2)/2); Result5(indnotA) = 0; isequal(Result, Result5)
ans = 1
Finally, if we have a mask for the values to set to 0, we simply use it to select and set elements.
Result6 = A; keepnotA = (A <= (17^2)/2); Result6(keepnotA) = 0; isequal(Result, Result6)
ans = 1
Which method or methods do you naturally find yourself using? Do you ever invert the logic of your algorithm to fit your way of thinking about addressing the data (the ins or the outs)? Please post your thoughts here. I look forward to seeing them.
Get the MATLAB code
Published with MATLAB® 7.6
Comments are closed.
32 CommentsOldest to Newest
A = reshape(1:49, 7, 7); R = 1:2:7; % Rows to remove C = 2:2:7; B = A(setxor(R, 1:end), setxor(C, 1:end)); % or B = A(setdiff(1:end, R), setdiff(1:end, C));--Loren
a(isnan(a)) = ;But if you have a matrix, you aren't guaranteed that the same number of NaNs are in each row/column so you may not end up with a rectangular array. --Loren
n=100; % square nxn matrices n2=n^2; A0=rand(n,n,n); % generate matrices for i=1:n % for each matrix % method 1 of dropping a matrix A1=A0; A1(:,:,i)=; % method 2 of dropping a matrix A2=A0; A2(1:n2)=; % method 3 of dropping a matrix A3=A0(:,:,2:n); % mean computation for comparison purposes mean(A0,3); endnote that upon running profiler, method 3 takes about half the time of method 1, and about 1/3 of the time of method 2. but the mean computation takes far less time than any! this quite surprising result (to me) leads me to have the following questions: 1) why does it take so long? 2) is there a way to make it go *much* faster? many thanks, joshua
n=100; % square nxn matrices n2=n^2; A0=rand(n,n,n); % generate matrices for i=1:n % for each matrix % method 1 of getting mean A1=A0(:,:,2:n); M1=mean(A3,3); % method 2 of getting mean M2=mean(A0(:,:,2:n),3); % mean computation for comparison purposes endrunning the profiler shows that the line to compute M2 takes equally long as the line to compute A1 and M1 combined. and, if i look carefully, i see that actually computing M2, matlab only spends a fraction of the time computing the mean, the rest is passing the variable to the mean function. so my question remains: is there anyway for matlab to not take a long time when dropping elements in an array? trying to trick it by putting it all on one line did not seem to work, sadly ;(