簡體   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