朱莉娅的联合熵表现

时间:2015-03-01 12:42:40

标签: performance julia entropy

我写了一个函数来计算矩阵中每列对的联合熵。但我想提高时间和记忆的表现。

该功能如下所示:

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)

......这似乎是一大堆记忆......

有关如何加速此功能并减少内存分配的任何建议?

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

以下是加快功能的一些想法。

  • 如果所有列的范围大致相同,则可以将极值计算移到循环外部并重用相同的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()