I have a 2 dimensional array L, and I am trying to create a vector of linear indices ind for each row of this array.
L=
1 5 25 4 0 0
2 3 3 45 5 6
45 5 6 0 0 0
I am using lenr to store the number of non zero elements in each row (starting from column 1).
lenr=
4
6
3
Then I have 1x45 array RULES. Indices stored in L refer to elements in RULES. Since I want to vectorize the code, I decided to create linear indices and then run RULES(ind).
This works perfectly:
ind=sub2ind(size(L),1,lenr(1));
while this doesn't work:
ind=sub2ind(size(L),1:3,1:lenr(1:3));
Any ideas?
UPDATE:
This is what I initially tried to vectorize the code, but it did not works and that's why I checked linear indices:
rul=repmat(RULES,3);
result = rul((L(1:J,1:lenr(1:J))));
If I correctly interpret your edit, you want to create a variable result that contains the elements of RULES indicated by the non-zero elements of L. Note that in general, the best way to vectorize sub2ind is to not use sub2ind.
If you want result to be a linear array, you can simply write
%// transpose so that result is ordered by row
L_transposed = L.';
result = RULES(L_transposed(L_transposed>0));
If, instead, you want result to be an array of the same size as L, with all numbers in L replaced by the corresponding element in RULES, it's even simpler:
result = L;
result(result>0) = RULES(result>0);
Related
I have a m-by-1 matrix, A. I want to find out which elements are duplicates and get their row values. (Just the row values because the matrix is m-by-1.)
I've tried
k = find(~unique(A));
but k contains the wrong values.
Here's an example of what I'm trying to do. Consider the array A;
A = [4
5
5
5
7
8
4];
Since 4 and 5 are the repeated elements here, I would like to get the row values of these elements and put them in a new array. The resulting array would be
RowValues= [1
2
3
4
7];
Note: The above is just an example and the actual array I am dealing with contains rational numbers of the type -0.0038, 1.3438 and so on in the array A.
Here is a solution using intersect:
s = sort(A);
c = intersect(s(1:2:end),s(2:2:end));
RowValues = find(ismember(A,c));
I have compared this method with the method proposed by #SardarUsama with a large [1 x 10000000] input in Octave. Here is the result:
=======INTERSECT==========
Elapsed time is 1.94979 seconds.
=======ACCUMARRAY==========
Elapsed time is 2.5205 seconds.
Find the count of each element of A using unique and accumarray, filter out the non-repeating values, use ismember to get the logical indices of repeating values and then use find to convert them to linear indices.
[C, ~, ic] = unique(A);
RowValues = find(ismember(A, C(accumarray(ic,1)>1)));
Why you get the wrong indices with your code?
Applying logical NOT on the vector of unique values would convert them to a logical vector containing true at the index where unique value is zero and false where it is non-zero and hence finding the non-zero (false in this case) elements of such a vector would lead nowhere.
I'm looking for a way to test if all elements of a matrix are greater than or equal to their corresponding indexes values in another matrix, and if not to stop evaluating. This is part of an elseif statement for setting a lower bound for values, thus as simplified example:
Lower Bound matrix: A = [4 5 6 7]
New values matrix: B = [7 8 9 10]
Is B>=A then yes, accept and proceed
whereas
Lower Bound matrix: A = [4 5 6 7]
New values matrix: C = [5 3 5 8]
Is C>=A? then no, all elements of C are not greater than A, reject and stop
My solution so far is a bit hackneyed:
Is sum(C>=A) < length(C)? no, then reject and stop
This gives the sum of the true/false values in the comparison C>=A, which if all values of C were greater would equal the length of C, else the sum would be less than the length of C. I keep thinking there's a simple and more elegant solution to this that I'm overlooking and would be grateful for any thoughts. Thanks!
MATLAB has a built-in function for performing this action called all. You can use this on a logical matrix to determine if all values are true. In your case you would pass the logical matrix: B >= A.
A = [4,5,6,7];
B = [7,8,9,10];
all(B(:) >= A(:))
1
Notice that I have used (:) above which ensures that both A and B are column vectors prior to performing the comparison. This way, they can be of any arbitrary dimension and the result of all will always be a scalar.
While you're at it, you may also look into any.
You must indeed rely on logical indexing. To check whether a given matrix B has elements greater than or equal to their corresponding indexes values in another given matrix A you can do something like:
if (sum(sum(B>=A))==numel(A))
%enter if body here
end
The statement B>=A will return a logical matrix with 1 in position (i,j) if B(i,j)>=A(i,j). You then sum all the 1s inside such matrix and then check if such sum is equal to the number of elements (numel()) in A (or B).
In your example. Given
A=[4 5 6 7];
B=[7 8 9 10];
the statement B>=A will return
ans =
1 1 1 1
because all elements in B are greater then elements in A. Sum this vector, you'll get 4. Is the sum (4) equal to the number of elements (4)? Yes. Then all elements in B are greater than or equal to the elements in A.
Note: the double sum() makes your code more robust. It will indeed work also with matrices and not just with vectors. That is because if you do sum() on a matrix, Matlab by default does not return the sum of all its elements, but the sum along the first dimension whose size is different from 1. So if our matrix is:
C =
8 1 6
3 5 7
4 9 2
sum(C) will return
ans =
15 15 15
(Matlab took the sum of every column).
By taking also the sum of such vector we'll get the sum of all the elements.
This ends the quick explanation regarding the nested sum().
I assume by an elegant solution you mean a solution which is more efficient.
Lets create test data:
A = zeros(100000,100000); B = zeros(100000,100000);
Linear Loop
for i = 1:numel(A)
if A(i) < B(i)
display('different')
break
end
end
Logical indexing
if (sum(sum(B>=A))~=numel(A))
display('different')
end
The loop is better when its comes to the best case (first element is smaller):
Elapsed time is 0.000236 seconds. Elapsed time is 0.131802 seconds.
and when its the average case:
Elapsed time is 0.001993 seconds. Elapsed time is 0.196228 seconds.
But we only care about the worst case:
B(end) = 1;
Elapsed time is 8.181473 seconds. Elapsed time is 0.108002 seconds.
I have two matrices.
mcaps which is a double 1698 x 2
index_g which is a logical 1698 x 2
When using the line of code below I get the error message that Index exceeds matrix dimensions. I don't see how this is the case though?
tsp = nansum(mcaps(index_g==1, :));
Update
Sorry I should have mentioned that I need the sum of each column in the mcaps vector
** Example of data **
mcaps index_g
5 6 0 0
4 3 0 0
6 5 1 1
4 6 0 1
8 7 0 0
There are two problems here. I missed one. Original answer is below.
What I missed is that when you use the logical index in this way, you are picking out elements of the matrix that may have different numbers of elements in each column, so MATLAB can't return a well formed matrix back to nansum, and so returns a vector. To get around this, use the fact that 0 + anything = 0
% create a mask of values you don't want to sum. Note that since
% index_g is already logical, you don't have to test equal to 1.
mask = ~index_g & isnan(mcaps)
% create a temporary variable
mcaps_to_sum = mcaps;
% change all of the values that you don't want to sum to zero
mcaps_to_sum(mask) = 0;
% do the sum
sum(mcaps_to_sum,1);
This is basically all that the nansum function does internally, is to set all of the NaN values to zero and then call the sum function.
index_g == 1 returns a 1698 x 2 logical matrix, but then you add in an extra dimension with the colon. To sum the columns, use the optional dim input. You want:
tsp = nansum(mcaps(index_g == 1),1);
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
I would like to create a column vector from the elements of a matrix A of size (3,3) that are not on the diagonal. Thus, I would have 6 elements in that output vector. How can I do this?
Use eye and logical negation, although this is no better than Divakar's original answer, and possibly significantly slower for very large matrices.
>> A = magic(4)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
>> A(~eye(size(A)))
ans =
5
9
4
2
7
14
3
10
15
13
8
12
Use this to get such a column vector, assuming A is the input matrix -
column_vector = A(eye(size(A))==0)
If you don't care about the order of the elements in the output, you can also use a combination of setdiff and diag -
column_vector = setdiff(A,diag(A))
You can also use linear indexing to access the diagonal elements and null them. This will automatically reshape itself to a single vector:
A(1:size(A,1)+1:end) = [];
Bear in mind that this will mutate the original matrix A. If you don't want this to happen, make a copy of your matrix then perform the above operation on that copy. In other words:
Acopy = A;
Acopy(1:size(A,1)+1:end) = [];
Acopy will contain the final result. You need to create a vector starting from 1 and going to the end in increments of the rows of the matrix A added with 1 due to the fact that linear indices are column-major, so the linear indices used to access a matrix progress down each row first for a particular column. size(A,1) will allow us to offset by each column and we add 1 each time to ensure we get the diagonal coefficient for each column in the matrix.
Assuming that the matrix is square,
v = A(mod(0:numel(A)-1, size(A,1)+1) > 0).';