我正在努力学习写好julia代码。我想编写以下统计信息。
(注1 {A} = 1如果为真,0如果为假)
,其中
和
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)
看起来你的第二个建议不是那么快,但它的分配比我的原始版本少,所以对于非常大的向量可能会更快。
答案 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)
添加另一个版本。这个比我在另一个答案中给出的更长的展开版本稍微慢一些。另一方面,它更清晰,并使用DataStructures
包counter
。在代码中,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