How to distinguish the two picture matrices? - matlab

I have a picture matrix A, the size of which is 200*3000 double. And I have another picture matrix B, the size of which is 200*1000 double. The 1000 columns of matrix B exactly comes from the columns of matrix A. My question is:
How to get a matrix C with the same size of matrix A, but only keep the original values of columns in matrix B? I mean the size of matrix C is 200*3000 double, but only 1000 columns have the same values as matrix B. The other 2000 columns will be set to another value d, that is my second question, what is the value I should set for d, so that the picture matrix C can distinguish from picture matrix A?

Use ismember with the 'rows' option. Here's an example:
A = [1 2 3 4; 5 6 7 8]; %// example A
B = [3 10 1; 7 20 5]; %// example B
val = NaN; %// example value to indicate no match
C = A; %// initiallize
ind = ismember(A.',B.','rows'); %// matching columns
C(:,~ind) = val; %// set non-matching columns to val
Equivalently, you coud replace ismember by bsxfun, so that line becomes
ind = any(all(bsxfun(#eq, A, permute(B, [1 3 2])), 1), 3);
In this example,
A =
1 2 3 4
5 6 7 8
B =
3 10 1
7 20 5
C =
1 NaN 3 NaN
5 NaN 7 NaN

Related

Algorithmically construct block matrices (matlab)

Let Matrices = [A B C D] be a set of square matrices. I want to construct
H = [A B C D;
B A B C;
C B A B;
D C B A]
If all I was interested in was the 4 by 4 case, then this would be enough. However, I want to construct the analogous matrix when Matrices = [A B C D E F] etc. What code could I write to do this?
This can be done as follows:
Concatenate the matrices into a 3D array;
Build the basic with numbers instead of matrices using toeplitz;
Extend this structure so that using linear indexing into the 3D array produces the desired result.
N = 2; % matrix size
M = 3; % number of matrices
matrices = arrayfun(#(x) {randi(9,N)}, 1:M); % input matrices
matrices_3D = cat(3, matrices{:}); % concatenate the matrices along the third dim
ind1 = repmat(reshape(1:N^2, N, N), M, M); % linear indices within each matrix
ind2 = (repelem(toeplitz(1:M), N, N)-1)*N^2; % linear indices to select the matrices
result = matrices_3D(ind1 + ind2); % build result
Example run:
>> celldisp(matrices)
matrices{1} =
1 4
2 6
matrices{2} =
6 4
5 9
matrices{3} =
5 4
6 5
>> result
result =
1 4 6 4 5 4
2 6 5 9 6 5
6 4 1 4 6 4
5 9 2 6 5 9
5 4 6 4 1 4
6 5 5 9 2 6

Merging sorted pairs

I have two (or more but if solved for two, it's solved for any number) 2-by-N matrices which represent points with an x (the first row) and y (the second row) coordinates. The points are always sorted in the increasing x coordinate. What I want to do is I want to merge these two matrices into one 3-by-N matrix so that if two points (one from each matrix) have the same x coordinate, they would form one column in the new matrix, the first row being the x coordinate and the second and third row being the two y coordinates. However, if there is a point in one matrix that has x coordinate different than all other points in the second matrix, I still want to have full 3-element column that is placed such that the x coordinates are still sorted and the missing value from the other matrix is replaced by the nearest value with lower x coordinate (or NaN if there is none).
Better to explain by example.
First matrix:
1 3 5 7 % x coordinate
1 2 3 4 % y coordinate
Second matrix:
2 3 4 7 8 % x coordinate
5 6 7 8 9 % y coordinate
Desired result:
1 2 3 4 5 7 8 % x coordinate
1 1 2 2 3 4 4 % y coordinate from first matrix
NaN 5 6 7 7 8 9 % y coordinate from second matrix
My question is, how can I do it effectively in matlab/octave and numpy? (Effectively because I can always do it "manually" with loops but that doesn't seem right.)
You can do it with interp1 and the keyword 'previous' for strategy (you can also choose 'nearest' if you do not care if it is larger or smaller) and 'extrap' for allowing extrapolation.
Define the matrices
a=[...
1 3 5 7;...
1 2 3 4];
b=[...
2 3 4 7 8;...
5 6 7 8 9];
Then find the interpolation points
x = unique([a(1,:),b(1,:)]);
And interpolate
[x ; interp1(a(1,:),a(2,:),x,'previous','extrap') ; interp1(b(1,:),b(2,:),x,'previous','extrap') ]
Timeit results:
I tested the algorithms on
n = 1e6;
a = cumsum(randi(3,2,n),2);
b = cumsum(randi(2,2,n),2);
and got:
Wolfie: 1.7473 s
Flawr: 0.4927 s
Mine: 0.2757 s
This verions uses set operations:
a=[...
1 3 5 7;...
1 2 3 4];
b=[...
2 3 4 7 8;...
5 6 7 8 9];
% compute union of x coordinates
c = union(a(1,:),b(1,:));
% find indices of x of a and b coordinates in c
[~,~,ia] = intersect(a(1,:),c);
[~,~,ib] = intersect(b(1,:),c);
% create output matrix
d = NaN(3,numel(c));
d(1,:) = c;
d(2,ia) = a(2,:);
d(3,ib) = b(2,:);
% fill NaNs
m = isnan(d);
m(:,1) = false;
i = find(m(:,[2:end,1])); %if you have multiple consecutive nans you have to repeat these two steps
d(m) = d(i);
disp(d);
Try it online!
Your example:
a = [1 3 5 7; 1 2 3 4];
b = [2 3 4 7 8; 5 6 7 8 9];
% Get the combined (unique, sorted) `x` coordinates
output(1,:) = unique([a(1,:), b(1,:)]);
% Initialise y values to NaN
output(2:3, :) = NaN;
% Add x coords from `a` and `b`
output(2, ismember(output(1,:),a(1,:))) = a(2,:);
output(3, ismember(output(1,:),b(1,:))) = b(2,:);
% Replace NaNs in columns `2:end` with the previous value.
% A simple loop has the advantage of capturing multiple consecutive NaNs.
for ii = 2:size(output,2)
colNaN = isnan(output(:, ii));
output(colNaN, ii) = output(colNaN, ii-1);
end
If you have more than 2 matrices (as suggested in your question) then I'd advise
Store them in a cell array, and loop over them to do the calls to ismember, instead of having one code line per matrix hardcoded.
The NaN replacement loop is already vectorised for any number of rows.
This is the generic solution for any number of matrices, demonstrated with a and b:
mats = {a, b};
cmats = horzcat(mats);
output(1, :) = unique(cmats(1,:));
output(2:numel(mats)+1, :) = NaN;
for ii = 1:size(mats)
output(ii+1, ismember(output(1,:), mats{ii}(1,:))) = mats{ii}(2,:);
end
for ii = 2:size(output,2)
colNaN = isnan(output(:,ii));
output(colNaN, ii) = output(colNaN, ii-1);
end

Making a matrix from another matrix

I have a matrix with 1 column, x rows. My second matrix has to be the first few values of that matrix concatenated to the last values of that matrix.
Example:
a=[0:1:10]
b=[0,1,9,10]
Question: How do I build b, by using a?
Say the number of values you want to extract off of each end is n. The horzcat command let's you horizontally concatenate matrices.
n=2;
a=[0:1:10];
b=horzcat(a(1:n),a(end-n+1:end))
E.g. for letting b be the first two columns of a and the two last columns of a concatenated: b = [a(:, 1:2), a(:, size(a, 2) - 1:size(a, 2))].
Example:
>> a = [0:1:10]
a =
0 1 2 3 4 5 6 7 8 9 10
>> b = [a(:, 1:2), a(:, size(a, 2) - 1:size(a, 2))]
b =
0 1 9 10

Multiplying matrix Matlab

I have a matrix M[1,98] and a matrix N[1,x], let's assume in this case x =16.
What I want is to multiply N by M , make the sum by element, and increment the matrix M. With the finality of getting an output of [1,98].
It's a bit confusing. An example:
M=[2 3 4 5 6 7]
N=[1 2 3]
it1=(2*1)+(3*2)+(4*3)+(5*0)+...=20
it2=(3*1)+(4*2)+(5*3)+(6*0)+...=26
it3=..
Output=[20 26 ... ... ... ...]
Like that until the end but considering the size of the matrix N variable. M has always the same size.
That's a convolution:
result = conv(M, N(end:-1:1), 'valid');
To achieve the result you want you need to flip the second vector and keep only the "valid" part of the convolution (no border effects).
In your example:
>> M = [2 3 4 5 6 7];
>> N = [1 2 3];
>> result = conv(M, N(end:-1:1), 'valid')
result =
20 26 32 38

Matlab: How to locate a data in Matrix B based on the info in Matrix A? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Sort a matrix with another matrix
The Matrix A ('10 x 1000' all numbers) look like this:
score(1.1) score(1.2) score(1.3)....score(1.1000)
score(2.1) score(2.2) score(2.3)....score(1.1000)
...
The Matrix B ('1 x 1000' all numbers):
Return(1) Return(2) Return(3) .....Return(1.1000)
Every time I sort a row of Matrix A, I want to sort Matrix B based on the order of the sorted row in Matrix A. Because there are 10 rows in Matrix A, Matrix B will be sorted 10 times and generate a new Matrix C ('10 x 1000') like this: (I am looking for a script to generate this Matrix C)
Return(3) Return(25) Return(600) .......Return(1000)
Return(36)Return(123) Return(2)........Return(212)
....
....
This should do what you want:
A = randn(10,1000);
B = randn(1,1000);
C = zeros(size(A));
for i = 1:10
[a idx] = sort(A(1,:));
A(i,:) = a;
C(i,:) = B(idx);
end
Now the rows of A are sorted, and the rows of C contain the corresponding sorted B.
This solution is a bit more compact, and it's also good to get used to doing this kind of solution for efficiency when your matrices get big. You can solve your problem with two ideas:
In [a, ix] = sort(X), a is a column-sorted version of X, and ix stores which rows moved where in each column. Thus if we do [a, ix] = sort(X.').'; (where the dot-apostrophe is the transpose) we can sort the rows.
B(ix) where ix is a bunch of indeces will make a matrix the same size as ix with the i-jth element being B at ix(i,j)
Then you just need to reshape it. So you can do:
A = rand(4,8);
B = rand(1,8);
n = size(A,1);
m = size(A,2);
[~,ix] = sort(A.');
C = reshape(B(ix'),n,m);
If I understand your question correctly the following should work. Using some sample scores:
>> score = [1 4 7 9; 3 5 1 7; 9 3 1 6]
score =
1 4 7 9
3 5 1 7
9 3 1 6
and sample return vector:
>> r = [10 20 30 40]
r =
10 20 30 40
Transpose the scores and sort since the SORT command works on columns of a matrix. We're only interested in the indices of the sorted values:
>> [~, ix] = sort(score')
ix =
1 3 3
2 1 2
3 2 4
4 4 1
Now transpose these indices and use them to reference the return values:
>> answer = r(ix)'
answer =
10 20 30 40
30 10 20 40
30 20 40 10