For example:
a = [1 2 3; 4 5 6; 7 8 9];
b = [2 4]; %//Indices I got
How can I set to zero every element of a not indexed in b in order to obtain:
0 2 0
4 0 0
0 0 0
I tried for loop:
for i = 1:numel(a)
if i ~= b
a(i) = 0;
end
end
but the matrix I cope with is really large and it takes ridiculously long time to finish running.
Is there any smart way to do it? Thank you.
Try this:
a = [1 2 3; 4 5 6; 7 8 9];
b = [2 4];
a(setdiff(1:length(a(:)),b)) = 0;
UPDATE
As proposed by #Daniel, for large matrices is better to use
a(setdiff(1:numel(a),b)) = 0;
An alternative to Anton's direct solution is one based on copying:
a = [1 2 3; 4 5 6; 7 8 9];
b = [2 4];
atmp = a(b);
a = zeros(size(a));
a(b) = atmp; %// copy needed elements
I guess efficiency of the two approaches boils down to allocation vs setdiff. Also, if your resulting matrix has many zeroes, you should perhaps consider using a sparse matrix.
Related
Suppose I have two matrices, A and B.
A = [2 8 4; 7 3 9];
B = [2 1 6; 1 3 9];
I'd like to get a matrix C that is as follows:
C = [2 0 0; 0 3 9];
C is a matrix that retains the common elements of A and B but changes the rest of the elements to zero. I could use a for loop and iterate over every element in both A and B but is there a more efficient method to obtain the results?
Assuming both matrices have same dimensions.
A = [2 8 4; 7 3 9];
B = [2 1 6; 1 3 9];
C = zeros(size(A));
C(A == B) = A(A == B);
C =
2 0 0
0 3 9
Another possibility is to use
C = A.*(B==A);
Given this vector
a = [1 2 3 4]
I want to create a matrix like this
b = [1 0 0 0;
2 1 0 0;
3 2 1 0;
4 3 2 1;
0 4 3 2;
0 0 4 3;
0 0 0 4]
in a vectorized way not using loops.
Hint: use conv2 (hover mouse to see code):
a = [1 2 3 4];
b = conv2(a(:), eye(numel(a)));
Or, in a similar mood, you can use convmtx (from the Signal Processing Toolbox):
a = [1 2 3 4];
b = convmtx(a(:), numel(a));
One way to do it:
a = [1 2 3 4]
n = numel(a);
%// create circulant matrix from input vector
b = gallery('circul',[a zeros(1,n-1)]).' %'
%// crop the result
c = b(:,1:n)
Another way:
b = union( tril(toeplitz(a)), triu(toeplitz(fliplr(a))),'rows','stable')
or its slightly variation
b = union( toeplitz(a,a.*0),toeplitz(fliplr(a),a.*0).','rows','stable')
and probably even faster:
b = [ toeplitz(a,a.*0) ; toeplitz(fliplr(a),a.*0).' ]
b(numel(a),:) = []
With bsxfun -
na = numel(a)
b = zeros(2*na-1,na)
b(bsxfun(#plus,[1:na]',[0:na-1]*2*na)) = repmat(a(:),1,na)
If you are looking for a faster pre-allocation, you can do -
b(2*na-1,na) = 0;.
Another bsxfun -
a=[1 2 3 4];
m=numel(a);
b=[a,zeros(1,m-1)].';
Q=bsxfun(#circshift, b, [0:m-1])
The following codes runs in Matlab:
a = [1 2 3 4]
b = [ 1 2 3; 1 2 3; 1 2 3]
a(b)
The result of a(b) is a matrix:
[ 1 2 3; 1 2 3; 1 2 3]
Can anyone explain what happened here? Why a vector can be indexed by a matrix, how to interpret the result?
That's a very standard MATLAB operation that you're doing. When you have a vector or a matrix, you can provide another vector or matrix in order to access specific values. Accessing values in MATLAB is not just limited to single indices (i.e. A(1), A(2) and so on).
For example, what you have there is a vector of a = [1 2 3 4]. When you try to use b to access the vector, what you are essentially doing is a lookup. The output is basically the same size as b, and what you are doing is creating a matrix where there are 3 rows, and each element accesses the first, second and third element. Not only can you do this for a vector, but you can do this for a matrix as well.
Bear in mind that when you're doing this for a matrix, you access the elements in column major format. For example, supposing we had this matrix:
A = [1 2
3 4
5 6
7 8]
A(1) would be 1, A(2) would be 3, A(3) would be 5 and so on. You would start with the first column, and increasing indices will traverse down the first column. Once you hit the 5th index, it skips over to the next column. So A(5) would be 2, A(6) would be 4 and so on.
Here are some examples to further your understanding. Let's define a matrix A such that:
A = [5 1 3
7 8 0
4 6 2]
Here is some MATLAB code to strengthen your understanding for this kind of indexing:
A = [5 1 3; 7 8 0; 4 6 2]; % 3 x 3 matrix
B = [1 2 3 4];
C = A(B); % C should give [5 7 4 1]
D = [5 6 7; 1 2 3; 4 5 6];
E = A(D); % E should give [8 6 3; 5 7 4; 1 8 6]
F = [9 8; 7 6; 1 2];
G = A(F); % G should give [2 0; 3 6; 5 7]
As such, the output when you access elements this way is whatever the size of the vector or matrix that you specify as the argument.
In order to be complete, let's do this for a vector:
V = [-1 9 7 3 0 5]; % A 6 x 1 vector
B = [1 2 3 4];
C = V(B); % C should give [-1 9 7 3]
D = [1 3 5 2];
E = V(D); % E should give [-1 7 0 9]
F = [1 2; 4 5; 6 3];
G = V(F); % G should give [-1 9; 3 0; 5 7]
NB: You have to make sure that you are not providing indexes that would make the accessing out of bounds. For example if you tried to specify the index of 5 in your example, it would give you an error. Also, if you tried anything bigger than 9 in my example, it would also give you an error. There are 9 elements in that 3 x 3 matrix, so specifying a column major index of anything bigger than 9 will give you an out of bounds error.
Notice that the return value of a(b) is the same size as b.
a(b) simply takes each element of b, call it b(i,j), as an index and returns the outputs a(b(i,j)) as a matrix the same size as b. You should play around with other examples to get a more intuitive feel for this:
b = [4 4 4; 4 4 4];
a(b) % Will return [4 4 4; 4 4 4]
c = [5; 5];
a(c) % Will error as 5 is out of a's index range
I have two vectors and I want the numbers to follow one each other. By this I mean:
a = [5 6 4 2 1];
b = [4 2 1 3];
Vector b can be smaller than a by one or can be the same length
I want to get
c = [5 4 6 2 4 1 2 3 1];
I tried to use reshape but gave up. So I just implemented the loop.
But is there a better way to solve this problem?
You can use sliced assignment:
% prepare c
c = zeros(1, length(a) + length(b));
% assign a
c(1:2:length(a)*2) = a;
% assign b
c((1:2:length(b)*2)+1) = b;
Note: This solution does not verify if either a or b are too short. Too long a or b will give an error though.
AFAIK reshape is only usable to change the dimensions of a single array/matrix.
Why not use simple concatenation and reordering?
>> a = [5 6 4 2 1];
>> b = [4 2 1 3];
>> c = [a b]; % initialize by concatenation
>> c([1:2:end 2:2:end]) = c % reorder by sliced re-assignment
c =
5 4 6 2 4 1 2 3 1
I have a matrix as shown in below:
A=[2 4;1 3;8 6;5 1;4 9]
now i need to extract the matrix A into 2 parts:
newpoint=[2 4];
rest=[1 3;8 6;5 1;4 9];
then apply loop again to extract the second column as new point :
newpoint=[1 3];
rest=[2 4;8 6;5 1;4 9];
Applying loop again to take third column number as new point :
newpoint=[8 6];
rest=[2 4;1 3;5 1;4 9];
Take the number in row sequence until the last row . Can someone be kind enough to help.Thanks~
Apart from HebeleHododo's answer, if you have big matrices maybe you can try this:
A = [2 4; 1 3; 8 6; 5 1; 4 9];
B = zeros(size(A,1)-1,size(A,2));
for idx = 1:size(A, 1)
newpoint = A(idx, :);
B(1:idx-1,:) = A(1:idx-1,:);
B(idx:end,:) = A(idx+1:end,:);
% do stuff
end
It doesn't get rid of the for loop, but the temporary B matrix is pre-allocated and the copy between A and B is clear, which makes it quicker.
For A = rand(100000,2); HebeleHododo's method takes ~123 seconds in my computer
and the one above takes ~85 seconds.
Edit: Just for reference, the timing is done using Intel Core i5-3450 CPU # 3.10GHz and Matlab R2011b
You said you want to extract columns, but gave examples with rows. I am going ahead and assuming you meant rows.
You can do it with a for loop.
A = [2 4; 1 3; 8 6; 5 1; 4 9];
for idx = 1:size(A, 1)
newpoint = A(idx, :);
rest = A; % Copy A to rest
rest(idx, :) = []; % Remove newpoint line
% do stuff
end
Results of first two iterations:
newpoint =
2 4
rest =
1 3
8 6
5 1
4 9
newpoint =
1 3
rest =
2 4
8 6
5 1
4 9
This is not a good method if your A matrix is big.
Edit: In fact, do not use this method. George Aprilis timed it and found 123 seconds for a 100000x2 matrix. I guess my computer is much slower. It took 216 seconds. I repeat, do not use this.