我有一个网络的邻接矩阵,想要计算Adamic-Adar得分。它按以下方式定义:对于每对边x和y,让z为它们的一个共同邻居,并且| z |是邻居的程度。
现在,分数被定义为所有常见邻居z的总和:
例如参见this paper, page 3。
我为MATLAB编写了一个小算法,但它使用了两个for循环。我确信它可以更快,但我不知道如何。你能说明一下如何加快这个速度吗?
% the entries of nn will always be 0 or 1, and the diagonal will always be 0
nn=[0 0 0 0 1 0; ...
0 0 0 1 1 0; ...
0 0 0 0 1 0; ...
0 1 0 0 0 1; ...
1 1 1 0 0 0; ...
0 0 0 1 0 0];
deg=sum(nn>0);
AAScore=zeros(size(nn));
for ii=1:length(nn)-1
for jj=ii+1:length(nn)
NBs=nn(ii,:).*nn(jj,:);
B=NBs.*deg;
C=B(B>1);
AAScore(ii,jj)=sum(1./log(C));
end
end
AAScore
我很感激任何建议,谢谢!
比较运行时
我的nn有~2%的条目,所以它可以近似为:
kk=1500;
nn=(rand(kk)>0.98).*(1-eye(kk));
答案 0 :(得分:1)
首先,获取将要设置的输出数组中的索引,即非零。查看代码,我们可以注意到,我们基本上从输入矩阵AND-ing
开始对每一行执行nn
行1s
。鉴于我们正在处理0s
和triu(...,1)
,这基本上转化为执行矩阵乘法。因此,矩阵乘法结果中的非零将指示需要计算的sqaured矩阵输出数组中的位置。这应该是有效的,因为我们将迭代较小的元素。最重要的是,由于我们得到一个上三角矩阵输出,这应该通过使用[R,C] = find(triu(nn*nn.'>0,1));
vals = sum(1./log(bsxfun(@times,nn(R,:).*nn(C,:),deg)),2);
out=zeros(size(nn));
out(sub2ind(size(out),R,C)) = vals;
的掩码进一步减少计算。
遵循这些想法,这是一个实现 -
nn
对于输入矩阵bsxfun(@times,nn(R,:).*nn(C,:),deg)
less-sparsey 且非常庞大的情况,您会感到计算R,C
的瓶颈。因此,对于这种情况,您可以直接使用这些[R,C] = find(triu(nn*nn.',1));
out=zeros(size(nn));
for ii =1:numel(R)
out(R(ii),C(ii)) = sum(1./log(nn(R(ii),:).*nn(C(ii),:).*deg));
end
索引来执行计算,以更新输出数组中的相应选择位置。
因此,另一种实现方式是 -
R,C
可以在上述两种方法之间建立中间关系,方法是从nn(R,:)
索引开始,然后选择nn(C,:)
之外的行和来自PHP >= 7.0 required yours is 5.6.15
的各行。并且以较低的复杂度迭代地使用这些块的向量化实现。设置块大小可能很棘手,因为它在很大程度上取决于系统资源,涉及的输入数组大小以及它的稀疏性。