For those super experts out there, I was wondering if you see a quick way to convert the following "for" loop into a one-line vector calculation that is more efficient.
%Define:
%A size (n,1)
%B size (n,m)
%C size (n,1)
B = [2 200; 3 300; 4 400];
C = [1;2;1];
for j=1:n
A(j) = B( j, C(j) );
end
So to be clear, is there any alternative way to express A, as a function of B and C, without having to write a loop?
Yes, there is:
A = B(sub2ind([n,m], (1:n).', C));
It depends on functions A, B, and C, but this might work:
j = 1:n;
A = B(j, C(j));
Related
I have a series of arrays of equal length, and want to make a matrix for each data point of these, and perform some sort of operation such a multiplying the matrices.
a=ones(1,10);
b=3*ones(1,10);
c=zeros(1,10);
for i=1:10
A(i)=[a(i) a(i);
b(i) b(i)];
B(i)=[c(i) c(i)];
C(i)=B(i)*A(i);
end
Is this possible without using cells?
A = zeros(2,2,length(a));
B = zeros(length(a),:);
C = zeros(size(B));
for i=1:10
A(:,:,i)=[a(i) a(i);
b(i) b(i)];
B(i,:)=[c(i) c(i)];
C(i,:)=B(i,:)*A(:,:,i);
end
Note you can make A and B without loops:
aa = permute(A, [3,2,1]);
bb = permute(B, [3,2,1]);
A = [aa,aa;bb,bb];
B = [c.', c.'];
I have been looking for a way to use boxplot for different length vectors. thanx for stackoverflow helpers, they give this solution:
A = randn(10, 1); B = randn(12, 1); C = randn(4, 1);
g = [repmat(1, [10, 1]) ; repmat(2, [12, 1]); repmat(3, [4, 1])];
figure; boxplot([A; B; C], g);
unfortunately, my data contains over 100 vectors with different lengths, I wonder if it can be done without repeating the repmat for over 100 times.
As long as your vectors have different lengths, store it in a cell array.
There are plenty was of doing it, here are 3 examples
1) "Naive" for loop
g = [];
vars_cell = {A, B, C, ....};
for it = 1 : length(vars_cell)
g = [g; repmat(it,size(vars_cell{it}))];
end
This way of doing it works but is very slow with big quantites of vectors or big vectors! It comes from the fact that you are re-defining g at each iteration, changing its size each time.
2) Not-naive for loop
vars_cell = {A, B, C, ....};
%find the sum of the length of all the vectors
total_l = sum(cellfun(#(x) length(x),vars_cell));
g = zeros(total_l,1);
acc = 1;
for it = 1 : length(vars_cell)
l = size(vars_cell{it});
g(acc:acc+l-1) = repmat(it,l);
acc = acc+l;
end
This method will be much faster than the 1st one because it defines g only once
3) The "one-liner"
vars_cell = {A, B, C, ....};
g = cell2mat(arrayfun(#(it) repmat(it, size(vars_cell{it})),1:length(vars_cell),'UniformOutput',0)');
This is qute equivalent to the 2nd solution, but if you like one line answers this is what you are looking for!
For those super experts out there, I was wondering if you see a quick way to convert the following "for" loop into a one-line vector calculation that is more efficient.
%Define:
%A size (n,1)
%B size (n,m)
%C size (n,1)
B = [2 200; 3 300; 4 400];
C = [1;2;1];
for j=1:n
A(j) = B( j, C(j) );
end
So to be clear, is there any alternative way to express A, as a function of B and C, without having to write a loop?
Yes, there is:
A = B(sub2ind([n,m], (1:n).', C));
It depends on functions A, B, and C, but this might work:
j = 1:n;
A = B(j, C(j));
I have the following for loop in my Matlab code I'd like to get rid of:
for i=1:size(thePolygon,3)
activeValues(:,i) = sum(normalVectors.*thePolygon(:,:,i),2);
checkValues(:,i) = sign(activeValues(:,i)-sum(normalVectors.*thePolygon3(:,:,i),2));
end
I tried replacing i with 1:size(thePolygon,3), but the dimensions don't line up for the element-by-element multiplication, and I'm not sure what else to try. Thanks in advance for any tips.
It's difficult to test without example data but:
activeValues = squeeze(sum(bsxfun(#times, normalVectors, thePolygon), 2))
OK so first some test data:
a = rand(3,3,3);
b = rand(3,3);
now we test yours
for i=1:size(a,3)
c(:,i) = sum(b.*a(:,:,i),2);
end
on my run I got:
c =
0.9773 1.0608 0.3673
0.6670 0.1597 0.7296
0.8372 1.1418 0.9828
and now mine:
squeeze(sum(bsxfun(#times, b, a), 2))
I get
ans =
0.9773 1.0608 0.3673
0.6670 0.1597 0.7296
0.8372 1.1418 0.9828
so I am assuming mine is correct.
Explanation:
bsxfun(#times, b, a) does broadcasting, it expands b along it's singleton dimension (in this case dim 3) to match the size of a and then applies the function (#times is just .*) element by element to the expanded b and a. This is identical (but better practice and faster) to going repmat(b, [1 1 size(a,3)]).*a.
Then we sum this 3D matrix column wize like you have, i.e. sum(x, 2) which returns a 1x3x3 result. But I want a 3x3 result so to get rid of the singelton dimension (i.e. dim 1 as it equals 1) I used squeeze
It should be trivial for you to now vectorize your second line in the same way.
BUT
tic; for k = 1:10000 c = squeeze(sum(bsxfun(#times, b, a), 2)); end; toc
Elapsed time is 0.394828 seconds.
tic; c = zeros(3,3); for k = 1:10000 for i=1:size(a,3)
c(:,i) = sum(b.*a(:,:,i),2);
end; end; toc
Elapsed time is 0.113199 seconds.
THE NON-VECTORIZED CODE IS FASTER IN MATLASB 2012b!!!!!!!
I'm fairly new to MATLAB. Normal matrix multiplication of a M x K matrix by an K x N matrix -- C = A * B -- has c_ij = sum(a_ik * b_kj, k = 1:K). What if I want this to be instead c_ij = sum(op(a_ik, b_kj), k = 1:K) for some simple binary operation op? Is there any nice way to vectorize this in MATLAB (or maybe even a built-in function)?
EDIT: This is currently the best I can do.
% A is M x K, B is K x N
% op is min
C = zeros(M, N);
for i = 1:M:
C(i, :) = sum(bsxfun(#min, A(i, :)', B));
end
Listed in this post is a vectorized approach that persists with bsxfun by using permute to create singleton dimensions as needed by bsxfun to let the singleton-expansion do its work and thus essentially replacing the loop in the original post. Please be reminded that bsxfun is a memory hungry implementation, so expect speedup with it only until it is stretched too far. Here's the final solution code -
op = #min; %// Edit this with your own function/ operation
C = sum(bsxfun(op, permute(A,[1 3 2]),permute(B,[3 2 1])),3)
NB - The above solution was inspired by Removing four nested loops in Matlab.
if the operator can operate element-by-element (like .*):
if(size(A,2)~=size(B,1))
error(blah, blah, blah...);
end
C = zeros(size(A,1),size(B,2));
for i = 1:size(A,1)
for j = 1:size(B,2)
C(i,j) = sum(binaryOp(A(i,:)',B(:,j)));
end
end
You can always write the loops yourself:
A = rand(2,3);
B = rand(3,4);
op = #times; %# use your own function here
C = zeros(size(A,1),size(B,2));
for i=1:size(A,1)
for j=1:size(B,2)
for k=1:size(A,2)
C(i,j) = C(i,j) + op(A(i,k),B(k,j));
end
end
end
isequal(C,A*B)
Depending on your specific needs, you may be able to use bsxfun in 3D to trick the binary operator. See this answer for more infos: https://stackoverflow.com/a/23808285/1121352
Another alternative would be to use cellfun with a custom function:
http://matlabgeeks.com/tips-tutorials/computation-using-cellfun/