MATLAB: Subtracting matrix subsets by specific rows
matlab, matrix, vectorization
Solution
a slightly shorter and vectorized way will be (if `a` is your matrix) :
b=a-kron(a(1:3:end,:),ones(3,1));
let's test:
a=[1 3 5
2 3 6
1 1 1
3 5 4
5 5 5
8 8 0]
a-kron(a(1:3:end,:),ones(3,1))
ans =
0 0 0
1 0 1
0 -2 -4
0 0 0
2 0 1
5 3 -4
Edit
Here's a bsxfun solution (less elegant, but hopefully faster):
a-reshape(bsxfun(@times,ones(1,3),permute(a(1:3:end,:),[2 3 1])),3,[])'
ans =
0 0 0
1 0 1
0 -2 -4
0 0 0
2 0 1
5 3 -4
Edit 2
Ok, this got me curios, as I know bsxfun starts to be less efficient for bigger array sizes. So I tried to check using `timeit` my two solutions (because they are one liners it's easy). And here it is:
range=3*round(logspace(1,6,200));
for n=1:numel(range)
a=rand(range(n),3);
f=@()a-kron(a(1:3:end,:),ones(3,1));
g=@() a-reshape(bsxfun(@times,ones(1,3),permute(a(1:3:end,:),[2 3 1])),3,[])';
t1(n)=timeit(f);
t2(n)=timeit(g);
end
semilogx(range,t1./t2);
So I didn't test for the for loop and Divkar's bsxfun, but you can see that for arrays smaller than 3e4 kron is better than bsxfun, and this changes at larger arrays (ratio of <1 means kron took less time given the size of the array). This was done at Matlab 2012a win7 (i5 machine)
Problem
Here is an example of a subset of the matrix I would like to use: 1 3 5 2 3 6 1 1 1 3 5 4 5 5 5 8 8 0 This matrix is in fact 3000 x 3. For the first 3 rows, I wish to subtract each of these rows with the first row of these three. For the second 3 rows, I wish to subtract each of these rows with the first of these three, and so on. As such, the output matrix will look like: 0 0 0 1 0 1 0 -2 -4 0 0 0 2 0 1 5 3 -4 What code in MATLAB will do this for me?