【发布时间】:2018-08-22 16:56:29
【问题描述】:
我对 Julia 编程语言非常陌生,我正在测试一些我通常在其他语言中执行的欧几里得距离运算。如果连续调用函数,这些函数会起作用,但 pmap 调用不会返回所需的结果。有人可以看看并让我知道我是否以正确的方式进行此操作? pmap 甚至是解决此问题的最佳方法吗?
using Distributed
#Example data
d1 = randn(50000,3)
d2 = randn(50000,3)
第一个函数:欧几里得距离矩阵
function EDM(m1, m2)
n1 = size(m1, 1)
n2 = size(m2,1)
k = size(m1, 2)
Dist = zeros(n1,n2)
for i in 1:n1
for j in 1:n2
dtemp = 0
for a in 1:k
dtemp += (m1[i,a] - m2[j,a]) ^ 2
end
Dist[i,j] = sqrt(dtemp)
end
end
return Dist
end
#pmap call
function pmap_EDM(m1,m2)
return pmap(EDM, m1, m2)
end
第二个函数:最小欧几里得距离单向
function MED(m1, m2)
n1 = size(m1, 1)
n2 = size(m2,1)
k = size(m1, 2)
Dist = zeros(n1,1)
for i in 1:n1
dsum = Inf
for j in 1:n2
dtemp = 0
for a in 1:k
dtemp += (m1[i,a] - m2[j,a]) ^ 2
end
dtemp = sqrt(dtemp)
if dtemp < dsum
dsum = copy(dtemp)
end
end
Dist[i,1] = dsum
end
return Dist
end
#pmap call
function pmap_MED(m1,m2)
return pmap(MED, m1, m2)
end
第三个函数:最小欧几里得距离和对应的单向指数
function MEDI(m1, m2)
n1 = size(m1, 1)
n2 = size(m2,1)
k = size(m1, 2)
Dist = zeros(n1,2)
for i in 1:n1
dsum = Inf
dsum_ind = 0
for j in 1:n2
dtemp = 0
for a in 1:k
dtemp += (m1[i,a] - m2[j,a]) ^ 2
end
dtemp = sqrt(dtemp)
if dtemp < dsum
dsum = copy(dtemp)
dsum_ind = copy(j)
end
end
Dist[i,1] = dsum
Dist[i,2] = dsum_ind
end
return Dist
end
#pmap call
function pmap_MEDI(m1,m2)
return pmap(MEDI, m1, m2)
end
调用函数
r1 = EDM(d1,d2) #serial
r2 = pmap_EDM(d1,d2)
r3 = MED(d1,d2) #serial
r4 = pmap_MED(d1,d2)
r5 = MEDI(d1,d2) #serial
r6 = pmap_MEDI(d1,d2)
编辑:
第一个函数应该返回一个简单的欧几里得距离矩阵,其中包含一个数组中的每一行与第二个数组中的每一行之间的距离。第二个和第三个函数是基于一个数组中的每一行到另一个数组中的每一行的最小距离返回这些距离的子集的偏差(第三个函数返回最小距离的索引位置)。距离似乎没有正确计算,后两个函数使用 pmap 返回一个 nx3 矩阵,而不是分别返回 nx1 和 nx2。
编辑 2:使用较小数据集显示结果的示例
d1 = randn(5,3)
d2 = randn(5,3)
julia> EDM(d1,d2)
5×5 Array{Float64,2}:
2.60637 3.18867 1.0745 2.60328 1.58608
1.2763 2.31037 3.04379 2.74113 2.00452
1.70024 2.07731 3.12397 2.60893 2.05932
2.44581 1.57345 0.910323 1.08718 0.407675
3.42936 1.13001 2.18345 1.08764 1.70883
julia> pmap_EDM(d1,d2)
5×3 Array{Array{Float64,2},2}:
[0.397928] [2.39283] [0.953501]
[1.06776] [0.815057] [1.87973]
[0.151963] [3.05161] [0.650967]
[0.571021] [0.275554] [0.883151]
[0.109293] [0.635398] [1.58254]
julia> MED(d1,d2)
5×1 Array{Float64,2}:
1.0744953977891307
1.2762979313081781
1.7002448697495505
0.40767454400155695
1.0876399289364607
julia> pmap_MED(d1,d2)
5×3 Array{Array{Float64,2},2}:
[0.397928] [2.39283] [0.953501]
[1.06776] [0.815057] [1.87973]
[0.151963] [3.05161] [0.650967]
[0.571021] [0.275554] [0.883151]
[0.109293] [0.635398] [1.58254]
julia> MEDI(d1,d2)
5×2 Array{Float64,2}:
1.0745 3.0
1.2763 1.0
1.70024 1.0
0.407675 5.0
1.08764 4.0
julia> pmap_MEDI(d1,d2)
5×3 Array{Array{Float64,2},2}:
[0.397928 1.0] [2.39283 1.0] [0.953501 1.0]
[1.06776 1.0] [0.815057 1.0] [1.87973 1.0]
[0.151963 1.0] [3.05161 1.0] [0.650967 1.0]
[0.571021 1.0] [0.275554 1.0] [0.883151 1.0]
[0.109293 1.0] [0.635398 1.0] [1.58254 1.0]
编辑 3:@函数二的分布式版本
using Distributed
using SharedArrays
#Minimum Euclidean Distances Unidirectional
@everywhere function MD(v1, m2)
n = size(m2, 1)
dsum = Inf
for j in 1:n
dtemp = sqrt((v1[1] - m2[j,1]) ^ 2 + (v1[2] - m2[j,2]) ^ 2 + (v1[3] - m2[j,3]) ^ 2)
if dtemp < dsum
dsum = dtemp
end
end
return dsum
end
function MED(m1, m2)
n1 = size(m1,1)
Dist = SharedArray{Float64}(n1)
m3 = SharedArray{Float64}(m2)
@sync @distributed for k in 1:n1
Dist[k] = MD(m1[k,:], m3)
end
return Dist
end
【问题讨论】:
-
您希望看到什么以及您看到的哪些不符合这些期望?
-
@Engineero 我已经更新了问题以指定这一点。 F1:期望看到一个简单的欧几里得距离矩阵。 F2:期望看到最小距离而不是整个距离矩阵。 F3:期望看到最小距离和索引位置最小距离出现在第二个数据集中。
-
我不是
pmap方面的专家,但是关于您的例程的另外两个 cmets:1) Julia 使用列优先排序(与 C 不同),因此像您在最内层循环中一样遍历列比将问题改写为跨行迭代要慢得多。 2) Distances 包是一个真的写得很好的 Julia 包,所以你正在寻找最佳速度,你应该检查一下。 -
第三条评论:
Number的子类型,例如浮点数和整数,在 Julia 中是不可变的,所以像copy(1)这样的操作是允许的,但不是特别有意义。你可以做x = 0 ; y = x ; y = 1,你会注意到x仍然是0。copy通常用于可变类型,例如数组。 -
@ColinTBowers 感谢您提供信息。我会查看 Distances 包,但乍一看它似乎没有提供计算整个距离矩阵的方法?