Comparing values across unequal matrices in Matlab - matlab

I would like to compare rows across two unequal matrices in Matlab and extract these rows to be stored in a different matrix (say D). For example,
tmp = [2245; 2345; 2290; 4576]
and
id=[1 2245 564 8890 123;
2 2445 5673 7846 342;
3 2290 3428 3321 908].
Id is a much larger matrix. I want to locate each value of tmp which is in ‘id’. Although using the intersect command in the line below I have been able to locate the rows of id which contain the values from tmp, I would like to do this for each value of tmp one by one as each value of tmp is repeated multiple times in id. I tried using foreach. However, I get an error message stating that foreach cannot be used for char type array. Could anyone please suggest an alternative how to go about this?
for j=1:length(tmp);
[D,itmp,id2] = intersect(tmp(j,1),id(:,2), 'rows');
Despite using the loop, the code doesn’t seem to take one value of j at a time. This was the reason behind trying ‘foreach j’. Also after finding the rows common to the two matrices and storing them in D, I would like to append matrix id to include the value of j next to the relevant row within id. For example, if the first value within tmp was repeated in id in rows 1,3,5,10; I would like a column in id which would take the value 1 next to rows 1,3,5,10. Any help on this would be much appreciated! Thanks.

Not sure exactly, what you trying to do, but to search a value in a matrix you can use find:
for i = 1:numel(tmp)
[row, col] = find(id == tmp(i));
end

