I have two matrices, one of which (Let's say matrix H) is 4x2 and the other one (matrix N) is 100x2.
I want to make a combination for every pair of N, containing every pair of H.
Basically, if my
H = [2 2; 2 4; 4 2; 4 4]
N = [1 1; 1 2; 1 3; ...;
10 8; 10 9; 10 10]
I would like to have a final matrix
M = [1 2 2 1; 1 2 4 1; 1 4 2 1; 1 4 4 1; 1 2 2 2; 1 2 4 2; ...; 10 4 4 10]
of a size 100x4 (because every pair of N will be multiplied |H|=4 times.)
So all the pairs of H matrix will be between all pairs of my N matrix.
I hope I am clear enough.
Use the follwing syntax:
%calculates the Cartesian multipication of 1:size(h,1) and 1:size(N,1)
sets = {1:size(H,1), 1:size(N,1)};
[hInds, nInds] = ndgrid(sets{:});
%generates the output matrix
outRes = [N( nInds(:),1),H( hInds(:),1),H( hInds(:),2),N( nInds(:),2)];
Partial results (displaying just the first rows of the output):
outRes =
1 2 2 1
1 2 4 1
1 4 2 1
1 4 4 1
1 2 2 2
1 2 4 2
1 4 2 2
1 4 4 2
1 2 2 3
1 2 4 3
1 4 2 3
1 4 4 3
...
Notice that if N is 4x2 and N is 10x2, the final matrix size will be 40x4 and not 100x4 as you mentioned.
Try this:
H= [2 2; 2 4; 4 2; 4 4];
N= fix(100*(rand(10,2))) % Replace this with your N matrix
iter=0;
for i=1:10
for j=1:4
iter=iter+1;
A(iter,:)=[N(i,1), H(j,1:2), N(i,2)];
end
end
A
Related
If I have this vector:
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6]
I would like to get the position of each unique number according to itself.
y = [1 2 3 4 5 1 2 3 1 1 2 1 2 3 4]
At the moment I'm using:
y = sum(triu(x==x.')) % MATLAB 2016b and above
It's compact but obviously not memory efficient.
For the pure beauty of MATLAB programming I would avoid using a loop. Do you have a better simple implementation ?
Context:
My final goal is to sort the vector x but with the constraint that a number that appear N times has the priority over another number that has appeared more than N times:
[~,ind] = sort(y);
x_relative_sort = x(ind);
% x_relative_sort = 1 2 3 4 6 1 2 4 6 1 2 6 1 6 1
Assuming x is sorted, here's one vectorized alternative using unique, diff, and cumsum:
[~, index] = unique(x);
y = ones(size(x));
y(index(2:end)) = y(index(2:end))-diff(index).';
y = cumsum(y);
And now you can apply your final sorting:
>> [~, ind] = sort(y);
>> x_relative_sort = x(ind)
x_relative_sort =
1 2 3 4 6 1 2 4 6 1 2 6 1 6 1
If you have positive integers you can use sparse matrix:
[y ,~] = find(sort(sparse(1:numel(x), x, true), 1, 'descend'));
Likewise x_relative_sort can directly be computed:
[x_relative_sort ,~] = find(sort(sparse(x ,1:numel(x),true), 2, 'descend'));
Just for variety, here's a solution based on accumarray. It works for x sorted and containing positive integers, as in the question:
y = cell2mat(accumarray(x(:), x(:), [], #(t){1:numel(t)}).');
You can be more memory efficient by only comparing to unique(x), so you don't have a large N*N matrix but rather N*M, where N=numel(x), M=numel(unique(x)).
I've used an anonymous function syntax to avoid declaring an intermediate matrix variable, needed as it's used twice - this can probably be improved.
f = #(X) sum(cumsum(X,2).*X); y = f(unique(x).'==x);
Here's my solution that doesn't require sorting:
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
y = cell2mat( splitapply(#(v){cumsum(v)},x,cumsum(logical([1 diff(x)]))) ) ./ x;
Explanation:
% Turn each group new into a unique number:
t1 = cumsum(logical([1 diff(x)]));
% x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
% t1 = [1 1 1 1 1 2 2 2 3 4 4 5 5 5 5 6 6 6];
% Apply cumsum separately to each group:
t2 = cell2mat( splitapply(#(v){cumsum(v)},x,t1) );
% t1 = [1 1 1 1 1 2 2 2 3 4 4 5 5 5 5 6 6 6];
% t2 = [1 2 3 4 5 2 4 6 3 4 8 6 12 18 24 1 2 3];
% Finally, divide by x to get the increasing values:
y = t2 ./ x;
% x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
% t2 = [1 2 3 4 5 2 4 6 3 4 8 6 12 18 24 1 2 3];
So i have two very long matrices. A sample is given below:
First_Matrix:
A = [...
1 1 1;
1 1 2;
1 1 3;
1 2 1;
1 2 2;
1 2 3;
1 3 1;
1 3 2;
1 3 3];
Second Matrix
B = [...
1 1 916;
1 2 653;
1 3 114];
And I would like a thirds matrix that would combine the first matrix with the third column of the second matrix, based on the values in the first two column of the 2 matrices matching (being the same).
So Ouput_Matrix:
C = [...
1 1 1 916;
1 1 2 916;
1 1 3 916;
1 2 1 653;
1 2 2 653;
1 2 3 653;
1 3 1 114;
1 3 2 114;
1 3 3 11];
What would be the best way to do this?
Thanks in advance
Use the second output of ismember with the 'rows' option to get the indices of the matching, from which you can easily build the result:
[~, ind] = ismember(A(:, [1 2]), B(:, [1 2]), 'rows');
C = [A B(ind, 3)];
The for loop isn't pretty and might slow you down if B is very long. But I don't think it's possible to avoid (edit: it seems it is).
A = [1 1 1
1 1 2
1 1 3
1 2 1
1 2 2
1 2 3
1 3 1
1 3 2
1 3 3];
B = [1 1 916
1 2 653
1 3 114];
C = [A zeros(size(A,1),1)];
for i = 1:size(B,1)
C(all(B(i,1:2)==A(:,1:2),2),4) = B(i,3);
end
C =
1 1 1 916
1 1 2 916
1 1 3 916
1 2 1 653
1 2 2 653
1 2 3 653
1 3 1 114
1 3 2 114
1 3 3 114
It is possible to achieve what you want without a for loop, but it may not be the most optimal implementation:
n = size(B, 1); % number of rows in B
B_(1, :, :) = B'; % convert to 3D matrix to be able to use elementwise comparision
x = squeeze(all(bsxfun(#eq, A(:, 1:2), B_(1, 1:2,:)), 2)); % x(i, j) == 1 if row A(i, :) matches B(j, :)
index = x * (1:n)'; % row B(index(i), :) corresponds with row A(i, :)
A(:, 4) = B(index, 3); % add data to A
An alternative formulation for x, without conversion to 3D, is:
x = bsxfun(#eq, A(:, 1), B(:,1)') & bsxfun(#eq, A(:, 2), B(:,2)');
The disadvantage of this method is that it less extendable to more matching columns.
given matrix A of size 6 by 6 contain blocks of numbers,each block of size 2 by 2, and outher reference matrix R of size 2 by 12 also contain blocks of numbers, each block of size 2 by 2. the perpse of the whole process is to form a new matrix, called the Index matrix, contain index's that refer to the position of the blocks within the matrix A based on the order of the blocks within the reference matrix R. and here is an exemple
matrix A:
A =[1 1 2 2 3 3;
1 1 2 2 3 3;
1 1 3 3 4 4;
1 1 3 3 4 4;
4 4 5 5 6 6;
4 4 5 5 6 6 ]
matrix R:
R=[1 1 2 2 3 3 4 4 5 5 6 6;
1 1 2 2 3 3 4 4 5 5 6 6 ]
the new matrix is:
Index =[1 2 3;
1 3 4;
4 5 6]
any ideas ?
With my favourite three guys - bsxfun, permute, reshape for an efficient and generic solution -
blksz = 2; %// blocksize
num_rowblksA = size(A,1)/blksz; %// number of blocks along rows in A
%// Create blksz x blksz sized blocks for A and B
A1 = reshape(permute(reshape(A,blksz,num_rowblksA,[]),[1 3 2]),blksz^2,[])
R1 = reshape(R,blksz^2,1,[])
%// Find the matches with "bsxfun(#eq" and corresponding indices
[valid,idx] = max(all(bsxfun(#eq,A1,R1),1),[],3)
%// Or with PDIST2:
%// [valid,idx] = max(pdist2(A1.',reshape(R,blksz^2,[]).')==0,[],2)
idx(~valid) = 0
%// Reshape the indices to the shapes of blocked shapes in A
Index = reshape(idx,[],num_rowblksA).'
Sample run with more random inputs -
>> A
A =
2 1 1 2
1 2 2 1
1 1 1 1
2 2 2 2
1 2 2 1
1 2 1 1
>> R
R =
2 1 1 1 1 2 2 2 1 1 1 1
2 1 2 1 1 2 2 1 2 2 2 1
>> Index
Index =
0 0
5 5
3 0
I have a list of numbers, [1:9], that I need to divide three groups. Each group must contain at least one number. I need to enumerate all of the combinations (i.e. order does not matter). Ideally, the output is a x by 3 array. Any ideas of how to do this in matlab?
Is this what you want:
x = 1:9;
n = length(x);
T=3;
out = {};
%// Loop over all possible solutions
for k=1:T^n
s = dec2base(k, T, n);
out{k}{T} = [];
for p=1:n
grpIndex = str2num(s(p))+1;
out{k}{grpIndex} = [out{k}{grpIndex} x(p)];
end
end
%// Print result. size of out is the number of ways to divide the input. out{k} contains 3 arrays with the values of x
out
Maybe this is what you want. I'm assuming that the division in groups is "monotonous", that is, first come the elements of the first group, then those of the second etc.
n = 9; %// how many numbers
k = 3; %// how many groups
b = nchoosek(1:n-1,k-1).'; %'// "breaking" points
c = diff([ zeros(1,size(b,2)); b; n*ones(1,size(b,2)) ]); %// result
Each column of c gives the sizes of the k groups:
c =
Columns 1 through 23
1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 4 4 4 4 5
1 2 3 4 5 6 7 1 2 3 4 5 6 1 2 3 4 5 1 2 3 4 1
7 6 5 4 3 2 1 6 5 4 3 2 1 5 4 3 2 1 4 3 2 1 3
Columns 24 through 28
5 5 6 6 7
2 3 1 2 1
2 1 2 1 1
This produces what I was looking for. The function nchoosekr_rec() is shown below as well.
for x=1:7
numgroups(x)=x;
end
c=nchoosekr_rec(numgroups,modules);
i=1;
d=zeros(1,modules);
for x=1:length(c(:,1))
c(x,modules+1)=sum(c(x,1:modules));
if c(x,modules+1)==length(opt_mods)
d(i,:)=c(x,1:modules);
i=i+1;
end
end
numgroups=[];
for x=1:length(opt_mods)
numgroups(x)=x;
end
count=0;
for x=1:length(d(:,1))
combos=combnk(numgroups,d(x,1));
for y=1:length(combos(:,1))
for z=1:nchoosek(9-d(x,1),d(x,2))
new_mods{count+z,1}=combos(y,:);
numgroups_temp{count+z,1}=setdiff(numgroups,new_mods{count+z,1});
end
count=count+nchoosek(9-d(x,1),d(x,2));
end
end
count=0;
for x=1:length(d(:,1))
for y=1:nchoosek(9,d(x,1))
combos=combnk(numgroups_temp{count+1},d(x,2));
for z=1:length(combos(:,1))
new_mods{count+z,2}=combos(z,:);
new_mods{count+z,3}=setdiff(numgroups_temp{count+z,1},new_mods{count+z,2});
end
count=count+length(combos(:,1));
end
end
function y = nchoosekr_rec(v, n)
if n == 1
y = v;
else
v = v(:);
y = [];
m = length(v);
if m == 1
y = zeros(1, n);
y(:) = v;
else
for i = 1 : m
y_recr = nchoosekr_rec(v(i:end), n-1);
s_repl = zeros(size(y_recr, 1), 1);
s_repl(:) = v(i);
y = [ y ; s_repl, y_recr ];
end
end
end
I need to transform a matrix:
X = [1 2; 3 4]
X = 1 2
3 4
to
X = [1 2; 1 2; 1 2; 3 4; 3 4; 3 4]
X = 1 2
1 2
1 2
3 4
3 4
3 4
and do this operation for a matrix with any number of rows.
How can I achieve this in MATLAB?
Here is a nice and easy way to do this using kron
kron(X,[1 1 1]')
this produces
1 2
1 2
1 2
3 4
3 4
3 4