Straighten and concatenate the individual grids from ndgrid [duplicate] - matlab

This question already has answers here:
Generate a matrix containing all combinations of elements taken from n vectors
(4 answers)
Closed 6 years ago.
I'm trying to do the following in a general way:
x = {0:1, 2:3, 4:6};
[a,b,c] = ndgrid(x{:});
Res = [a(:), b(:), c(:)]
Res =
0 2 4
1 2 4
0 3 4
1 3 4
0 2 5
1 2 5
0 3 5
1 3 5
0 2 6
1 2 6
0 3 6
1 3 6
I believe I have to start the following way, but I can't figure out how to continue:
cell_grid = cell(1,numel(x));
[cell_grid{:}] = ndgrid(x{:});
[cell_grid{:}]
ans =
ans(:,:,1) =
0 0 2 3 4 4
1 1 2 3 4 4
ans(:,:,2) =
0 0 2 3 5 5
1 1 2 3 5 5
ans(:,:,3) =
0 0 2 3 6 6
1 1 2 3 6 6
I can solve this in many ways for the case with three variables [a, b, c], both with and without loops, but I start to struggle when I get more vectors. Reshaping it directly will not give the correct result, and mixing reshape with permute becomes really hard when I have arbitrary number of dimensions.
Can you think of a clever way to do this that scales to 3-30 vectors in x?

