MATLAB: scan the row of a matrix and use values to search another matrix - matlab

I have matrix X and A where
X = [x1, y1, 1, 1; x2, y2, 1, 3; x3, y, 2, 4]
A = [1, 1, 0; 1, 3, 1; 1, 4, 2]
I want to:
1. scan the last two columns for every row in X (FYI, these two number combinations are unique)
2. find those values in the first two columns of A
3. get the value of the last column in that row of A.
For example, for the first row of X, I get 1 and 1, so I find 1 and 1 for the first two columns in A (which appears to be the first row), so the number I want to get is 0.
I think I can do it using a loop and a "find" function if it were just one number I'm working with, but I'm new to matlab and have trouble with a combination of two numbers. I would appreciate your help!

The ismember function may be what you're looking for, along with the () and : operators to extract columns from an array.
% Map rows in X to rows in A
[tf,loc] = ismember(X(:,[3 4]), A(:,[1 2]), 'rows');
% Grab the corresponding value from A
rslt = A(loc, 3);
Now you have a logical vector tf that indicates for each row in X whether it was found in A, and loc, which holds the corresponding indexes in to the rows of A for the ones that matched. Then you use those indexes to index in to A to pull out the "value" or dependent variable columns. These are vectorized operations, so it'll be faster than doing it with loops and find().
Read through the documentation for ismember, unique, paren, and the functions they reference to get more background on Matlab's functions for doing recordwise searching like this.

Related

How to find the repeated values in a matrix and which rows they belong to?

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.

How to marginalise a vector with index?

I have this code:
A = [3,1,5,8]
B = [0, 0]
indexB = [1,2,2,1]
for i = 1:4
B(indexB(i)) = B(indexB(i)) + A(i)
end
So, in the end, I got
B = [11, 6]
I wonder if I can use a more efficient way to sum up instead of using the for-loop?
Classic use of accumarray. Only this time, you accumulate the entries in A then add this on top of B as B is the starting point of the summation:
B = B(:); % Force into columns
B = B + accumarray(indexB(:), A(:));
How accumarray works is quite simple. You can think of it as a miniature MapReduce paradigm. Simply put, for each data point we have, there is a key and an associated value. The goal of accumarray is to place (or bin) all of the values that belong to the same key and do some operation on all of these values. In our case, the "key" would be the values in indexB where each element is a location to index into B. The values themselves are those from A. We would then want to add up all of the values that belong to each location in indexB together. Thankfully, the default behaviour for accumarray is to add all of these values. Specifically, the output of accumarray would be an array where each position computes the sum of all values that mapped to a key. For example, the first position would be the summation of all values that mapped to the key of 1, the second position would be the summation of all values that mapped to the key of 2 and so on.
Because you are using B as a starting point, the end result would be to take the summation result from accumarray and add this on top of B thus completing the code.
Minor Note
I do have to point out that accumarray works by columns. Because you are using rows, I had to force the input so that they are columns, which is the purpose of the (:) syntax. The output will also be as a column so you can transpose that if you wish to have it in a row format.

Matlab - Access elements form each column using a vector containing the rows [duplicate]

I'm writing a MATLAB function to read out data into an n-dimensional array (variable dimension size). I need to be able to access a specific point in the Matrix (to write to it or read it, for example), but I don't know ahead of time how many indexes to specify.
Currently I have a current_point vector which I iterate through to specify each index, and a max_points vector which specifies the size of the array. So, if for example I wanted a 3-dimensional array of size 1000-by-15-by-3, max_points = [1000 15 3], and current_point iterates from [1, 1, 1] to [1000, 15, 3] ([1, 1, 1] -> [1000, 1, 1] -> [1, 2, 1] -> [1000, 2, 1] ->...). What I'd like to be able to do is feed current_point as an index to the matrix like so:
output_matrix(current_point) = val
But apparently something like output_matrix([1 2 3]) = val will just set outputmatrix(1:3) = 30. I can't just use dummy variables because sometimes the matrix will need 3 indexes, other times 4, other times 2, etc, so a vector of variable length is really what I need here. Is there a simple way to use a vector as the points in an index?
Using the function sub2ind to create a linear index is the typical solution to this problem, as shown in this closely-related question. You could also compute a linear index yourself instead of calling sub2ind.
However, your case may be simpler than those in the other questions I linked to. If you're only ever indexing a single point with your current_point vector (i.e. it's just an n-element vector of subscripts into your n-dimensional matrix), then you can use a simple solution where you convert current_point to a cell array of subscripts using the function num2cell and use it to create a comma-separated list of indices. For example:
current_point = [1 2 3 ...]; % A 1-by-n array of subscripts
subCell = num2cell(current_point); % A 1-by-n cell array of subscripts
output_matrix(subCell{:}) = val; % Update the matrix point
The operation subCell{:} creates the equivalent of typing subCell{1}, subCell{2}, ..., which is the equivalent of typing current_point(1), current_point(2), ....
I know it is too late but for anybody who will find this topic. the easiest way that work for me is to use: diag(A (x(:),y(:)) );
unfortunately this works only if you need to get values from the matrix, not for changing values
You can use the sub2ind function to get the linear index from the subscript.
Example:
A=magic(4)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
selectElement={2,3}; %# get the element at position 2,3 in A.
indx=sub2ind(size(A),selectElement{:});
A(indx)
ans =
10
In the above example, I've stored the subscripts (can be any number of dimensions) as a cell. If you have it stored as a vector, simply use num2cell() to convert it to a cell.
You can now easily assign a value to this as A(indx)=value;. I've used different variables than yours to keep the answer general, but the idea is the same and you just need to replace the variable names.
You also mentioned in your post that you're looping from (1,1,1) till some value, (1000,15,3) and assigning a value to each of these points. If you're looping along the columns, you can replace this entire operation with a vectorized solution.
Let finalElement={1000,15,3} be the final step of the loop. As before, find the linear index as
index=sub2ind(size(A),finalElement{:});
Now if you have the values you assign in the loop stored as a single vector, values, you can simply assign it in a single step as
A(1:index)=values;

