Julia 中的联合熵性能
Joint Entropy Performance in Julia
我写了一个函数来计算矩阵中每个列对的联合熵。但我想提高有关时间和内存的性能。
函数如下所示:
function jointentropy(aln)
mat = Array(Float64,size(aln,2),size(aln,2))
for i in combinations(1:size(aln,2),2)
a = i[1]
b = i[2]
mina, maxa = extrema(aln[:,a])
minb, maxb = extrema(aln[:,b])
h = Array(Float64,(maxa-mina+1,maxb-minb+1))
h = hist2d([aln[:,a] aln[:,b]],mina-1:1:maxa,minb-1:1:maxb)[3]
h = h/size(aln[:,1],1)
I,J,V = findnz(h)
l = sparse(I,J,log2(V),maxa-mina+1,maxb-minb+1)
mat[b,a] = - sum(l.*h)
end
return mat
end
进入此函数的矩阵如下所示:
rand(45:122,rand(1:2000),rand(1:2000))
具有 500x500 矩阵的示例导致以下 @time 输出:
elapsed time: 33.692081413 seconds (33938843192 bytes allocated, 36.42% gc time)
...这似乎是一大堆内存...
关于如何加速此功能并减少内存分配有什么建议吗?
在此先感谢您的帮助!
这里有一些想法可以加快您的功能。
如果所有列的范围大致相同,您可以将极值计算移到循环外并重新使用相同的 h
数组。
hist2d
创建一个新数组:您可以使用 hist2d!
重复使用之前的数组。
赋值h = h/size(aln[:,1],1)
创建一个新数组。
h = h/size(aln[:,1],1)
中的除法是对数组的所有元素完成的,包括零。
您可以使用循环代替 findnz
和稀疏矩阵(findnz
已经包含循环)。
.
function jointentropy2(aln)
n1 = size(aln,1)
n2 = size(aln,2)
mat = Array(Float64,n2,n2)
lower, upper = extrema(aln)
m = upper-lower+1
h = Array(Float64,(m,m))
for a in 1:n2
for b in (a+1):n2
Base.hist2d!(h,[aln[:,a] aln[:,b]],lower-1:1:upper,lower-1:1:upper)[3]
s = 0
for i in 1:m
for j in 1:m
if h[i,j] != 0
p = h[i,j] / n1
s += p * log2(p)
end
end
end
mat[b,a] = - s
end
end
return mat
end
这比初始函数快两倍,
内存分配除以 4.
aln = rand(45:122,500,400)
@time x = jointentropy(aln)
# elapsed time: 26.946314168 seconds (21697858752 bytes allocated, 29.97% gc time)
@time y = jointentropy2(aln)
# elapsed time: 13.626282821 seconds (5087119968 bytes allocated, 16.21% gc time)
x - y # approximately zero (at least below the diagonal --
# the matrix was not initialized above it)
下一个优化候选对象是hist2d
(在这里,您可以使用循环和稀疏矩阵)。
@profile jointentropy2(aln)
Profile.print()
我写了一个函数来计算矩阵中每个列对的联合熵。但我想提高有关时间和内存的性能。
函数如下所示:
function jointentropy(aln)
mat = Array(Float64,size(aln,2),size(aln,2))
for i in combinations(1:size(aln,2),2)
a = i[1]
b = i[2]
mina, maxa = extrema(aln[:,a])
minb, maxb = extrema(aln[:,b])
h = Array(Float64,(maxa-mina+1,maxb-minb+1))
h = hist2d([aln[:,a] aln[:,b]],mina-1:1:maxa,minb-1:1:maxb)[3]
h = h/size(aln[:,1],1)
I,J,V = findnz(h)
l = sparse(I,J,log2(V),maxa-mina+1,maxb-minb+1)
mat[b,a] = - sum(l.*h)
end
return mat
end
进入此函数的矩阵如下所示:
rand(45:122,rand(1:2000),rand(1:2000))
具有 500x500 矩阵的示例导致以下 @time 输出:
elapsed time: 33.692081413 seconds (33938843192 bytes allocated, 36.42% gc time)
...这似乎是一大堆内存...
关于如何加速此功能并减少内存分配有什么建议吗?
在此先感谢您的帮助!
这里有一些想法可以加快您的功能。
如果所有列的范围大致相同,您可以将极值计算移到循环外并重新使用相同的
h
数组。hist2d
创建一个新数组:您可以使用hist2d!
重复使用之前的数组。赋值
h = h/size(aln[:,1],1)
创建一个新数组。h = h/size(aln[:,1],1)
中的除法是对数组的所有元素完成的,包括零。您可以使用循环代替
findnz
和稀疏矩阵(findnz
已经包含循环)。
.
function jointentropy2(aln)
n1 = size(aln,1)
n2 = size(aln,2)
mat = Array(Float64,n2,n2)
lower, upper = extrema(aln)
m = upper-lower+1
h = Array(Float64,(m,m))
for a in 1:n2
for b in (a+1):n2
Base.hist2d!(h,[aln[:,a] aln[:,b]],lower-1:1:upper,lower-1:1:upper)[3]
s = 0
for i in 1:m
for j in 1:m
if h[i,j] != 0
p = h[i,j] / n1
s += p * log2(p)
end
end
end
mat[b,a] = - s
end
end
return mat
end
这比初始函数快两倍, 内存分配除以 4.
aln = rand(45:122,500,400)
@time x = jointentropy(aln)
# elapsed time: 26.946314168 seconds (21697858752 bytes allocated, 29.97% gc time)
@time y = jointentropy2(aln)
# elapsed time: 13.626282821 seconds (5087119968 bytes allocated, 16.21% gc time)
x - y # approximately zero (at least below the diagonal --
# the matrix was not initialized above it)
下一个优化候选对象是hist2d
(在这里,您可以使用循环和稀疏矩阵)。
@profile jointentropy2(aln)
Profile.print()