You can use cellfun to flatten each of the cell array elements and then concatenate them along the second dimension.
tmp = cellfun(#(x)x(:), cell_grid, 'uniformoutput', false);
out = cat(2, tmp{:})
Alternately, you could avoid cellfun and concatenate them along the dimension that is one higher than your dimension of each cell_grid member (i.e. numel(x) + 1). Then reshape to flatten all dimensions but the last one you just concatenated along.
out = reshape(cat(numel(x) + 1, cell_grid{:}), [], numel(x));

Related

How do I extract the odd and even rows of my matrix into two separate matrices in scilab?

I'm very new to scilab syntax and can't seem to find a way to extract the even and odd elements of a matrix into two separate matrix, suppose there's a matrix a:
a=[1,2,3,4,5,6,7,8,9]
How do I make two other matrix b and c which will be like
b=[2 4 6 8] and c=[1 3 5 7 9]
You can separate the matrix by calling row and column indices:
a=[1,2,3,4,5,6,7,8,9];
b=a(2:2:end);
c=a(1:2:end);
[2:2:end] means [2,4,6,...length(a)] and [1:2:end]=[1,3,5,...length(a)]. So you can use this tip for every matrix for example if you have a matrix a=[5,4,3,2,1] and you want to obtain the first three elements:
a=[5,4,3,2,1];
b=a(1:1:3)
b=
1 2 3
% OR YOU CAN USE
b=a(1:3)
If you need elements 3 to 5:
a=[5,4,3,2,1];
b=a(3:5)
b=
3 2 1
if you want to elements 5 to 1, i.e. in reverse:
a=[5,4,3,2,1];
b=a(5:-1:1);
b=
1 2 3 4 5
a=[1,2,3,4,5,6,7,8,9];
b = a(mod(a,2)==0);
c = a(mod(a,2)==1);
b =
2 4 6 8
c =
1 3 5 7 9
Use mod to check whether the number is divisible by 2 or not (i.e. is it even) and use that as a logical index into a.
The title is about selecting rows of a matrix, while the body of the question is about elements of a vector ...
With Scilab, for rows just do
a = [1,2,3 ; 4,5,6 ; 7,8,9];
odd = a(1:2:$, :);
even = a(2:2:$, :);
Example:
--> a = [
5 4 6
3 6 5
3 5 4
7 0 7
8 7 2 ];
--> a(1:2:$, :)
ans =
5 4 6
3 5 4
8 7 2
--> a(2:2:$, :)
ans =
3 6 5
7 0 7

How can I go through the columns of a matrix in matlab and add them each to a specific column of a sum matrix in matlab?

Supose there is a Matrix
A =
1 3 2 4
4 2 5 8
6 1 4 9
and I have a Vector containing the "class" of each column of this matrix for example
v = [1 , 1 , 2 , 3]
How can I sum the columns of the matrix to a new matrix as column vectors each to the column of their class? In this example columns 1 and 2 of A would added to the first column of the new matrix, column 2 to the 3 to the 2nd, column 4 the the 3rd.
Like
SUM =
4 2 4
6 5 8
7 4 9
Is this possible without loops?
One of the perfect scenarios to combine the powers of accumarray and bsxfun -
%// Since we are to accumulate columns, first step would be to transpose A
At = A.' %//'
%// Create a vector of linear IDs for use with ACCUMARRAY later on
idx = bsxfun(#plus,v(:),[0:size(A,1)-1]*max(v))
%// Use ACCUMARRAY to accumulate rows from At, i.e. columns from A based on the IDs
out = reshape(accumarray(idx(:),At(:)),[],size(A,1)).'
Sample run -
A =
1 3 2 4 6 0
4 2 5 8 9 2
6 1 4 9 8 9
v =
1 1 2 3 3 2
out =
4 2 10
6 7 17
7 13 17
An alternative with accumarray in 2D. Generate a grid with the vector v and then apply accumarray:
A = A.';
v = [1 1 2 3];
[X, Y] = ndgrid(v,1:size(A,2));
Here X and Y look like this:
X =
1 1 1
1 1 1
2 2 2
3 3 3
Y =
1 2 3
1 2 3
1 2 3
1 2 3
Then apply accumarray:
B=accumarray([X(:) Y(:)],A(:)),
SUM = B.'
SUM =
4 2 4
6 5 8
7 4 9
As you see, using [X(:) Y(:)] create the following array:
ans =
1 1
1 1
2 1
3 1
1 2
1 2
2 2
3 2
1 3
1 3
2 3
3 3
in which the vector v containing the "class" is replicated 3 times since there are 3 unique classes that are to be summed up together.
EDIT:
As pointed out by knedlsepp you can get rid of the transpose to A and B like so:
[X2, Y2] = ndgrid(1:size(A,1),v);
B = accumarray([X2(:) Y2(:)],A(:))
which ends up doing the same. I find it a bit more easier to visualize with the transposes but that gives the same result.
How about a one-liner?
result = full(sparse(repmat(v,size(A,1),1), repmat((1:size(A,1)).',1,size(A,2)), A));
Don't optimize prematurely!
The for loop performs fine for your problem:
out = zeros(size(A,1), max(v));
for i = 1:numel(v)
out(:,v(i)) = out(:,v(i)) + A(:,i);
end
BTW: With fine, I mean: fast, fast, fast!

Verify a matrix value on MATLAB 2 [duplicate]

This question already has answers here:
Verify a matrix value on MATLAB
(3 answers)
Closed 8 years ago.
I am using MATLAB. I have a question about how i can verify that the values of a matrix are being repeating, like this:
A=[ 2 3 2 3 2 3 2 3]
with the answer AUX=1
If the matrix A repeat at least the first two values for all columns after, i want a AUX = 1. but if not, only AUX= 0.
or
A=[ 2 3 3 2 2 3 3 2]
with the answer AUX=1
If the matrix A repeat like before, i want a AUX = 1. but if not, only AUX= 0.
The matrix A can also have zeros numbers after the numbers. (example, A = [ 1 2 1 2 1 0 0 0], A = [ 2 3 3 2 2 3 3 2 0 0 0 ].)
I think you are looking for this, finding whether the same two numbers are used in each non overlapping window of 2 values:
% Cutting off the tail
x = [1 2 2 1 1 2 1 2 0 0];
x = x(1:find(x,1,'last'));
x = x(1:2*fix(numel(x)/2));
% Checking for allowed values (the first 2 values, each one once)
M=sort(reshape(x,2,[]));
AUX = size(unique(M','rows'),1)==1
Note that this cuts of trailing zeros, so you may need an extra step if the number of remaining elements is not always odd but that should be easy.
% A
A = [1 2 3 4 4 5; 1 3 4 5 6 5; 6 7 4 1 3 3];
% make A a column vector
A_col = A(:);
% calculate histogram of A with max(A_col) bins
n = hist(A_col, max(A_col));
AUX = sum(n > 1) > 0

Create a new matrix from existing matrix between zeros

I have in a matrix data that contains 0 and 'proper' data. I want to crete several matrixes (new ones) to separate the data from the zeros and get rid of these zeros.
So, here is a simple example:
data = 1 3 6 4
3 6 9 5
4 5 6 2
0 0 0 0
0 0 0 0
2 4 1 8
1 4 6 5
0 0 0 0
1 7 9 1
3 4 5 8
And i want to get in this case two matrixes that would be:
A =1 3 6 4
3 6 9 5
4 5 6 2
B= 2 4 1 8
1 4 6 5
C = 1 7 9 1
3 4 5 8
Obviously my data files have thousands of datapoint and i need to automat this.
Any ideas how to do it?
Step 1: create an index of the rows containing only zeros using all:
index = all(data==0,2); #% data==0<-- logical matrix; the 2 means along dimension 2
Step 2: create vectors containing the first and last indices of each segment of desired values:
index = [1; double(index); 1]; #% convert to numeric and pad with ones
firsts = diff(index)==-1; #% 0 (real row) - 1 (spacer row) = -1
lasts = (diff(index)==1)-1; #% subtract 1 because of padding
Step 3: Create a cell array which contains sequential segments of the original matrix in each cell (using cell arrays, each cell can be a different size, or even a different type):
#% firsts and lasts should be the same length
#% iterate through lists of first/last indices
for ii=1:length(firsts)
result{ii} = data(firsts(ii):lasts(ii), :);
end
Obligatory Matlab public service announcement: i and j are popular loop index variables... you'll notice I used ii instead. Here's why.
here's an alternative way that keeps the # of columns of data in the resulted cell array:
L=bwlabel(data);
for n=1:max(L)
result{n}=reshape(data(L==n),[],size(data,2));
end
result =
[3x4 double] [2x4 double] [2x4 double]
result{1}
ans =
1 3 6 4
3 6 9 5
4 5 6 2

MATLAB Concatenate vectors with unequal dimensions

Lets say I have got vector1:
2
3
5
6
7
9
And a vector2:
1
2
3
Now I would like to obtain the following matrix:
2 1
3 2
5 3
6 1
7 2
9 3
That is, I want to add vector2 as a column next to vector1 until the new column is completely filled. I have to do this with a lot of vectors with different sizes. The only thing I know in advance is that the length of vector1 is an integer multiple of the length of vector2.
Any suggestions?
Use repmat to replicate the smaller matrix.
a = [2 3 5 6 7 9]';
b = [1 2 3]';
c = [a repmat(b, length(a) / length(b), 1)]
Result:
c =
2 1
3 2
5 3
6 1
7 2
9 3
You can then replicate the vector:
[vector1, repmat(vector2,n,1)]
where n is your multiple of vector2.
This could be an alternative
[x [y'; y']]