Find column locations of vector elements inside a matrix - matlab

Given a vector such as a = [2 5 9] and a matrix such as
8 11 5
b = 2 6 1
4 9 3
What's the best way to find which column of b contains each element of a? In this example I'd want an output like [1 3 2] because 2 is in the first column, 5 is in the third column, and 9 is in the second column. For my purposes it's safe to assume that a number can only appear in one column.

One approach -
[colID,~] = find(squeeze(any(bsxfun(#eq,b,permute(a,[1 3 2])),1)))
Or if you would like to avoid squeeze and any -
[~,colID,~] = ind2sub([size(b) numel(a)],find(bsxfun(#eq,b(:),a)))

Another way would be to use ismember:
A = [2 5 9];
B = [8 11 5; 2 6 1; 4 9 3];
[~, ind] = ismember(A,B);
[~, col] = ind2sub(size(B), ind)
col =
1 3 2

Another approach:
[~, index] = ismember(a, b);
[row, col] = ind2sub(size(b, 1), index);

Related

Building matrices using column vector and matrix in matlab

I have a column vector A (6x1) with values [6 3 10 4 2 8]'; and a matrix B (6x5) with values
B = [1 2 3 0 4 ;
3 7 8 5 0 ;
0 9 1 0 1 ;
5 0 3 1 2 ;
4 6 7 6 4 ;
3 1 2 7 3]
I want to make five matrices with size 6x2 using Matlab.
The first column is vector A
The second column is columns from B, like [A, B(first col)], [A, B(second col)]
First matrix is [6 1; 3 3; 10 0; 4 5; 2 4; 8 3];
2nd matrix is [6 2; 3 7; 10 9; 4 0; 2 6; 8 1]
... and so on
Any help I really appreciate it
You could use a loop
C = NaN( size(B,1), 2, size(B,2) );
for ii = 1:size(B,2)
C(:,:,ii) = [A, B(:,ii)];
end
This gives you a 3D array, where each slice in the 3rd dimension is a 6x2 matrix (for this example) as desired. You would access the nth slice with C(:,:,n).
You can do this slightly more concisely with arrayfun, but it's basically a loop in disguise
C = arrayfun( #(ii) [A, B(:,ii)], 1:size(B,2), 'uni', 0 );
C = cat(3, C{:} );
You could omit the cat function if you're happy with results in a cell array, where you access the nth matrix with C{n}.
You could first make a copy of the columns of A, then concatenate A and B, and reshape:
At = repmat(A, 1, size(B,2));
C = reshape([At;B], 6, 2, []);
Or oneliner:
C = reshape([repmat(A, 1, size(B,2));B], 6, 2, []);
Then retrieve your matrices with C(:,:,k)
you can use this
first_matrix=[A,B(:,1)];
second_matrix=[A,B(:,2)];
third_matrix=[A,B(:,3)];
... and so on

Reshape vector with a step and window size

I have a vector, for example
A = [1 2 3 4 5 6 7 8]
I want to "reshape" it to matrix with windowsize=4 and stepsize=2, such that the resulting matrix is
b = [ 1 3 5;
2 4 6;
3 5 7;
4 6 8 ]
You can set up an indexing matrix, then just index into A...
A = [1 2 3 4 5 6 7 8];
windowsize = 4;
stepsize = 2;
% Implicit expansion to create a matrix of indices
idx = bsxfun( #plus, (1:windowsize).', 0:stepsize:(numel(A)-windowsize) );
b = A(idx);
Note; in this case idx and b are the same, but you need the final indexing step assuming A isn't just consecutive integers in your real example.

Identifying Matrix element links/connection MATLAB

Hi I have a correlation Matrix:
A = [1 2 1 3 1 2 4 3 5 1;
2 3 4 5 6 6 6 7 7 8];
I need to find out how many times each individual element of row 1 is linked to elements in row 2.
For example, here element 1 in row 1 is related to the following elements of row 2, {2, 4, 6, 8}, so total 4 elements.
Similarly 2 is linked to {3, 6}, for a total of 2 elements.
Resulting Matrix C should be:
[element name in 1st row; Number of connection].
In previous example, C = [1 2 ....; 4 2 ...];
Since actual matrix size is of the order of 1000s', it is impossible to do manually. Any help will be appreciated.
There is probably a way to do this without resorting to a for loop but this is one solution I can think of right now. Identify the unique elements in the first row of matrix A and loop over all the elements to find the ones they are linked to in the second row.
I have assumed that you only need to identify the unique elements that the first row is linked to, hence the unique() function inside the for loop; if that is not the case, please remove that from the code.
a = [1 2 1 3 1 2 4 3 5 1; 2 3 4 5 6 6 6 7 7 8];
row1el = unique(a(1, :));
c = zeros(2, length(row1el));
for i = 1:length(row1el)
idx = a(1, :) == row1el(i);
linkedEl = a(2, idx);
c(1, i) = row1el(i);
c(2, i) = length(unique(linkedEl));
end
disp(c)
If I understood the question properly, you are not really concerned about the values in the second row, but the number of occurrences of the elements in row 1. This can be obtained with the unique and histc functions:
C(1,:)=unique(A(1,:));
C(2,:)=histc(A(1,:),C(1,:));
C =
1 2 3 4 5
4 2 2 1 1
The answer depends on whether repeated columns should be counted repeatedly or not. Consider the following data:
A = [1 2 1 3 1 2 4 3 5 1;
2 3 4 5 6 6 6 5 7 8]; %// col [3;5] appears twice
If repeated columns should be counted according to their multiplicity: you can use accumarray:
[ii, ~, kk] = unique((A(1,:)));
jj = accumarray(kk.', A(2,:).', [], #(x) numel(x)).';
C = [ii; jj];
Result with my example A:
C =
1 2 3 4 5
4 2 2 1 1
Or you can use sparse:
[~, ii, jj] = find(sum(sparse(A(2,:), A(1,:), 1)));
C = [ii; jj];
The result is the same as above.
If repeated columns should be counted just once: either of the two approaches is easily adapted to this case:
[ii, ~, kk] = unique((A(1,:)));
jj = accumarray(kk.', A(2,:).', [], #(x) numel(unique(x))).'; %'// note: "unique"
C = [ii; jj];
or
[~, ii, jj] = find(sum(sparse(A(2,:), A(1,:), 1) > 0)); %// note: ">0"
C = [ii; jj];
Result (note third column is different than before):
C =
1 2 3 4 5
4 2 1 1 1

Find the minimum positive difference between elements in vector

A = [1 3 5 8]
B = [1 2 3 4 5 6 7 8]
I would like to create a vector C which returns the rownumber of the element in vector A with the smallest non-negative difference to each element in vector B.
So, given the example above, it should return:
C = [1 2 2 3 3 4 4 4]
I'm sure there are many ways to do this. Here's one:
A = [1 3 5 8]
B = [1 2 3 4 5 6 7 8]
%create matrices of the values to subtract
[a,b] = meshgrid(A,B);
%subtract
aLessB = a-b;
%make sure we don't use the negative values
aLessB(aLessB < 0) = Inf;
%sort the subtracted matrix
[dum, idx] = sort(aLessB, 2, 'ascend');
idx(:,1) is the solution you are looking for.
An alternative solution:
D = bsxfun(#minus, A', B);
D(D < 0) = Inf;
[~, C] = min(D, [], 1);

average 3rd column when 1st and 2nd column have same numbers

just lets make it simple, assume that I have a 10x3 matrix in matlab. The numbers in the first two columns in each row represent the x and y (position) and the number in 3rd columns show the corresponding value. For instance, [1 4 12] shows that the value of function in x=1 and y=4 is equal to 12. I also have same x, and y in different rows, and I want to average the values with same x,y. and replace all of them with averaged one.
For example :
A = [1 4 12
1 4 14
1 4 10
1 5 5
1 5 7];
I want to have
B = [1 4 12
1 5 6]
I really appreciate your help
Thanks
Ali
Like this?
A = [1 4 12;1 4 14;1 4 10; 1 5 5;1 5 7];
[x,y] = consolidator(A(:,1:2),A(:,3),#mean);
B = [x,y]
B =
1 4 12
1 5 6
Consolidator is on the File Exchange.
Using built-in functions:
sparsemean = accumarray(A(:,1:2), A(:,3).', [], #mean, 0, true);
[i,j,v] = find(sparsemean);
B = [i.' j.' v.'];
A = [1 4 12;1 4 14;1 4 10; 1 5 5;1 5 7]; %your example data
B = unique(A(:, 1:2), 'rows'); %find the unique xy pairs
C = nan(length(B), 1);
% calculate means
for ii = 1:length(B)
C(ii) = mean(A(A(:, 1) == B(ii, 1) & A(:, 2) == B(ii, 2), 3));
end
C =
12
6
The step inside the for loop uses logical indexing to find the mean of rows that match the current xy pair in the loop.
Use unique to get the unique rows and use the returned indexing array to find the ones that should be averaged and ask accumarray to do the averaging part:
[C,~,J]=unique(A(:,1:2), 'rows');
B=[C, accumarray(J,A(:,3),[],#mean)];
For your example
>> [C,~,J]=unique(A(:,1:2), 'rows')
C =
1 4
1 5
J =
1
1
1
2
2
C contains the unique rows and J shows which rows in the original matrix correspond to the rows in C then
>> accumarray(J,A(:,3),[],#mean)
ans =
12
6
returns the desired averages and
>> B=[C, accumarray(J,A(:,3),[],#mean)]
B =
1 4 12
1 5 6
is the answer.