我正在尝试在 Julia 中运行引导程序并编写了一个工作引导程序函数。但是,它很慢,并且 R 中的相同代码运行时间减半。我确信我的代码中一定存在一些低效问题,我对使用 Julia 非常陌生。我想知道是否有人可以为我提供一些建议/建议。
这是完全可重现的代码
using DataFrames
using Statistics
using StatsBase
df = DataFrame(rand(1:9, 1000,1000), :auto); # Create data
# Bootstrap function
function bootstrap(;iters=1, data=nothing, statistic=nothing)
statArr = DataFrame() # Init empty dataframe
for i in 1:iters
data_sample = data[sample(1:nrow(data), nrow(data), replace=true), :] # sample the data with replacement
stat = statistic(data_sample)
append!(statArr, stat) # push dataframe to empty dataframe
end
return statArr
end;
# Statistic function for column means
function meanmap(data)
return mapcols(col -> mean(col), data)
end;
# Run the bootstrap on the data
@time bootDist = bootstrap(iters = 9999, data = df, statistic = meanmap);
这大约需要 68 秒才能运行,而在 R 中需要 35 秒。
非常感谢您的建议。 谢谢。
答案 0 :(得分:3)
使用 DataFrames.jl 你可以做例如:
function bootstrap(;iters=1, data=nothing, statistic=nothing)
statArr = Float64.(empty(data)) # Init empty dataframe
for i in 1:iters
stat = statistic(data, rand(1:nrow(data), nrow(data)))
push!(statArr, stat) # push row to empty dataframe
end
return statArr
end;
# Statistic function for column means
meanmap(data, sel) = [mean(@view x[sel]) for x in eachcol(data)]
哪个应该比 R 快。变化是:
push!
它而不是append!
对其进行julia> x = rand(1:nrow(df), nrow(df));
julia> y = df[!, 1];
julia> f(y, x) = mean(@view y[x]);
julia> g(y, x) = [f(y, x) for _ in 1:9999*1000];
julia> @time g(y, x);
(这样可以节省创建和验证数据框对象的时间)立>
(我只对代码进行了主要优化;还有一些额外的小优化可以进行,但它们不应显着影响运行时间)
另请注意,您接近最大执行速度为:
rand(1:nrow(data), nrow(data))
大致是您可以预期的执行时间下限,它并不比上面的代码快多少(当然,它快了 25%-30%,因为它的工作量更少,CPU 也更多缓存友好)。
作为一个小评论,显示在这种情况下细节的重要性(我认为这很有趣,虽然这是一个小优化,所以我没有考虑)。
如果您使用 sort!(rand(1:nrow(data), nrow(data)))
而不是 mean
,您可以多节省 1 秒。原因是通过这种方式,您可以确保在计算 mean
时按顺序访问数据(这对 CPU 缓存更友好,并且 -t
不受观察顺序的影响)。
像这样的第二个评论是在多 CPU 机器上(并使用 function bootstrap(;iters=1, data=nothing, statistic=nothing)
statArr = Float64.(empty(data)) # Init empty dataframe
tmp = Vector{Any}(undef, iters)
Threads.@threads for i in 1:iters
stat = statistic(data, rand(1:nrow(data), nrow(data)))
tmp[i] = stat
end
for v in tmp
push!(statArr, v) # push dataframe to empty dataframe
end
return statArr
end
开关选择使用多个线程启动 Julia)可以使用线程来加速这样的事情(再次 - 我做到了不是将这里的东西优化到最后一次可能的调整,而是想展示主要思想):
if ( testvalue[i] != "HRZ") {
这在 Julia 中实现起来更快也更容易(虽然可行,但在 R 中不那么容易)。
关于视图,您可以阅读here。