Подтвердить что ты не робот

Что такое идиоматический стиль Джулии для операций с колонками или строками?

Извиняется, если этот довольно общий - хотя и еще вопрос кодирования.

С небольшим количеством времени на моих руках я пытался узнать немного 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

Итак, до сих пор в Джулии я пытаюсь написать идиоматический и, надеюсь, понятный/сложный код. Поэтому я заменил двойной цикл со списком, чтобы создать массив таймингов, например:

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

Это дает массив таймингов для каждой из двух функций:

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, max, median для столбцов (или строк) массива без использования цикла?

Я могу, конечно, сделать это легко для этого простого случая с циклом (sim, который я перечеркнул выше), но я не могу найти что-либо в документах, что эквивалентно словам apply(array,1, fun) или даже colMeans.

Ближайшая родовая функция, о которой я могу думать,

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

.., но синтаксис действительно действительно не привлекателен. Есть ли более естественный способ для apply функций по столбцам или строкам многомерного массива в Julia?

4b9b3361

Ответ 1

Анонимные функции были в настоящее время медленны в julia, поэтому я не буду использовать их для бенчмаркинга, если вы не будете тестировать анонимные функции. Это даст неправильное предсказание производительности для кода, который не использует анонимные функции в критичных для производительности частях кода.

Я думаю, вы хотите, чтобы две аргументные функции редукции, такие как sum (arr, 1), суммировали по первому размеру. Если функции библиотеки нет, вы можете использовать reducedim

Ответ 2

Требуемая функция mapslices.

Ответ 3

Я думаю, что @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] 

где quantile является встроенным, который дает min, lq, медианный, uq и max.. точно так же, как microbenchmark.

EDIT Следуя рекомендациям здесь, я протестировал новую функцию mapslice, которая очень похожа на R apply и сравнила ее с вышеприведенной функцией. Обратите внимание, что mapslice имеет dim=1 как срез столбца, тогда как test[:,1] - это первый столбец... так что противоположность R, хотя он имеет одинаковую индексацию?

# 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, так что создание срезов является ссылкой, а не созданием новых копий каждого фрагмента (строка столбца и т.д.)...