Matlab vector to matrix conversion - matlab

I want to convert the following vector A into matrix B, best demonstrated by this example:
n = 4;
A = [1 2 3 4 5 6];
B = [ 1 2 3 4;
2 3 4 5;
3 4 5 6; ]
I am currently using a loop to achieve this and wondered if it was possible to vectorize it?
Thanks L.

You can use bsxfun -
A(bsxfun(#plus,[0:numel(A)-n]',1:n))
You can also use hankel -
hankel(A(1:n),A(n:end)).'
Sample run -
>> A = [3,4,6,0,1,2]
A =
3 4 6 0 1 2
>> n
n =
4
>> A(bsxfun(#plus,[0:numel(A)-n]',1:n))
ans =
3 4 6 0
4 6 0 1
6 0 1 2
>> hankel(A(1:n),A(n:end)).'
ans =
3 4 6 0
4 6 0 1
6 0 1 2

If you have the Signal Processing Toolbox you can also use convmtx:
n = 4;
A = [1 2 3 4 5 6];
m = numel(A)-n;
B = flipud(convmtx(A,m+1));
B = B(:,m+1:end-m);

Related

Indexing a matrix in matlab according to conditions set on other matrices

I am trying to index my matrix based on two conditions, I'll explain.
Let's say I have two matrices:
a = [7 3 4; 5 6 7; 4 8 0];
b = [1 9 8; 2 4 6; 6 1 6];
And a third matrix to index:
c = [1 2 3; 4 5 6; 7 8 9];
My aim is to index c in a way that I get a 3x3 matrix in which only the values of c are copied over for whose indexes the following conditions are met and the rest are zeros.
a <= 5, b >= 6
Resulting matrix:
result = [0 2 3; 0 0 0; 7 0 9]
I hope I was able to explain my problem.
Given
a = [7 3 4; 5 6 7; 4 8 0];
b = [1 9 8; 2 4 6; 6 1 6];
c = [1 2 3; 4 5 6; 7 8 9];
result = zeros(size(c);
Using logical indexing,
>> d = (a <= 5) & (b >= 6)
d =
0 1 1
0 0 0
1 0 1
>> result(d) = c(d)
result =
0 2 3
0 0 0
7 0 9
Loop throw rows and columns and set the result.
for row=1:size(a,1)
for col=1:size(a,2)
if(a(row,col)> b(row,col))
result(row,col) = 0
else
result(row,col) = c(row,col)
end
end
end

Count repeating integers in an array

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];

how to remove the column with all the same elements in matlab?

Suppose the input is:
[1 2 3;
2 3 3;
3 4 3;
3 5 3;]
The expected output would be:
[1 2;
2 3;
3 4;
3 5;]
The reason to remove the third column is because all the elements in the third column is the same. Is there a default matlab function for this?
A(:,sum(abs(diff(A)))>0,1)
"Keep the columns where the difference is larger than zero"
Both the posted answers are incorrect. Test the edge cases where A only has 1 or 2 rows:
i.e:
A = [1 2 3];
or:
A = [1 2 3;
2 3 3];
diff and any need to be supplied with the correct dimension:
A = A(:,any(diff(A,1,1),1));
This outputs:
A = [1 2 3; 2 3 3];
EDU>> A(:,any(diff(A,1,1),1))
ans =
1 2
2 3
and
A = [1 2 3]
EDU>> A(:,any(diff(A,1,1),1))
ans =
Empty matrix: 1-by-0
Also, IMO this, semantically, makes the most sense:
A(:,all(bsxfun(#eq,A,A(1,:)),1)) = []
How about:
A =
1 2 3
2 3 3
3 4 3
3 5 3
B = A==repmat(A(1,:),size(A,1),1)
B =
1 1 1
0 0 1
0 0 1
0 0 1
C = sum(B) == size(A,1)
C =
0 0 1
A(:,C) =[]
A =
1 2
2 3
3 4
3 5
In one line:
A(:, sum(A==repmat(A(1,:),size(A,1),1)) == size(A,1)) = []

MATLAB Matrix Transformation

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

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