Outer product in Matlab? - matlab

How to turn two vectors into a matrix of all combinations of their elements?
For example, vectors
>> A=[1;2;3]
A =
1
2
3
>> B=[4;5;6]
B =
4
5
6
Should be turned to
[1, 4; 1, 5; 1, 6; 2, 4; 2, 5; 2, 6; 3, 4; 3, 5; 3, 6]
ans =
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6

I'm sure there is a simpler way of doing this but... meshgrid will get you close and you just need to perform some array manipulation to get your result:
[BA, BB] = meshgrid(A,B);
[BA(:) BB(:)]

An order of magnitude slower than meshgrid, but just to show you a different method:
[kron(A,ones(numel(B),1)), kron(ones(numel(A),1), B)];

Related

Find which matrix row has values specified from array

How can I find which row in a matrix has a specified set values that I entered in an array?
So for example;
A = [4 5 6 7;
8 4 5 6;
4 5 6 8;
8 4 8 9;
1 2 2 4;
5 3 4 6];
and I want to find which row has the vector of [4 5 6 8]
You can use a combination of all and find...
With implicit expansion (R2016b or newer)
find( all( A == [4 5 6 8], 2 ) )
Equivalently you can use bsxfun (compatible with all MATLAB versions)
find( all( bsxfun( #eq, A, [4 5 6 8] ), 2 ) )
The output in both cases is 3 from your example A.
I would go for #Wolfie's approach, assuming order matters.
Another possibility is to use ismember. This can be used both when order matters and when it doesn't. Let
A = [4 5 6 7; 8 4 5 6; 4 5 6 8; 8 4 8 9; 1 2 2 4; 5 3 4 6];
v = [4 5 6 8];
If order matters:
result = find(ismember(A, v, 'rows'));
If order doesn't matter:
result = find(all(ismember(A, v), 2));

3d matrix inline initialization

Is there any way to inline initialize a 3D matrix in MATLAB in a single line? Thus, without use of for-loops and pre-initialization, e.g. via zero(a,b,c). As far as I know we can only do 2D as in:
matr=[1,2;3,4]
where , and ; indicate the two dimensions. Is there any deliminator for the third dimension that I do not know about? I know that the a multi-line initilization is possible via
matr(:,:,1) = [1 2 3; 9 8 7; 4 6 5];
matr(:,:,2) = [0 3 2; 8 8 4; 5 3 5];
matr(:,:,3) = [6 4 7; 6 8 5; 5 4 3];
Use cat to concatenate along the third dimension:
cat(3, [1 2 3; 9 8 7; 4 6 5], [0 3 2; 8 8 4; 5 3 5], [6 4 7; 6 8 5; 5 4 3])
You can also achieve this using reshape:
reshape([[1 2 3; 9 8 7; 4 6 5], [0 3 2; 8 8 4; 5 3 5], [6 4 7; 6 8 5; 5 4 3]], [3,3,3])

How do I Combine two equal sized vectors element wise in MatLab?

I have two vectors:
a = [1 3 5 7 9];
b = [2 4 6 8 10];
That I need to combine together element wise. Meaning that I need the first element of vector a, then the first element of vector b, second of a, second of b, and so forth until I get the following:
combined = [1 2 3 4 5 6 7 8 9 10]
How do I do this within MatLab?
Edit
I ran a test of the top three answers (Josh, Marc, & Kronos) and compared the time it took to run them. I ran each 100 times after doing a 10 iteration warmup. The vectors created were exactly the same size in length (16e+6) and were random values ranging from 1 to 100:
Test Results
Test: Total Time (100 runs): Avg Time Per Exec:
Josh B 21.3687 0.2137
Marc C 21.4273 0.2143
Kronos 31.1897 0.3119
It appears that both Josh's and Marc's solutions are similar in execution time.
a = [1 3 5 7 9];
b = [2 4 6 8 10];
temp = [a; b];
combined = temp(:)';
This can be done by the following:
a = [1 3 5 7 9];
b = [2 4 6 8 10];
combinedSize = size(a, 2) * 2;
combined(1:2:combinedSize) = a;
combined(2:2:combinedSize) = b;
This is obviously assuming that your vectors are exactly the same size. If by chance you want to merge two vectors that are not the same size then you can do the following:
combinedSize = max(size(a, 2), size(b, 2)) * 2;
combined = NaN(1,combinedSize);
combined(1:2:size(a,2)*2) = a;
combined(2:2:size(b,2)*2) = b;
This will place a NaN for the remaining elements of the smaller vector. For example, given the following sample vectors:
a = [1 3 5 7 9 11];
b = [2 4 6 8];
will result in the combined vector:
combined =
1 2 3 4 5 6 7 8 9 NaN 11 NaN
Place the vectors below eachother in a matrix and use reshape. For example:
>> A=[1 2 3]
A =
1 2 3
>> B=[4 5 6]
B =
4 5 6
>> C=reshape([A;B],1,size(A,2)+size(B,2))
C =
1 4 2 5 3 6
It's straightforward to generalize to more than 2 vectors.
You can also give a try to looping, for example:
a=[1 2 3 4 5];
b=[11 12 13 14 15];
for i = 1:N
{
if (i%2==0)
{ c[i] = b[i]; }
else
{ c[i] = a[i]; }
This shall work!
All the answers above only work if the two vectors have the same number of elements. The following will work even if they have different number of elements:
>>
A = [1 3 5];
B = [2 4 6 7 8];
C = [1 3 5 7 8];
D = [2 4 6];
AB = nan(1,2*max(numel(A),numel(B)));
CD = nan(1,2*max(numel(C),numel(D)));
AB(2*(1:length(A))) = A;
AB(1+2*(1:length(B))) = B;
CD(2*(1:length(C))) = C;
CD(1+2*(1:length(D))) = D;
>>
AB = AB(~isnan(AB))
CD = CD(~isnan(CD))
The result would be:
AB =
1 2 3 4 5 6 7 8
CD =
1 2 3 4 5 6 7 8

GROUP BY in MATLAB

I want to do what SQL's GROUP BY does in MATLAB. For example,
M = [
1, 5;
2, 5;
3, 5;
1, 6;
2, 6;
1,7 ]
SQL: SELECT MAX(c1), c2 FROM M(c1, c2) GROUP BY 2
Result = [
3, 5;
2, 6;
1, 7]
How can I do this in Matlab?
grpstats in the Statistics Toolbox can do this:
>> [grpstats(M(:,1), M(:,2), {'max'}) unique(M(:,2))]
ans =
3 5
2 6
1 7
If you don't mind doing some preprocessing to get the order (or if the first column is nicely built from 1 to n), you can do it like this:
accumarray([1 2 3 1]',[11 12 13 14]',[],#max)
This will give:
14
12
13
Or in your case:
accumarray(M(:,1),M(:,2),[],#max)
Note the order. The second number for example, will correspond to M(:,1) == 2
I think there is a simple solution to this.
Here is what I tested on Matlab and it worked:
>> M = [
1, 5;
2, 5;
3, 5;
1, 6;
2, 6;
1,7 ];
>> grpstats(M,M(:,2),{'max'})
ans =
3 5
2 6
1 7

How do I convert a 2X2 matrix to 4X4 matrix in MATLAB?

I need some help in converting a 2X2 matrix to a 4X4 matrix in the following manner:
A = [2 6;
8 4]
should become:
B = [2 2 6 6;
2 2 6 6;
8 8 4 4;
8 8 4 4]
How would I do this?
In newer versions of MATLAB (R2015a and later) the easiest way to do this is using the repelem function:
B = repelem(A, 2, 2);
For older versions, a short alternative to the other (largely) indexing-based solutions is to use the functions kron and ones:
>> A = [2 6; 8 4];
>> B = kron(A, ones(2))
B =
2 2 6 6
2 2 6 6
8 8 4 4
8 8 4 4
Can be done even easier than Jason's solution:
B = A([1 1 2 2], :); % replicate the rows
B = B(:, [1 1 2 2]); % replicate the columns
Here's one more solution:
A = [2 6; 8 4];
B = A( ceil( 0.5:0.5:end ), ceil( 0.5:0.5:end ) );
which uses indexing to do everything and doesn't rely on the size or shape of A.
This works:
A = [2 6; 8 4];
[X,Y] = meshgrid(1:2);
[XI,YI] = meshgrid(0.5:0.5:2);
B = interp2(X,Y,A,XI,YI,'nearest');
This is just two-dimensional nearest-neighbor interpolation of A(x,y) from x,y ∈ {1,2} to x,y ∈ {0.5, 1, 1.5, 2}.
Edit: Springboarding off of Jason S and Martijn's solutions, I think this is probably the shortest and clearest solution:
A = [2 6; 8 4];
B = A([1 1 2 2], [1 1 2 2]);
A = [2 6; 8 4];
% arbitrary 2x2 input matrix
B = repmat(A,2,2);
% replicates rows & columns but not in the way you want
B = B([1 3 2 4], :);
% swaps rows 2 and 3
B = B(:, [1 3 2 4]);
% swaps columns 2 and 3, and you're done!
Here's a method based on simple indexing that works for an arbitrary matrix. We want each element to be expanded to an MxN submatrix:
A(repmat(1:end,[M 1]),repmat(1:end,[N 1]))
Example:
>> A=reshape(1:6,[2,3])
A =
1 3 5
2 4 6
>> A(repmat(1:end,[3 1]),repmat(1:end,[4 1]))
ans =
1 1 1 1 3 3 3 3 5 5 5 5
1 1 1 1 3 3 3 3 5 5 5 5
1 1 1 1 3 3 3 3 5 5 5 5
2 2 2 2 4 4 4 4 6 6 6 6
2 2 2 2 4 4 4 4 6 6 6 6
2 2 2 2 4 4 4 4 6 6 6 6
To see how the method works, let's take a closer look at the indexing. We start with a simple row vector of consecutive numbers
>> m=3; 1:m
ans =
1 2 3
Next, we extend it to a matrix, by repeating it M times in the first dimension
>> M=4; I=repmat(1:m,[M 1])
I =
1 2 3
1 2 3
1 2 3
1 2 3
If we use a matrix to index an array, then the matrix elements are used consecutively in the standard Matlab order:
>> I(:)
ans =
1
1
1
1
2
2
2
2
3
3
3
3
Finally, when indexing an array, the 'end' keyword evaluates to the size of the array in the corresponding dimension. As a result, in the example the following are equivalent:
>> A(repmat(1:end,[3 1]),repmat(1:end,[4 1]))
>> A(repmat(1:2,[3 1]),repmat(1:3,[4 1]))
>> A(repmat([1 2],[3 1]),repmat([1 2 3],[4 1]))
>> A([1 2;1 2;1 2],[1 2 3;1 2 3;1 2 3;1 2 3])
>> A([1 1 1 2 2 2],[1 1 1 1 2 2 2 2 3 3 3 3])
There is a Reshape() function that allows you to do this...
For example:
reshape(array, [64, 16])
And you can find a great video tutorial here
Cheers