Matlab - selecting values - matlab

Suppose I have a matrix
A = [1,2,3,4,5 ; 1,1,1, 21, 43]
I want to select the entries from the first row that have a 1 in the row below them, basically end up with [1,2,3] as a result. How do I do this? Thank you very much

You can use logical indexing like this:
result = A(1, A(2,:) == 1)
This says take the first row of A and columns for which the expression A(2,:) == 1 holds true.
A(2,:) == 1 checks for every column in row 2 whether the value is 1 and returns an array of true or false that acts as a selector as described above. In your example, it would produce an array [1 1 1 0 0].

Related

matlab return every second occurrence of value in vector

I have a vector with ID numbers that repeat an even number of times. I am only interested in every second time each number appears. I want to create a boolean mask that gives a true/1 for each second occurance of a number. I have already done this with a loop, but the actual vector will contain millions of elements, so the loop is too slow. I need a "vectorized" solution.
Here is an example Vector:
101
102
103
101
104
102
101
103
101
104
This should output the following mask:
0 (first occurrence of 101)
0 (first occurrence of 102)
0 (first occurrence of 103)
1 (second occurrence of 101)
0 (first occurrence of 104)
1 (second occurrence of 102)
0 (third occurrence of 101)
1 (second occurrence of 103)
1 (fourth occurrence of 101)
1 (second occurrence of 104)
You can do this very easily with a combination of unique and accumarray. First assign each value a unique ID, then bin all array locations together that are part of the same ID. You'll need to sort them as accumarray doesn't guarantee an order when you are binning things together. The output of this will be a cell array where each cell gives you the array locations that occurred for a particular index.
Once you do this, extract out every second element from each cell generated from accumarray, then use these to set all of the corresponding locations in a mask to 1. You can use a combination of cellfun, which can be used to process each cell individually and extracting every second element to create a new cell array, and vertcat which can be used to stack all of the cell arrays together into one final index array. This index array can be used to accomplish setting the locations in your mask to true:
%// Your data
V = [101,102,103,101,104,102,101,103,101,104];
%// Get list of unique IDs
[~,~,id] = unique(V,'stable');
%// Bin all of the locations in V together that belong to the
%// same bin
out = accumarray(id, (1:numel(V)).',[], #(x) {sort(x)}); %'
%// Extract out every second value that is for each bin
out2 = cellfun(#(x) x(2:2:end), out, 'uni', 0);
%// Create a mask and set the corresponding locations to true
mask = false(numel(V), 1);
mask(vertcat(out2{:})) = 1;
We get:
>> mask
mask =
0
0
0
1
0
1
0
1
1
1
Let's bsxfun it for a vectorized solution -
%// Assuming A as the input vector
M = bsxfun(#eq,A(:),unique(A(:).')) %//'
out = any(M - mod(cumsum(M,1).*M,2),2)
Here is one approach:
A = [101,102,103,101,104,102,101,103,101,104];
IDs = unique(A); % Find all the IDs present
test = arrayfun(#(x) find(A==x), IDs, 'UniformOutput', false); % Per ID, find where A == ID
repeatidx = cellfun(#(x) x(2:2:length(x)), test, 'UniformOutput', false); % Dump out the second match
repeatidx = cell2mat(repeatidx); % Flatten the cell array
B = false(size(A)); % Intialize output boolean array
B(repeatidx) = true; % Set true values based on repeatidx
Which returns:
B =
0 0 0 1 0 1 0 1 1 1

Condition execute for different columns in each row

A = [0,0,1,0,1,0,1,0,0,0;
0,0,0,0,1,0,1,0,0,0;
0,0,1,0,1,0,1,0,0,0];
B = [2,5;
1,6;
3,10];
Expected Output Cell Array:
C = [1,1,1,1; %// 2-3-4, 3-4-5, 4-5, 5
0,0,1,1,1,0; %// 1-2-3, 2-3-4, 3-4-5, 4-5-6, 5-6, 6
1,1,1,1,1,0,0,0]; %// 3-4-5, 4-5-6, 5-6-7, 7-8-9, 8-9-10, 9-10, 10
Matrix B includes which columns should be used to execute the condition on Matrix A. For example, first row of B is 2 and 5; so elements between 2nd 5th column of matrix A should be used to execute the condition. Second row of B is 1 and 6; so elements between 1st 6th column should be used to execute the condition. And so on...
The condition: if sum of successive 3 elements is bigger than or equal to 1 then write 1 to matrix C; otherwise write 0. For example, A includes 0,1,0 as three successive elements (sum is 0+1+0=1), so write 1 to matrix C. Another example, first three elements of A in second row are 0,0,0 (sum is 0), so write 0 to matrix C. And so on...
"Sometimes it can be considered only 1 or 2 successive elements."
For example, condition execution of first row of A ends with 5th column, so only value 5th column should be considered; which is 1. So 1 is written to matrix C.
Explaining the first row of C:
1, since (sum of 2,3,4 elements of A(1,:)) >= 1
1, since (sum of 3,4,5 elements of A(1,:)) >= 1
since max limit is 5, only 2 successive elements are taken here
1, since (sum of 4,5 elements alone of A(1,:)) >= 1
since max limit is 5, only 1 successive element is taken here
1, since (sum of 5th element alone of A(1,:)) >= 1
Without for loop, only with matrix operations, how can I do this complex task? or any trick?
Using mat2cell, cellfun, im2col and any
subMatLen = 3;
%// Converting both A & B matrix to Cell Arrays to perform operations Row-wise
AC = mat2cell(A,ones(1,size(A,1)),size(A,2));
BC = mat2cell(B,ones(1,size(B,1)),size(B,2));
%// Getting only the columns of each rows within the limits specified by Matrix B
%// Also appended with zeros for my own convenience as it wont affect the 'summing' process
out = cellfun(#(x,y) [x(y(1):y(2)),zeros(1,subMatLen-1)],AC, BC, 'uni', 0);
%// Finally taking each 1x3 sliding sub-matrix and returning 1 if `any` of it is non-zero
%// which is equivalent to summing and checking whether they are >= 1
out = cellfun(#(x) any(im2col(x, [1,subMatLen], 'sliding')), out, 'uni', 0);
Your Sample Input:
A = [0,0,1,0,1,0,1,0,0,0;
0,0,0,0,1,0,1,0,0,0;
0,0,1,0,1,0,1,0,0,0];
B = [2,5;
1,6;
3,10];
Output:
>> celldisp(out)
out{1} =
1 1 1 1
out{2} =
0 0 1 1 1 0
out{3} =
1 1 1 1 1 0 0 0
If you want them as a single row or column matrix, you could add this to the bottom of the code:
out = cat(2,out{:})
or
out = (cat(2,out{:})).'

What does it mean to use logical indexing/masking to extract data from a matrix? (MATLAB)

I am new to matlab and I was wondering what it meant to use logical indexing/masking to extract data from a matrix.
I am trying to write a function that accepts a matrix and a user-inputted value to compute and display the total number of values in column 2 of the matrix that match with the user input.
The function itself should have no return value and will be called on later in another loop.
But besides all that hubbub, someone suggested that I use logical indexing/masking in this situation but never told me exactly what it was or how I could use it in my particular situation.
EDIT: since you updated the question, I am updating this answer a little.
Logical indexing is explained really well in this and this. In general, I doubt, if I can do a better job, given available time. However, I would try to connect your problem and logical indexing.
Lets declare an array A which has 2 columns. First column is index (as 1,2,3,...) and second column is its corresponding value, a random number.
A(:,1)=1:10;
A(:,2)=randi(5,[10 1]); //declares a 10x1 array and puts it into second column of A
userInputtedValue=3; //self-explanatory
You want to check what values in second column of A are equal to 3. Imagine as if you are making a query and MATLAB is giving you binary response, YES (1) or NO (0).
q=A(:,2)==3 //the query, what values in second column of A equal 3?
Now, for the indices where answer is YES, you want to extract the numbers in the first column of A. Then do some processing.
values=A(q,2); //only those elements will be extracted: 1. which lie in the
//second column of A AND where q takes value 1.
Now, if you want to count total number of values, just do:
numValues=length(values);
I hope now logical indexing is clear to you. However, do read the Mathworks posts which I have mentioned earlier.
I over simplified the code, and wrote more code than required in order to explain things. It can be achieved in a single-liner:
sum(mat(:,2)==userInputtedValue)
I'll give you an example that may illustrate what logical indexing is about:
array = [1 2 3 0 4 2];
array > 2
ans: [0 0 1 0 1 0]
using logical indexing you could filter elements that fullfil a certain condition
array(array>2) will give: [3 4]
you could also perform alterations to only those elements:
array(array>2) = 100;
array(array<=2) = 0;
will result in "array" equal to
[0 0 100 0 100 0]
Logical indexing means to have a logical / Boolean matrix that is the same size as the matrix that you are considering. You would use this as input into the matrix you're considering, and any locations that are true would be part of the output. Any locations that are false are not part of the output. To perform logical indexing, you would need to use logical / Boolean operators or conditions to facilitate the selection of elements in your matrix.
Let's concentrate on vectors as it's the easiest to deal with. Let's say we had the following vector:
>> A = 1:9
A =
1 2 3 4 5 6 7 8 9
Let's say I wanted to retrieve all values that are 5 or more. The logical condition for this would be A >= 5. We want to retrieve all values in A that are greater than or equal to 5. Therefore, if we did A >= 5, we get a logical vector which tells us which values in A satisfy the above condition:
>> A >= 5
ans =
0 0 0 0 1 1 1 1 1
This certainly tells us where in A the condition is satisfied. The last step would be to use this as input into A:
>> B = A(A >= 5)
B =
5 6 7 8 9
Cool! As you can see, there isn't a need for a for loop to help us select out elements that satisfy a condition. Let's go a step further. What if I want to find all even values of A? This would mean that if we divide by 2, the remainder would be zero, or mod(A,2) == 0. Let's extract out those elements:
>> C = A(mod(A,2) == 0)
C =
2 4 6 8
Nice! So let's go back to your question. Given your matrix A, let's extract out column 2.
>> col = A(:,2)
Now, we want to check to see if any of column #2 is equal to a certain value. Well we can generate a logical indexing array for that. Let's try with the value of 3:
>> ind = col == 3;
Now you'll have a logical vector that tells you which locations are equal to 3. If you want to determine how many are equal to 3, you just have to sum up the values:
>> s = sum(ind);
That's it! s contains how many values were equal to 3. Now, if you wanted to write a function that only displayed how many values were equal to some user defined input and displayed this event, you can do something like this:
function checkVal(A, val)
disp(sum(A(:,2) == val));
end
Quite simply, we extract the second column of A and see how many values are equal to val. This produces a logical array, and we simply sum up how many 1s there are. This would give you the total number of elements that are equal to val.
Troy Haskin pointed you to a very nice link that talks about logical indexing in more detail: http://www.mathworks.com/help/matlab/math/matrix-indexing.html?refresh=true#bq7eg38. Read that for more details on how to master logical indexing.
Good luck!
%% M is your Matrix
M = randi(10,4)
%% Val is the value that you are seeking to find
Val = 6
%% Col is the value of the matrix column that you wish to find it in
Col = 2
%% r is a vector that has zeros in all positions except when the Matrix value equals the user input it equals 1
r = M(:,Col)==Val
%% We can now sum all the non-zero values in r to get the number of matches
n = sum(r)
M =
4 2 2 5
3 6 7 1
4 4 1 6
5 8 7 8
Val =
6
Col =
2
r =
0
1
0
0
n =
1

Find a column that only contains a 1 Matlab

I know that there is the command
A(:, find(sum(abs(A)) == 1)) = []
and that will find which columns summed up equals one and then removes them. This is not what I am looking for because if a row contains a 2 and a -1 it will remove that row. But I am trying to find a column that contains all zeros and a 1 and then the command will set that 1 to a zero.
Any help will be greatly appreciated.
EX:
A column of zeros
[1 2 3
0 3 2
0 1 2]
I want the first column to then be changed to a column of zeros
Try this:
sum(a)==1 & sum(a==1) & ~sum(a>1) & ~sum(a<0)
The first statement will be true when the column sums 1
The second will be true when there is at least a 1
The third will be true when there are no numbers greater than 1
The fourth will be true when there are no numbers less than 0
So, only 1s and 0s that add up to 1
The final result will be a vector of 1s and 0s (1==true, 0=false)
To change those single 1s in columns to 0 do:
a(:,sum(a)==1 & sum(a==1) & ~sum(a>1) & ~sum(a<0))=0
You need to merge those two conditions :
idx = find ((sum(a==1)==1));
idx2 = find ((sum(abs(a)) == 1));
The first one search for columns where their only one number "1".
And the second search for columns where the absolute sums is only 1, so no problem with 2,-1,-1,1 !
You're almost there. Just needed to assign 0 instead of deleteting using []
A(:, find(sum(abs(A)) == 1)) = 0
A simpler expression would be:
A(:, sum(A==1)==1 & sum(abs(A))==1) = 0;
Explanation:
A==1 - returns a boolean array with 1's where A==1, 0's everywhere else
sum(A==1) - sums over the first dimension of the boolean array: will ==1 where there is exactly one 1
sum(abs(A)) - when there is exactly one 1, this sum will ==1 only if the rest are zero

Deleting columns in array with zeros

I have an array that starts of with zeros and continues into other numbers
I would like to delete the columns in the array that start off with zero but keep the other numbers
example of an column array below:
x= [0 0 0 0 0 2 4 6 8 0 1 2];
Answer of column array would look like
x= 2 4 6 8 0 1 2
I'm using octave 3.4.2/matlab
Thanks
Here is the code:
x = x(find(x~=0, 1):end);
or
x(1:find(x~=0,1)-1) = [];
The find command should work for this.
Assuming your vector is x:
find(x ~= 0)
Will return all indices where x is non-zero. Just grab the first index and go from there to delete all values from 1 to index.
Logical indexing will work just fine in this case: i.e.,
y = x(:,x(1,:)~=0)
will do the job for you. The inner logical comparison, x(1,:)~=0 returns true for every column whose first element is not zero. The indexing operation, x(:,...) selects only those columns for which the logical comparison returned true.