Nx2 matrix of points [x1 y1; x2 y2; etc.], get highest y value for each unique x

I'm trying to find an idiomatic way to do this.
Essentially I have an Nx2 matrix of points of the form
A = [3 4; 3 5; 4 5; 4, 6; 7 3]
I'd like my output to be [3 5; 4 6; 7 3]. In other words I would like each unique x value along with the maximum y value associated with that x.
I was hoping there would be some sort of
unique(A, 'rows', 'highestterm', 2)
method for accomplishing this, but couldn't find anything. Can anyone think of a vectorized way to solve this problem? I can do it pretty easily in a for loop, but would like to avoid that if possible.
I don't know of any single call, like you hoped. But, it can be done fairly tightly (and fully vectorized) like the code below.
%sort by first and then second column
A = sortrows(A,[1 2]);
%find each change in the first column of A
inds = find(diff(A(:,1)) > 0);
%add the last point...because find(diff) doesn't get the last point
inds(end+1) = size(A,1);
%get just those rows that meet the desired criteria
A = A(inds,:);
So, this works by sorting the data and looking for the values in the first column that don't repeat. If there are repeated values, this code grabs the last of the repeating values. Finally, because we sorted by both columns via sortrows(A,[1 2]), the last entry for a repeating value will have the biggest corresponding value from the 2nd column. I think that this hits all of your requirements.
Using accumarray and unique:
[r1, ~, u] = unique(A(:,1));
r2 = accumarray(u, A(:,2), [], #max);
result = [r1 r2];

Use a vector as an index to a matrix

I'm writing a MATLAB function to read out data into an n-dimensional array (variable dimension size). I need to be able to access a specific point in the Matrix (to write to it or read it, for example), but I don't know ahead of time how many indexes to specify.
Currently I have a current_point vector which I iterate through to specify each index, and a max_points vector which specifies the size of the array. So, if for example I wanted a 3-dimensional array of size 1000-by-15-by-3, max_points = [1000 15 3], and current_point iterates from [1, 1, 1] to [1000, 15, 3] ([1, 1, 1] -> [1000, 1, 1] -> [1, 2, 1] -> [1000, 2, 1] ->...). What I'd like to be able to do is feed current_point as an index to the matrix like so:
output_matrix(current_point) = val
But apparently something like output_matrix([1 2 3]) = val will just set outputmatrix(1:3) = 30. I can't just use dummy variables because sometimes the matrix will need 3 indexes, other times 4, other times 2, etc, so a vector of variable length is really what I need here. Is there a simple way to use a vector as the points in an index?
Using the function sub2ind to create a linear index is the typical solution to this problem, as shown in this closely-related question. You could also compute a linear index yourself instead of calling sub2ind.
However, your case may be simpler than those in the other questions I linked to. If you're only ever indexing a single point with your current_point vector (i.e. it's just an n-element vector of subscripts into your n-dimensional matrix), then you can use a simple solution where you convert current_point to a cell array of subscripts using the function num2cell and use it to create a comma-separated list of indices. For example:
current_point = [1 2 3 ...]; % A 1-by-n array of subscripts
subCell = num2cell(current_point); % A 1-by-n cell array of subscripts
output_matrix(subCell{:}) = val; % Update the matrix point
The operation subCell{:} creates the equivalent of typing subCell{1}, subCell{2}, ..., which is the equivalent of typing current_point(1), current_point(2), ....
I know it is too late but for anybody who will find this topic. the easiest way that work for me is to use: diag(A (x(:),y(:)) );
unfortunately this works only if you need to get values from the matrix, not for changing values
You can use the sub2ind function to get the linear index from the subscript.
Example:
A=magic(4)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
selectElement={2,3}; %# get the element at position 2,3 in A.
indx=sub2ind(size(A),selectElement{:});
A(indx)
ans =
10
In the above example, I've stored the subscripts (can be any number of dimensions) as a cell. If you have it stored as a vector, simply use num2cell() to convert it to a cell.
You can now easily assign a value to this as A(indx)=value;. I've used different variables than yours to keep the answer general, but the idea is the same and you just need to replace the variable names.
You also mentioned in your post that you're looping from (1,1,1) till some value, (1000,15,3) and assigning a value to each of these points. If you're looping along the columns, you can replace this entire operation with a vectorized solution.
Let finalElement={1000,15,3} be the final step of the loop. As before, find the linear index as
index=sub2ind(size(A),finalElement{:});
Now if you have the values you assign in the loop stored as a single vector, values, you can simply assign it in a single step as
A(1:index)=values;