25

抱歉,如果这相当笼统 - 尽管仍然是一个编码问题。

有一点时间在我手上,我一直在努力学习一点Julia. 我认为复制R microbenchmark函数是一个好的开始——这样我就可以无缝地比较 R 和 Julia 函数。

例如,这是microbenchmark我试图模拟的 2 个 R 函数的输出:

Unit: seconds
expr                    min        lq    median        uq        max      neval
vectorised(x, y)    0.2058464 0.2165744 0.2610062 0.2612965  0.2805144     5
devectorised(x, y)  9.7923054 9.8095265 9.8097871 9.8606076 10.0144012     5

到目前为止,在 Julia 中,我正在尝试编写惯用且希望可以理解/简洁的代码。因此,我用列表推导替换了一个双循环来创建一个时序数组,如下所示:

function timer(fs::Vector{Function}, reps::Integer)
#    funs=length(fs)
#    times = Array(Float64, reps, funs)
#    for funsitr in 1:funs
#        for repsitr in 1:reps
#            times[reps, funs] = @elapsed fs[funs]()
#        end
#    end

    times= [@elapsed fs[funs]() for   x=1:reps, funs=1:length(fs)]
    return times
end

这为 2 个函数中的每一个提供了一个时序数组:

julia> test=timer([vec, devec], 10)
10x2 Array{Float64,2}:
 0.231621  0.173984
 0.237173  0.210059
 0.26722   0.174007
 0.265869  0.208332
 0.266447  0.174051
 0.266637  0.208457
 0.267824  0.174044
 0.26576   0.208687
 0.267089  0.174014
 0.266926  0.208741

我的问题(最后)是如何在不使用循环的情况下习惯性地跨数组的列(或行)应用函数,例如min, ?maxmedian

对于这个简单的情况,我当然可以很容易地用一个循环(我在上面划掉的那个)来轻松地做到这一点——但我在文档中找不到任何相当于 sayapply(array,1, fun)甚至colMeans.

我能想到的最接近的通用函数是

julia> [mean(test[:,col]) for col=1:size(test)[2]]
2-element Array{Any,1}:
 0.231621
 0.237173

..但语法真的没有吸引力。在 Julia 中,是否有一种更自然的方法可以apply跨多维数组的列或行执行函数?

4

3 回答 3

17

你想要的功能是mapslices.

于 2013-12-25T15:50:59.603 回答
11

匿名函数目前在 julia 运行缓慢,因此除非您对匿名函数进行基准测试,否则我不会将它们用于基准测试。对于在代码的性能关键部分不使用匿名函数的代码,这将给出错误的性能预测。

我认为您希望归约函数的两个参数版本,例如 sum(arr, 1) 对第一个维度求和。如果没有可用的库函数,您可以使用reduceim

于 2013-12-24T17:00:38.930 回答
4

我认为@ivarne 有正确的答案(并已勾选)但我只是补充说我做了一个apply类似的功能:

function aaply(fun::Function, dim::Integer, ar::Array)
            if !(1 <= dim <= 2)
                    error("rows is 1, columns is 2")
            end
            if(dim==1)
                res= [fun(ar[row, :]) for row=1:size(ar)[dim]]
            end
            if(dim==2)
                res= [fun(ar[:,col]) for col=1:size(ar)[dim]]
            end
            return res
end

然后得到我想要的:

julia> aaply(quantile, 2, test)
2-element Array{Any,1}:
 [0.231621,0.265787,0.266542,0.267048,0.267824]
 [0.173984,0.174021,0.191191,0.20863,0.210059] 

wherequantile是一个内置函数,它给出了 min、lq、median、uq 和 max.. 就像 microbenchmark 一样。

编辑按照此处的建议,我测试了mapslice与 R 非常相似的新函数,apply并将其与上述函数进行了基准测试。请注意,第一列是按列切片...所以与R相反,尽管它具有相同的索引mapslicedim=1test[:,1]

# nonsense test data big columns
julia> ar=ones(Int64,1000000,4)
1000000x4 Array{Int64,2}:

# built in function
julia> ms()=mapslices(quantile,ar,1)
ms (generic function with 1 method)

# my apply function
julia> aa()=aaply(quantile, 2, ar)
aa (generic function with 1 method)

# compare both functions
julia> aaply(quantile, 2, timer1([ms, aa], 40))
2-element Array{Any,1}:
 [0.23566,0.236108,0.236348,0.236735,0.243008] 
 [0.235401,0.236058,0.236257,0.236686,0.238958]

因此,乐趣几乎彼此一样快。从阅读 Julia 邮件列表的部分内容来看,他们似乎打算对 Julialang 的这一部分做一些工作,以便通过引用制作切片,而不是制作每个切片的新副本(列行等)......

于 2013-12-24T19:36:04.553 回答