【问题标题】:MATLAB: Fast calculation of Adamic-Adar ScoreMATLAB:快速计算 Adamic-Adar 分数
【发布时间】:2016-07-31 17:10:10
【问题描述】:

我有一个网络的邻接矩阵,并且想要计算 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));
  • 我的双倍时间:37.404445 秒。
  • Divakar 的第一个解决方案:58.455826 秒。
  • Divakar 的更新解决方案:22.333510 秒。

【问题讨论】:

  • @Divakar,是的,它总是只有 0 和 1。 (我编辑问题)
  • nn 的典型大小是多少?
  • nn 的典型尺寸在 5000x5000 或 6000x6000 之间。

标签: algorithm performance matlab network-programming vectorization


【解决方案1】:

首先,获取输出数组中要设置的索引,即非零。查看代码,我们可以注意到我们基本上对输入矩阵nn 中的每一行执行AND-ing 对每一行。鉴于我们正在处理1s0s,这基本上转化为执行矩阵乘法。因此,矩阵乘法结果中的非零值将指示平方矩阵输出数组中需要计算的位置。这应该是有效的,因为我们将迭代较少的元素。最重要的是,由于我们得到了一个上三角矩阵输出,这应该通过使用带有triu(...,1) 的掩码来进一步减少计算。

按照这些想法,这是一个实现 -

[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 less-sparsey 并且非常庞大的情况,您会感觉到计算bsxfun(@times,nn(R,:).*nn(C,:),deg) 的瓶颈。因此,对于这种情况,您可以直接使用那些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,:) 中选择行块,并使用向量化实现跨这些块以较低的复杂性迭代。设置块大小可能很棘手,因为它在很大程度上取决于系统资源、所涉及的输入数组大小以及它的稀疏性

【讨论】:

  • 非常感谢您提供了这个更紧凑、更好的版本,没有 fors。我会尽量记住你的技巧(尤其是 bsxfun)。我很惊讶,但是对于大约 500x500 的矩阵,该版本似乎比蛮力双倍更慢。我不明白,将尝试使用 Profiler 查看会发生什么。你有什么想法吗?
  • 感谢 Divakar,这已经给了将近两倍的改进!请参阅我的编辑。我仍然感到惊讶;通常,当将 double-for 修改为矢量化计算时,它会提供更大的改进因素。但这当然取决于算法的类型。无论如何 - 非常感谢,这真的很有帮助!
  • @NicoDean 在考虑矢量化解决方案时,有很多事情在起作用,大型阵列情况下的内存带宽要求是一个重要的问题。如果您在较小的 nn 上运行它,例如大小为 (100,100) ,则矢量化的会快得多,主要是因为内存需求较少。此外,针对您的问题,这里还要注意一点 - 如果您不做log(),我们会将其减少到sum(bsxfun(@times,然后可以用矩阵乘法代替,从而加快速度边距。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-26
  • 2016-02-21
  • 2013-05-26
  • 2011-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多