26

Possible Duplicate:
How can I divide each row of a matrix by a fixed row?

I'm looking for an elegant way to subtract the same vector from each row of a matrix. Here is a non elegant way of doing it.

a = [1 2 3];
b = rand(7,3);
c(:,1) = b(:,1) - a(1);
c(:,2) = b(:,2) - a(2);
c(:,3) = b(:,3) - a(3);

Also, the elegant way can't be slower than this method.

I've tried

c = b-repmat(a,size(b,1),1); 

and it seems slower.

EDIT: The winner is this method.

c(:,1) = b(:,1) - a(1);
c(:,2) = b(:,2) - a(2);
c(:,3) = b(:,3) - a(3);

EDIT: More methods, and tic toc results:

n = 1e6;
m = 3;
iter = 100;
a = rand(1,m);
b = rand(n,m);

tic
c = zeros(size(b));
for i = 1:iter
    c(:,1) = b(:,1) - a(1);
    c(:,2) = b(:,2) - a(2);
    c(:,3) = b(:,3) - a(3);
end
toc

tic
c = zeros(size(b));
for i = 1:iter
    c(:,1) = b(:,1) - a(1);
    c(:,2) = b(:,2) - a(2);
    c(:,3) = b(:,3) - a(3);
end
toc

tic
c = zeros(size(b));
for i = 1:iter
    for j = 1:3
        c(:,j) = b(:,j) - a(j);
    end
end
toc

tic
for i = 1:iter
    c = b-repmat(a,size(b,1),1);
end
toc

tic
for i = 1:iter
    c = bsxfun(@minus,b,a);
end
toc

tic
c = zeros(size(b));
for i = 1:iter
    for j = 1:size(b,1)
        c(j,:) = b(j,:) - a;
    end
end
toc

results

Elapsed time is 0.622730 seconds.
Elapsed time is 0.627321 seconds.
Elapsed time is 0.713384 seconds.
Elapsed time is 2.621642 seconds.
Elapsed time is 1.323490 seconds.
Elapsed time is 17.269901 seconds.
Community
  • 1
  • 1
Miebster
  • 2,365
  • 4
  • 21
  • 27
  • 2
    This is basically a duplicate of these other questions (same idea, different arithmetic operation): [How do I divide matrix elements by column sums in MATLAB?](http://stackoverflow.com/questions/1773099/how-do-i-divide-matrix-elements-by-column-sums-in-matlab), [How can I divide each row of a matrix by a fixed row?](http://stackoverflow.com/questions/4723824/how-can-i-divide-each-row-of-a-matrix-by-a-fixed-row) – gnovice Mar 17 '11 at 17:35
  • 4
    For those too lazy to follow the links: `c=bsxfun(@minus,b,a);` – Jonas Mar 17 '11 at 17:42
  • bsxfun seems slower, see edit – Miebster Mar 17 '11 at 17:55
  • 1
    For your timings: take those c and b initializations out of the loop, and please try to vary the size (7, 3) with more interesting values, like something in the range 1e2... 1e4. And if you really have a real use case, care to describe it! Thanks – eat Mar 17 '11 at 18:24
  • I found that since 2016, the following method would work (matrix-array operation). `c = b .- a` Not sure regarding the timing, but this should be reasonably fast and straightforward. – Olga Gnatenko Feb 09 '19 at 22:19
  • @OlgaGnatenko Can you share a link for this functionality? This doesn't appear to be supported in Matlab 2019b. – osprey Mar 02 '20 at 18:38

2 Answers2

6

Here is my contribution:

c = b - ones(size(b))*diag(a)

Now speed testing it:

tic
for i = 1:10000
    c = zeros(size(b));
    b = rand(7,3);
    c = b - ones(size(b))*diag(a);
end
toc

The result:

Elapsed time is 0.099979 seconds.

Not quite as fast, but it is clean.

MudPhud
  • 123
  • 1
  • 6
1

There are only three obvious answers, and you gave two of them in your question.

The third is by row,

c(1,:) = b(1,:) - a; %...

but I'd expect that to be slower than your by-column processing for large matrixes since it accesses elements out of memory order.

If you turn your by-column processing into a for loop in a *.m file or subfunction, is it still faster than the repmat version?

One other thing you might test for speed: Try preallocating c.

c = zeros(size(b));
c(:,1) = b(:,1) - a(1); %...
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • The fourth is by using `bsxfun`, as explained in the duplicate answers as well as my comment. – Jonas Mar 17 '11 at 17:44