Matlab - How to create logical array matrix without looping [duplicate] - matlab

This question already has answers here:
Creating Indicator Matrix
(6 answers)
Closed 6 years ago.
I want to do something like the following:
Y = [1; 2; 3];
X = repmat(1:10, 3, 1);
for i=1:3
X(i,:) = X(i,:) == Y(i);
end
So I end up with
X =
1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
Is there a way to do this without looping?

If you start from 1:10 vector, using bsxfun:
Y = [1; 2; 3];
X = bsxfun(#eq, Y, 1:10);
Otherwise with repmat:
Y = [1; 2; 3];
X = repmat(1:10, 3, 1);
X = repmat(Y, 1, size(X,2)) == X;
(Or ones as suggested by leo.)

One solution would be
Y = [1; 2; 3];
X = repmat(1:10, 3, 1);
Z = X == (Y * ones(1, 10)) ;
But I am not sure this is faster. It does not use a loop, though :)
EDIT : you could use a repmat instead of the * ones(1, 10)

Related

How to generate a customized checker board matrix as fast as possible?

I need a function that creates a checker board matrix with M rows and N columns of P*Q rectangles. I modified the third solution from here to get that:
function [I] = mycheckerboard(M, N, P, Q)
nr = M*P;
nc = N*Q;
i = floor(mod((0:(nc-1))/Q, 2));
j = floor(mod((0:(nr-1))/P, 2))';
r = repmat(i, [nr 1]);
c = repmat(j, [1 nc]);
I = xor(r, c);
it works with no problem:
I=mycheckerboard(2, 3, 4, 3)
I =
0 0 0 1 1 1 0 0 0
0 0 0 1 1 1 0 0 0
0 0 0 1 1 1 0 0 0
0 0 0 1 1 1 0 0 0
1 1 1 0 0 0 1 1 1
1 1 1 0 0 0 1 1 1
1 1 1 0 0 0 1 1 1
1 1 1 0 0 0 1 1 1
But it's not fast enough since there are lots of calls of this function in a single run. Is there a faster way to get the result? How can I remove floating point divisions and/or calls of the floor function?
Your code is fairly fast for small matrices, but becomes less so as the dimensions get larger. Here's a one-liner using bsxfun and imresize (requires Image Processing toolbox that most have):
m = 2;
n = 3;
p = 4;
q = 3;
I = imresize(bsxfun(#xor, mod(1:m, 2).', mod(1:n, 2)), [p*m q*n], 'nearest')
Or, inspired by #AndrasDeak's use of kron, this is faster with R2015b:
I = kron(bsxfun(#xor, mod(1:m, 2).', mod(1:n, 2)), ones(p, q))
For a small bit more speed, the underlying code for kron can be simplified by taking advantage of the structure of the problem:
A = bsxfun(#xor, mod(1:m, 2).', mod(1:n, 2));
A = permute(A, [3 1 4 2]);
B = ones(q, 1, p);
I = reshape(bsxfun(#times, A, B), [m*n p*q]);
or as one (long) line:
I = reshape(bsxfun(#times, permute(bsxfun(#xor, mod(1:m, 2).', mod(1:n, 2)), [3 1 4 2]), ones(q, 1, p)), [m*n p*q]);
I suggest first creating a binary matrix for the checkerboard's fields, then using the built-in kron to blow it up to the necessary size:
M = 2;
N = 3;
P = 4;
Q = 3;
[iM,iN] = meshgrid(1:M,1:N);
A = zeros(M,N);
A(mod(iM.'+iN.',2)==1) = 1;
board = kron(A,ones(P,Q))

Assigning indexes in MatLab using sub2ind

I have 3 data sets, two with coordinates and one with data with the length of n with a loop I would assign the data in this way
MAT = zeros(m, n);
for i = 1:n
MAT(Z(i), X(i)) = MAT(Z(i), X(i)) + DATA(i);
end
I want to do it without a loop since what I am trying to do is something like:
MAT = zeros(m, n);
mn = size(MAT);
MAT(sub2ind(mn, Z, X)) = MAT(sub2ind(mn, Z, X)) + DATA;
Anyone has an idea how to make it properly and efficiently?
Cheers.
You should use the function accumarray, for example:
Let:
>> Z = [ 1 2 4 3 1];
>> X = [3 2 1 4 3];
>> D = [5 6 7 8 -10];
>> m = 4;n = 4;
Then we have:
>> MAT = accumarray([Z(:),X(:)],D(:),[m,n])
MAT =
0 0 -5 0
0 6 0 0
0 0 0 8
7 0 0 0

Generate boolean matrix by predicate on row and column

I have the following vector:
y = [1; 3; 2; 3; 1];
All its values are between 1 and n (in this case, 3) and denote different options.
I want to create a matrix of size size(y, 1) x n whose rows correpond to y values:
1 0 0 % because y(1) = 1
0 0 1 % because y(2) = 3
0 1 0 % because y(3) = 2
0 0 1
1 0 0
One way to do this would be
Y = zeros(size(y, 1), num_labels);
for i = 1:m
Y(i, y(i)) = 1;
end
Is there a better way to do this, maybe in a single expression?
Basically, what I need is to generate a matrix with boolean predicate (i, j) => j == y(i).
You can try this if a is a column vector
a = [1; 3; 2; 3; 1];
bsxfun(#eq, a, [1:max(a)])
and this if it is a row vector
a = [1; 3; 2; 3; 1]';
bsxfun(#eq, a', [1:max(a)])
If you have access to Statistics Toolbox, the command dummyvar does exactly what you need.
>> y = [1; 3; 2; 3; 1];
>> dummyvar(y)
ans =
1 0 0
0 0 1
0 1 0
0 0 1
1 0 0
You can use sub2ind after initializing the matrix as follows:
y = [1; 3; 2; 3; 1];
m = length(y);
n = max(y);
Y = zeros(m, n);
Y(sub2ind(size(Y), 1:m, y')) = 1
Y =
1 0 0
0 0 1
0 1 0
0 0 1
1 0 0
The trick here is to know that the corresponding rows of y go from 1 to m one by one.
accumarray([(1:length(y)).' y], 1)
As suggested by Dmitri Bouianov on Coursera discussion forum, this also works:
Y = eye(num_labels)(y, :);
This solution uses elements of y to as indices to select rows from an identity matrix.
In Octave (at least as of 3.6.3, not sure when it was introduced), you can use broadcasting to do this extremely easily. It works like this:
Y = y==1:3
(if y is a row matrix, you need to transpose it first - if you want to have Y transposed instead, use y==(1:3)')

Converting a matrix in MATLAB

Let's say I've got a vector a = [1 2 4]. I want it converted into a vector which looks like this b = [1 2 0 4], i.e. each number is placed into a correct position and since 3 is not included into the vector a, it is replaced by 0 in vector b. This can be done the following way:
a = [1 2 4]
b = zeros(1, size(a, 2));
b(1, a) = a;
I can't figure out a way to do the same for a matrix. For example,
c = [1 4 2 0; 3 1 0 0; 4 0 0 0; 1 3 4 0];
I need to convert into a matrix that looks like this:
d = [1 2 0 4; 1 0 3 0; 0 0 0 4; 1 0 3 4];
Any tips? How can this be done? How can I do this without using loops?
Here's a vectorized solution:
a = [1 4 2 0; 3 1 0 0; 4 0 0 0; 1 3 4 0];
b = zeros(size(a,1),max(a(:)));
[rowIdx,~] = find(a);
vals = a(a>0);
b( sub2ind(size(b),rowIdx,vals) ) = vals;
Does this work? (Edited: fixed mistake.)
[m,n] = size(c)
d = zeros(m,n)
for i=1:m
d(i,c(i,c(i,:)>0)) = c(i,c(i,:)>0)
end

How can I generate the following matrix in MATLAB?

I want to generate a matrix that is "stairsteppy" from a vector.
Example input vector: [8 12 17]
Example output matrix:
[1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1]
Is there an easier (or built-in) way to do this than the following?:
function M = stairstep(v)
M = zeros(length(v),max(v));
v2 = [0 v];
for i = 1:length(v)
M(i,(v2(i)+1):v2(i+1)) = 1;
end
You can do this via indexing.
A = eye(3);
B = A(:,[zeros(1,8)+1, zeros(1,4)+2, zeros(1,5)+3])
Here's a solution without explicit loops:
function M = stairstep(v)
L = length(v); % M will be
V = max(v); % an L x V matrix
M = zeros(L, V);
% create indices to set to one
idx = zeros(1, V);
idx(v + 1) = 1;
idx = cumsum(idx) + 1;
idx = sub2ind(size(M), idx(1:V), 1:V);
% update the output matrix
M(idx) = 1;
EDIT: fixed bug :p
There's no built-in function I know of to do this, but here's one vectorized solution:
v = [8 12 17];
N = numel(v);
M = zeros(N,max(v));
M([0 v(1:N-1)]*N+(1:N)) = 1;
M(v(1:N-1)*N+(1:N-1)) = -1;
M = cumsum(M,2);
EDIT: I like the idea that Jonas had to use BLKDIAG. I couldn't help playing with the idea a bit until I shortened it further (using MAT2CELL instead of ARRAYFUN):
C = mat2cell(ones(1,max(v)),1,diff([0 v]));
M = blkdiag(C{:});
A very short version of a vectorized solution
function out = stairstep(v)
% create lists of ones
oneCell = arrayfun(#(x)ones(1,x),diff([0,v]),'UniformOutput',false);
% create output
out = blkdiag(oneCell{:});
You can use ones to define the places where you have 1's:
http://www.mathworks.com/help/techdoc/ref/ones.html