繁体   English   中英

成对加权距离矢量化

[英]Pairwise weighted distance vectorization

以下有效和矢量化的Matlab代码使用权重向量WTS(每个维度1个权重;所有点的相同权重)计算2组A点和B点之间的加权欧氏距离:

    WTS = sqrt(WTS); 

    % modify A and B against weight values
    A = WTS(ones(1,size(A,1)),:).*A;
    B = WTS(ones(1,size(B,1)),:).*B; 

    % calculate distance
    AA = sum(A.*A,2);  
    BB = sum(B.*B,2)'; 
    D = sqrt(AA(:,ones(1,size(B,1))) + BB(ones(1,size(A,1)),:) - 2*A*B'); 

(来源: https//github.com/nolanbconaway/pairdist/blob/master/pairdist.m

我的问题是:是否有一个有效的矢量化形式(Matlab,R或Julia很好)用于类似的计算,区别在于WTS是一组与A大小相同的权重向量 换句话说,代替1个权重向量, 我需要A中每个点的1个权重向量

这个答案似乎做了我需要的,但它是在Python中,我不知道如何将其转换为Matlab / R / Julia: https//stackoverflow.com/a/19285289/834518

此外,不是在MATLAB有效计算加权距离的重复,因为该问题涉及单个权重向量情况,并且我明确要求N个权向量情况。

编辑:示例应用:RBF网络和高斯混合模型,其中您(可以)为每个神经元/组件具有1个权重向量。 解决问题的有效方法对于这些问题至关重要。

在朱莉娅你不必将它矢量化为高效,只需编写循环,它将比这些矢量化形式更快,因为它可以融合并摆脱临时性。 这是一个非常有效的实现成对适用于朱莉娅 ,你可以工作。 它有所有的花里胡哨,但你可以根据需要配对它。

注意,矢量化不一定是“快速的”,它只比在R / Python / MATLAB中循环更快,因为它只对一个用低级语言(C / C ++)编写的优化内核进行单个函数调用,这实际上是循环的。 但是将矢量化函数放在一起通常会有很多临时分配,因为每个矢量化函数都会返回数组。 因此,如果你真的需要效率,你应该避免一般的矢量化,并用允许低成本函数调用/循环的语言编写它。 这篇文章更多地解释了高级语言中矢量化的问题

这回答了你遇到的三个问题之一。 对于MATLAB或R,我没有一个好的答案。

这是MATLAB中的矢量化版本(R2016b及更高版本):

W2 = 1./W.^2;
D = sqrt(sum((A./W).^2 ,2) - 2 * (A .* W2) * B.' +W2 * (B.^2).');

在R2016b之前的版本中,您可以使用:

W2 = 1./W.^2;
D = sqrt(bsxfun(@plus,sum((A./W).^2 ,2) , -2 * (A .* W2) * B.' +W2 * (B.^2).'));

将MATLAB翻译成julia:

W2 = 1./W.^2;
z=sqrt.(broadcast(+,sum((A./W).^2 ,2) , -2 * (A .* W2) * B.' .+W2 * (B.^2).'));

在这里,我提出的方法Vectorization与@DanGetz提供的Loop方法进行了比较。 其他解决方案不适用于此。

距离计算比较

我们可以看到,对于小于128的维度,循环版本比矢量化版本更快。 随着维数的增加,循环版本的性能会变差。

以下代码用于生成图:

function pdist_vectorized (A::Matrix, B::Matrix, W::Matrix)
    W2 = 1./W.^2;
    return sqrt.(broadcast(+,sum((A./W).^2 ,2) , -2 * (A .* W2) * B.' .+W2 * (B.^2).'));
end

result = zeros(10,2);
for i = 1:10
    A = rand( 3000, 2^i);
    B = rand( 2000, 2^i);
    W = ones(size(A));
    result[i,1]=(@timed pdist_1alloc(A,B,W))[2];
    result[i,2]=(@timed pdist_vectorized(A,B,W))[2];
end

using Plots
pyplot()
plot(2.^(1:10), result, title="Pairwise Weighted Distance",
    label=["Loop" "Vectorization"], lw=3,
    xlabel = "Dimension", ylabel = "Time Elapsed(seconds)")

作为未来读者的附加信息, Distances.jl包可以有效地实现您能想到的大多数距离。 作为一般建议,如果一项操作在科学计算中非常普遍,那么将有一个实施它的包。

using Distances

D = pairwise(WeightedEuclidean(weights), A, B)

另一个版本经过优化以分配结果矩阵,而不是其他:

function pdist_1alloc(A::Matrix, B::Matrix, W::Matrix)
    LA, LD = size(A) ; LB = size(B,1)
    res = zeros(LB, LA)
    indA = 0 ; indB = 0 ; indres = 0
    @inbounds for i=1:LD
        for j=1:LA
            a = A[indA+j] ; w = W[indA+j] ; a2w = a^2*w ; awtmp = -2.0*a*w
            for k=1:LB
                indres += 1
                b = B[indB+k] ; b2w = b^2*w
                res[indres] += a2w+awtmp*b+b2w
            end
        end
        indA += LA ; indB += LB ; indres = 0
    end
    res .= sqrt.(res)
    return res
end

它比@ rahnema1的版本快2倍,并使用相同的技巧,但不是可读的。 另外,我为首先误解问题的确切设置而道歉(并建议在这里不直接适用的Distance.jl)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM