python - 在 Julia 中加速 kNN 函数

标签 python pandas dataframe julia knn

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

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

然后我比较了 Julia 代码和等效的 Python 代码之间的运行时间。 (我在 Julia 中使用 Distances 来查找欧几里德距离,并使用 Gadfly 进行绘图,但关闭绘图对时间影响不大。)

结果:

Julia :
耗时:1.175523034 秒(分配了 455531636 字节,47.54% gc 时间)

python :
耗时:0.9517326354980469 秒

我想知道是否有一种方法可以加快我的 Julia 代码的速度,或者它此时是否运行得尽可能快(我的意思是我在使代码运行最快方面是否犯了任何明显的错误。 )

Julia notebook
Python notebook
repo有笔记本和数据集

谢谢!..

编辑:删除 convert() 语句并传递所有内容,因为 Real 将时间减慢到 2.29 秒。

最佳答案

所以首先,我删除了 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.3s的惩罚。继续实际的算法,我使用了内置的分析器(例如 @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 位整数。

关于python - 在 Julia 中加速 kNN 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28080071/

相关文章:

python - 如何分割字符串,使其包含少于 n 个字符并进行扭曲

python - 为什么你永远不应该重新加载模块?

python - Pandas Holidays to Dataframe with Holiday Name

python - pandas - 带有时间序列数据的堆积条形图

基于正则表达式的R子串

python - 将唯一值加入新数据框(python、pandas)

python - 对 itertools groupby 求和感到困惑

python - 从文档中了解 PyTorch 伯努利分布

python - 对 Python Pandas 数据透视表中的列进行分组

python - 将逗号分隔值从 mysql 加载到 python 中的数据框