朱莉娅:优化功能

时间:2016-02-04 01:16:32

标签: optimization julia

我正在努力学习写好julia代码。我想编写以下统计信息。

(注1 {A} = 1如果为真,0如果为假)

enter image description here

,其中

enter image description here

enter image description here

function cohens_kappa(x::Vector{Int}, k::Int)
  support = unique(x)
  m = length(support)
  n = length(x)
  y = BitArray(n, m)
  for j in eachindex(support)
    y[:,j] = (X .== support[j])
  end

  num = 0.0
  den = 0.0
  for j in eachindex(support)
    pjjk = sum(y[(1 + k):n, j] & y[1:(n - k), j]) / (n - k)
    pj = sum(y[:, j]) / n

    num += pjjk - pj ^ 2
    den += (1 / m) - pj ^ 2
  end
  return (num / den)
end

这是最有效的编码方式吗?

编辑: 谢谢你的所有建议。你能解释为什么你的代码更有效吗?我想学习如何继续编写好的代码。

针对@ user3580870测试我们的两个例子

@time [cohens_kappa(X, k) for k in 1:15]
  0.000507 seconds (1.58 k allocations: 269.016 KB)

@time [cohens_kappa2(X, k) for k in 1:15]
  0.000336 seconds (166 allocations: 12.375 KB)

@time [cohens_kappa3(X, k) for k in 1:15]
  0.000734 seconds (303 allocations: 84.109 KB)

看起来你的第二个建议不是那么快,但它的分配比我的原始版本少,所以对于非常大的向量可能会更快。

3 个答案:

答案 0 :(得分:3)

这是另一个版本,它带来了重大改进:

   function cohens_kappa2(x::Vector{Int}, k::Int)
     d = Dict{Int,Int}()
     n = length(x)
     c1 = Int[]
     pnew = 0
     for i=1:n
       p = get(d,x[i],0)
       if p>0
         c1[p] += 1
       else
         pnew += 1
         d[x[i]] = pnew
         push!(c1,1)
       end
     end
     c2 = zeros(Int,pnew)
     for i=(k+1):n
       if x[i-k]==x[i] c2[d[x[i]]] += 1 ; end
     end
     num, dentmp = 0.0, 0.0
     for i=1:pnew
       pjjk = c2[i]/(n-k)
       pj = c1[i] / n
       num += pjjk - pj^2
       dentmp += pj^2
     end
     return (num / (1.0-dentmp))
   end

一般来说,优化几乎总是可行的,但就像从自然界中提取石油一样,它会增加程序员的成本和工作量。

在一个测试用例中,上面给了我5倍到10倍的加速。您的数据的结果是什么?

答案 1 :(得分:2)

还有一个优化可用。要找到自相关,您只需使用逻辑索引找到的减少的匹配向量:

function cohens_kappa_2(x::vector{Int},k:Int)

  ...

  # Autocorrelation dictionary
  dxx=Dict{Int,Int}()

  # k-step element-wise matches
  xx=(x[1:end-k])[x[1:end-k] .== x[1+k:end]]

  # Populate the dictionary
  for exx in xx
    dxx[exx] += 1 # Warning! pseudo-code
  end

  ...

end

关键的见解是,统计数据的自相关部分只“关心”与前面的元素k步相匹配的元素,因此我们可以先检查它。

请注意,使用字典是因为其散列允许对唯一元素进行线性时间分辨。相比之下,唯一函数将实现某种形式的排序,堆或树结构,平均具有O(N * lnN)性能。

答案 2 :(得分:1)

添加另一个版本。这个比我在另一个答案中给出的更长的展开版本稍微慢一些。另一方面,它更清晰,并使用DataStructurescounter。在代码中,cc计算所有元素及其freqeuncies和cc2计数k相同元素的距离对。来源:

using DataStructures     # install with Pkg.add("DataStructures")

function cohens_kappa3(x::Vector{Int}, k::Int)
      n = length(x)
      cc = counter(x)
      cc2 = counter(x[[i<=k ? false : x[i]==x[i-k] for i=1:n]])
      num, den = 0.0,1.0
      for (val,freq) in cc
          pj2 = (freq/n)^2
          num += cc2[val]/(n-k)-pj2
          den -= pj2
      end
      return num/den
end