加快Julia的kNN功能

时间:2015-01-22 01:48:54

标签: python pandas dataframe julia knn

我决定将一些Python代码从Peter Harrington的机器学习行动翻译成Julia,从kNN算法开始。

在对他提供的数据集进行规范化之后,我写了一些函数:find_kNN()mass_kNN(为多个输入找到kNN的函数),以及将给定数据集拆分为随机选取的列车的函数和测试数据集,调用mass_kNN(),并多次绘制结果精度。

然后我比较了Julia代码和等效Python代码之间的运行时间。 (我在朱莉娅使用距离找到欧几里德距离和牛羚进行绘图,但是关闭绘图并不会影响时间。)

结果:

朱莉娅:
已用时间:1.175523034秒(分配455531636字节,gc时间47.54%)

的Python:
经过的时间:0.9517326354980469秒

我想知道是否有办法加快我的Julia代码,或者它是否在此时尽可能快地运行(我的意思是如果我在制作代码方面犯了任何明显的错误跑得最快。)

Julia notebook
Python notebook
repo包含笔记本和数据集

谢谢!..

修改:删除convert()语句并将所有内容传递给Real,将时间减慢到2.29秒。

1 个答案:

答案 0 :(得分:6)

首先,我删除了plot_probs的最后两行 - 我认为绘图并不是一个非常棒的基准测试,它在很大程度上超出了我(或你)的控制范围 - 如果它是一个真正的因素,可以尝试PyPlot。我还花了几次plot_probs来看看第一次花费多少时间来编译它:

**********elapsed time: 1.071184218 seconds (473218720 bytes allocated, 26.36% gc time)
**********elapsed time: 0.658809962 seconds (452017744 bytes allocated, 40.29% gc time)
**********elapsed time: 0.660609145 seconds (452017680 bytes allocated, 40.45% gc time)

所以一次支付0.3秒的罚款。转到实际的算法,我使用了内置的分析器(例如@profile plot_probs(norm_array, 0.25, [1:3], 10, 3)),它显示了所有的时间(基本上)花在这里:

  • ~80%:[ push!(dist, euclidean(set_array[i,:][:], input_array)) for i in 1:size(set_array, 1) ]
  • ~20%:[ d[i] = get(d, i, 0) + 1 for i in labels[sortperm(dist)][1:k] ]

使用像这样的数组理解不是惯用的Julia(或者就此而言的Python)。第一个也很慢,因为所有切片都会产生许多数据副本。我不是Distances.jl的专家,但我认为你可以用

替换它
dist = Distances.colwise(Euclidean(), set_array', input_array)

d = Dict{Int,Int}()
for i in labels[sortperm(dist)][1:k]
    d[i] = get(d, i, 0) + 1
end

给了我

**********elapsed time: 0.731732444 seconds (234734112 bytes allocated, 20.90% gc time)
**********elapsed time: 0.30319397 seconds (214057552 bytes allocated, 37.84% gc time)

通过在mass_kNN中进行一次转置,可以提取更多性能,但这需要触及太多的地方,这篇文章足够长。尝试微观优化它导致我使用

dist=zeros(size(set_array, 1)
@inbounds for i in 1:size(set_array, 1)
    d = 0.0
    for j in 1:length(input_array)
        z = set_array[i,j] - input_array[j]
        d += z*z
    end
    dist[i] = sqrt(d)
end

将其送到

**********elapsed time: 0.646256408 seconds (158869776 bytes allocated, 15.21% gc time)
**********elapsed time: 0.245293449 seconds (138817648 bytes allocated, 35.40% gc time)

所以花了大约一半的时间 - 但不是真的值得,而且不太灵活(例如,如果我想要L1)。其他代码审查点(未经请求,我知道):

  • 我发现Vector{Float64}Matrix{Float64}Array{Float64,1}Array{Float64,2}更容易被发现,并且不太可能被混淆。
  • Float64[]Array(Float64, 0)
  • 更常见
  • Int64只能写为Int,因为它不需要是64位整数。