Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vectorize call to function of two vectors (treat matrix as array of vector)

I wish to compute the cumulative cosine distance between sets of vectors.
The natural representation of a set of vectors is a matrix...but how do I vectorize the following?

function d = cosdist(P1,P2)
    ds = zeros(size(P1,2),1);
    for k=1:size(P1,2)
      %#used transpose() to avoid SO formatting on '
        ds(k)=transpose(P1(:,k))*P2(:,k)/(norm(P1(:,k))*norm(P2(:,k)));
    end
    d = prod(ds);
end

I can of course write

fz = @(v1,v2) transpose(v1)*v2/(norm(v1)*norm(v2));
ds = cellfun(fz,P1,P2);

...so long as I recast my matrices as cell arrays of vectors. Is there a better / entirely numeric way?
Also, will cellfun, arrayfun, etc. take advantage of vector instructions and/or multithreading?

Note probably superfluous in present company but for column vectors v1'*v2 == dot(v1,v2) and is significantly faster in Matlab.

like image 646
reve_etrange Avatar asked Feb 25 '23 05:02

reve_etrange


2 Answers

Since P1 and P2 are of the same size, you can do element-wise operations here. v1'*v equals sum(v1.*v2), by the way.

d = prod(sum(P1.*P2,1)./sqrt(sum(P1.^2,1) .* sum(P2.^2,1)));
like image 172
Jonas Avatar answered Apr 30 '23 22:04

Jonas


@Jonas had the right idea, but the normalizing denominator might be incorrect. Try this instead:

%# matrix of column vectors
P1 = rand(5,8);
P2 = rand(5,8);

d = prod( sum(P1.*P2,1) ./ sqrt(sum(P1.^2,1).*sum(P2.^2,1)) );

You can compare this against the results returned by PDIST2 function:

%# PDIST2 returns one minus cosine distance between all pairs of vectors
d2 = prod( 1-diag(pdist2(P1',P2','cosine')) );
like image 26
Amro Avatar answered Apr 30 '23 21:04

Amro