You can easily achieve this using a combination of bsxfun and permute. What you would do is transform the tmp vector so that it is a single 3D vector, then use the eq (equals) function and see which values in your matrix are equal to each value of tmp. Therefore, do something like:
%// Your data
id=[1 2245 564 8890 123;
2 2445 5673 7846 342;
3 2290 3428 3321 908]
tmp = [2245; 2345; 2290; 4576];
tmp2 = permute(tmp, [3 2 1]); %// Make a 3D vector
tmp3 = bsxfun(#eq, id, tmp2); %// Find which locations of id are equal to each value of tmp
This is what I get for my final output, stored in tmp3:
tmp3(:,:,1) =
0 1 0 0 0
0 0 0 0 0
0 0 0 0 0
tmp3(:,:,2) =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
tmp3(:,:,3) =
0 0 0 0 0
0 0 0 0 0
0 1 0 0 0
tmp3(:,:,4) =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
As you can see here, each 3D slice tells you which elements in id match the corresponding value in tmp. Therefore, the first slice tells you whether any element in id is equal to tmp(1), which is 2245. In this case, this would be the first row and second column. For the second slice, no values matched tmp(2) = 2345. For the third slice, one value in id matched tmp(3) = 2290, which is row 3, column 3.
Now, what you're really after is determining the rows and columns of where each value of tmp matched each location in id. You want this to be delineated per id number. That can easily be done using ind2sub and find on this matrix:
[rows, cols, ID] = ind2sub(size(tmp3), find(tmp3))
rows =
1
3
cols =
2
2
ID =
1
3
Therefore, ID tells you which id we have matched to, and rows, cols tells you which rows and columns in id we were able to match with. Therefore, for id = 1, we found a match with tmp(1)= 2245, and this is located at row=1,col=2. Similarly, for id = 3, we found a match with tmp(3)=2290 and this is at row=3,col=2.
To make this into all one big 2D matrix that contains all the information you want, you can simply concatenate all of these columns into one matrix. Therefore:
final = [ID rows cols]
final =
1 1 2
3 3 2
You can read this like so:
id=1 with tmp(1) = 2245, we found this value in row=1,col=2.
id=3, with tmp(3) = 2290, we found this value in row=3,col=2
Hope this helps!

Related

How to get the logical matrix corresponding to "scatter" plot?

If I have a two column matrix A like below, I can plot the scatter plot using scatter/plot command. I would like to get the matrix corresponding to such outputs as in hist command. hist command gives the vector output too.
A=[7 1;3 2; 4 3]
For example out=scatter(A(:,1),A(:,2)) must give something like below:
[0 0 0;
0 0 0;
0 1 0;
0 0 1;
0 0 0;
0 0 0;
1 0 0]
Only the indices (7,1), (3,2) and (4,3) are only ones. Or Can someone give me a snippet code to realize this without using loops?
You can use a combination of sparse and full where you can specify the non-zero row and column locations, and the rest of the matrix would be zero:
A = [7 1; 3 2; 4 3];
B = full(sparse(A(:,1), A(:,2), 1, max(A(:,1)), max(A(:,2)))) == 1;
The sparse command takes in the row and column locations of what is non-zero for the first two inputs, the third input is what the non-zero location would be for each row and column location. We can specify a constant to mean that every non-zero location gets the same coefficient, which is 1. We can also specify the size of the matrix, where in this case the rows and columns of the output correspond to the largest number in the first and second columns respectively. Because this is a sparse matrix, you will want to convert this to a full matrix and because you want it to be logical, you will want to compare all elements with the number 1.
We thus get for the output, which is B:
B =
7×3 logical array
0 0 0
0 0 0
0 1 0
0 0 1
0 0 0
0 0 0
1 0 0
Alternatively, we can use sub2ind to create linear indices to index into a pre-allocated matrix of logical false and set only those non-zero row locations to true:
A = [7 1; 3 2; 4 3];
B = false(max(A(:,1)), max(A(:,2)));
ind = sub2ind(size(B), A(:,1), A(:,2));
B(ind) = true;
We first allocate the matrix, then calculate the linear indices to index into the matrix, then finally set the right locations to true. The output here would be the same as the sparse approach.
Just to add: rayryeng's solution is fine if you really want your result to be logical in the sense that it is equal to one if there is anything at the coordinate and zero otherwise. Still, since you added a note on hist, I was wondering if you actually want to count the number of times a specific coordinate is hit. In this case, consider using
S = histcounts2(A(:,2),A(:,1));
if you have access to R2015b+. If not, there is a hist2 function on fileexchange you can use for the purpose.
Here is my solution. Matlab provides a command called accumarray.
S = logical(accumarray(A, 1) )
will give the result too.

Matlab:Efficient assignment of values in a sparse matrix

I'm working in Matlab and I have the next problem:
I have a B matrix of nx2 elements, which contains indexes for the assignment of a big sparse matrix A (almost 500,000x80,000). For each row of B, the first column is the column index of A that has to contain a 1, and the second column is the column index of A that has to contain -1.
For example:
B= 1 3
2 5
1 5
4 1
5 2
For this B matrix, The Corresponding A matrix has to be like this:
A= 1 0 -1 0 0
0 1 0 0 -1
1 0 0 0 -1
-1 0 0 1 0
0 -1 0 0 1
So, for the row i of B, the corresponding row i of A must be full of zeros except on A(i,B(i,1))=1 and A(i,B(i,2))=-1
This is very easy with a for loop over all the rows of B, but it's extremely slow. I also tried the next formulation:
A(:,B(:,1))=1
A(:,B(:,2))=-1
But matlab gave me an "Out of Memory Error". If anybody knows a more efficient way to achieve this, please let me know.
Thanks in advance!
You can use the sparse function:
m = size(B,1); %// number of rows of A. Or choose larger if needed
n = max(B(:)); %// number of columns of A. Or choose larger if needed
s = size(B,1);
A = sparse(1:s, B(:,1), 1, m, n) + sparse(1:s, B(:,2), -1, m, n);
I think you should be able to do this using the sub2ind function. This function converts matrix subscripts to linear indices. You should be able to do it like so:
pind = sub2ind(size(A),1:n,B(:,1)); % positive indices
nind = sub2ind(size(A),1:n,B(:,2)); % negative indices
A(pind) = 1;
A(nind) = -1;
EDIT: I (wrongly, I think) assumed the sparse matrix A already existed. If it doesn't exist, then this method wouldn't be the best option.

Is there an array creation function for full arrays that has the same signature as sparse matrix constructor?

I'd like to accumulate indexed elements in a matrix, like table and tapply function in R.
I found sparse(i,j,s,m,n) fit my need perfectly,
As the document says:"Any elements of s that have duplicate values of i and j are added together."
But I have to convert the obtained sparse matrix to a full one using full():
a = a + full(sparse(i,j,s,m,n));
Is this a efficient way to do so?
By the way, is there anything like below, no matter whether adding duplicated i,j pairs?
a = setelements(a, i,j,s);
and
vector = getelement(a,i,j);
where i&j take meanings in sparse() function.
And what if a is a multidimensional array? sparse() only deal with matrix.
Do I have to set the entries page by page with outer loops?
Take a look at accumaray. For example,
ii = [1 2 2 3 3];
jj = [3 2 2 2 2];
s = [10 20 30 40 50];
a = accumarray([ii(:) jj(:)],s(:));
gives
a =
0 0 10
0 50 0
0 90 0
Note that each row of the first argument ([ii(:) jj(:)]) defines an N-dimensional index into the output array (N is 2 in this example).
accumarray is very flexible. It works for N-dimensional arrays, lets you specify size of the result (it may be larger than inferred from the supplied indices), and can even apply an arbitrary function (different from sum) to each set of values defined by the same index.
As a more general example, with the above data,
a = accumarray([ii(:) jj(:)],s(:),[4 4],#max)
gives
a =
0 0 10 0
0 30 0 0
0 50 0 0
0 0 0 0

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.

I Need help Numeric Comparison in matlab

I have one matrix called targets (1X4000); column 1 to 2000 contains double value 0 and column 2001 to 4000 contains double value 1
a)
i want to create a matrix called targets_1 where i want to check if the value is 0 then make the entry 1 so at the end of the day i must have a matrix with :column 1 to 2000 with value 1 and column 2001:4000 with value zero
b)
Same situation as above but this time i want to check if the value is 1 then make the entry 1 and if it is zero then make the entry zero; at the end; my new matrix targets_2 contains values: column 1 to 2000 with value zero and column 2001:4000 with value 1
i know how to use the strcmp function to make such checking with strings, but problem is that my original matrix is double and i dont know if there is such function like
setosaCmp = strcmp('setosa',species);
which could work with double (numbers); any help would be appreciated
Your question isn't very clear. It sounds like the following would satisfy your description:
targets_1 = 1 - targets;
targets_2 = targets;
targets1 = double(targets == 0);
targets2 = targets;
I'm basing this answer purely on the fact that you've mentioned setosaCmp = strcmp('setosa', species);. From this I'm guessing that
You have Statistics Toolbox, as setosa is a species of iris from the Fisher Iris dataset widely used in Statistics Toolbox demos, and
You have a variable containing class labels, and you'd like to construct some class indicator variables (i.e. a new variable for each class label, each of which is 1 when the item is in that class, and 0 when it's not).
Is that right? If not, please ignore me.
If I'm right, then I think the command you're looking for is dummyvar from Statistics Toolbox. Try this:
>> classLabels = [1, 2, 1, 2, 3, 1, 3];
>> dummyvar(classLabels)
ans =
1 0 0
0 1 0
1 0 0
0 1 0
0 0 1
1 0 0
0 0 1