gpt4 book ai didi

dataframe - Julia 优化

转载 作者:行者123 更新时间:2023-12-04 03:22:55 34 4
gpt4 key购买 nike

我正在尝试在 Julia 中运行 Bootstrap 并编写了一个有效的 Bootstrap 函数。但是,它很慢,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 秒。

非常感谢您的建议。谢谢。

最佳答案

使用 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 更快。变化是:

  • 主要:使用 View 而不是在每次迭代中复制所有内容
  • minor:不要为每个 bootstrap 复制创建一个数据框,而是创建一个向量并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);

大致是您可以预期的执行时间的下限,它并不比上面的代码快多少(当然,它快了大约 25%-30%,因为它做的工作更少,占用更多 CPU缓存友好)。


作为一个小评论,说明细节在这种情况下的重要性(我认为这很有趣,尽管它是一个小的优化,所以我将其省略)。

如果您使用 sort!(rand(1:nrow(data), nrow(data))) 而不是 rand(1:nrow(data), nrow(data)) 你又节省了 1 秒。原因是,通过这种方式,您可以确保在计算 mean 时按顺序访问数据(这对 CPU 缓存更友好,并且 mean 不受观察顺序的影响)。

这样的第二个评论是,在多 CPU 机器上(并使用 -t 开关选择使用多个线程启动 Julia),可以使用线程来加速这样的事情(再次 - 我没有在这里优化到最后可能的调整,而是想展示主要思想):

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 中要快得多,也容易得多(虽然可行,但在 R 中并不那么容易)。


关于 View ,您可以阅读它们 here .

关于dataframe - Julia 优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68107161/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com