【问题标题】:MATLAB loop optimizationMATLAB 循环优化
【发布时间】:2011-07-27 05:31:09
【问题描述】:

我有一个矩阵,ma​​trix_logical(50000,100000),它是一个稀疏逻辑矩阵(很多错误,一些正确)。我必须生成一个矩阵,intersect(50000,50000),对于每一对 i,jma​​trix_logical(50000,100000) 行,存储行 ij 都具有“true”作为值的列数。

这是我写的代码:

% store in advance the nonzeros cols
for i=1:50000
    nonzeros{i} = num2cell(find(matrix_logical(i,:)));
end

intersect = zeros(50000,50000);

for i=1:49999
    a = cell2mat(nonzeros{i});
    for j=(i+1):50000
        b = cell2mat(nonzeros{j});
        intersect(i,j) = numel(intersect(a,b));
    end
end

是否可以进一步提高性能?计算矩阵需要很长时间。我想避免代码第二部分中的双循环。

ma​​trix_logical 是稀疏的,但在 MATLAB 中不会保存为稀疏,否则性能会变得最差。

【问题讨论】:

  • 请注意,intersect 可能是一个错误的变量名选择,因为已经有一个 interesect 函数。
  • 你有没有想过使用 pdist() 和自定义距离函数来给出你想要的结果?
  • @Eugenio:您要生成的结果矩阵(假设它具有single 类类型)太大而无法放入内存50000*50000*4/2^30 = 9.31 GB...

标签: performance matlab loops vectorization


【解决方案1】:

由于 [i,j] 条目计算 i 和 j 行的元素乘法中非零元素的数量,您可以通过将 matrix_logical 与其转置相乘来实现(您应该转换为数字数据类型首先,例如matrix_logical = single(matrix_logical)):

inter = matrix_logical * matrix_logical';

它适用于稀疏或完整表示。

编辑

为了计算numel(intersect(a,b))/numel(union(a,b));(如您的评论中所要求的),您可以使用以下事实:对于两组ab,您有

length(union(a,b)) = length(a) + length(b) - length(intersect(a,b))

所以,您可以执行以下操作:

unLen = sum(matrix_logical,2);
tmp = repmat(unLen, 1, length(unLen)) + repmat(unLen', length(unLen), 1);
inter = matrix_logical * matrix_logical';
inter = inter ./ (tmp-inter);

【讨论】:

  • 好答案!但是,您需要将 matrix_logical 转换为数字矩阵 (single(matrix_logical))。
  • @Itamar 感谢您的回答;我的代码实际上需要联合上的交集(我删除了第二部分只是为了使代码更简单)所以:intersection(i,j) = numel(intersect(a,b))/numel(union(a,b)); 是否仍然可以应用您的方法?
  • @Itamar;非常感谢,真的,你的回答真的很有帮助。
  • 在这种情况下,您可以考虑接受它(以及接受您发布的其他问题的答案,如stackoverflow.com/faq#howtoask 此处所述)
【解决方案2】:

如果我理解正确,您需要行的逻辑与:

intersct = zeros(50000, 50000)
for ii = 1:49999
    for jj = ii:50000
        intersct(ii, jj) = sum(matrix_logical(ii, :) & matrix_logical(jj, :));
        intersct(jj, ii) = intersct(ii, jj);
    end
end

没有避免双循环,但至少可以在没有第一个循环和慢查找命令的情况下工作。

【讨论】:

  • 问题是:如果matrix_logical 非常稀疏,这会比OP的原始代码慢吗?
  • 第一个循环其实没问题,够快;问题出在代码的第二部分。
  • @Oli 嗯,你是对的,可能会构建一个示例,其中我的代码比 OP 代码慢。不管怎样,Itamar 提出了一个更优雅的解决方案,它甚至可以同时处理真正的稀疏矩阵......
【解决方案3】:

详细说明我的评论,这里有一个适合pdist()的距离函数

function out = distfun(xi,xj)
    out = zeros(size(xj,1),1);
    for i=1:size(xj,1)
        out(i) = sum(sum( xi & xj(i,:) )) / sum(sum( xi | xj(i,:) ));
    end

根据我的经验,sum(sum()) 的逻辑运算速度比 nnz() 快​​,因此它出现在上面。

您还需要使用squareform() 来适当地重塑pdist() 的输出:

squareform(pdist(martrix_logical,@distfun));

注意pdist() 包含一个'jaccard' 距离度量,但它实际上是 Jaccard distance 而不是 Jaccard indexcoefficient,这显然是你所追求的价值。

【讨论】:

  • 感谢回答,我没有尝试,因为我最终使用了 Itamar 提出的解决方案。
猜你喜欢
  • 1970-01-01
  • 2020-10-19
  • 2021-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-18
  • 2020-02-06
  • 2019-05-31
相关资源
最近更新 更多