¿Para qué sirve el estilo idiomático de Julia por operaciones de columna o fila?


Disculpas si esto es bastante general - aunque sigue siendo una pregunta de codificación.

Con un poco de tiempo en mis manos he estado tratando de aprender un poco de Julia. Pensé que un buen comienzo sería copiar el R microbenchmark función - por lo que podría comparar sin problemas R y funciones de Julia.

Por ejemplo, esto es microbenchmark salida para 2 funciones R que estoy tratando de emular:

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

Así que hasta ahora en Julia estoy tratando de escribir código idiomático y con suerte comprensible/conciso. Por lo Tanto reemplazó un bucle doble con una comprensión de lista para crear una matriz de tiempos, como así:

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

Esto da una matriz de tiempos para cada una de las 2 funciones:

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

Mi pregunta (finalmente) es cómo idiomáticamente aplicar una función como min, max, median ¿a través de columnas (o filas) de una matriz sin usar un bucle?

Por supuesto, puedo hacerlo fácilmente para este simple caso con un bucle( sim al que taché arriba), pero no puedo encontrar nada en los documentos que es equivalente a decir apply(array,1, fun) o, incluso, colMeans.

El tipo genérico más cercano de función que se me ocurre es {[15]]}

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

.. pero la sintaxis realmente no es atractivo. ¿Hay una forma más natural de apply funciones a través de columnas o filas de una matriz multidimensional en Julia?

Author: Stephen Henderson, 2013-12-24

3 answers

Funciones anónimas fue actualmente son lentos en julia, por lo que no los usaría para benchmarking a menos que benchmarks funciones anónimas. Eso dará una predicción de rendimiento incorrecta para el código que no utiliza funciones anónimas en partes críticas de rendimiento del código.

Creo que desea que la versión de dos argumentos de las funciones de reducción, como sum(arr, 1) sume sobre la primera dimensión. Si no hay una función de biblioteca disponible, puede usar reducedim

 11
Author: ivarne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-14 09:01:30

La función que desea es mapslices.

 13
Author: John Myles White,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-25 15:50:59

Creo que @ivarne tiene la respuesta correcta (y la he marcado), pero solo añado que hice una función similar a 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

Esto entonces consigue lo que quiero así:

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] 

Donde quantile es un built-in que da min, lq, median, uq, y max.. como microbenchmark.

EDITAR Siguiendo los consejos que aquí he probado la nueva función mapslice que funciona casi como R apply y punto de referencia contra la función anterior. Tenga en cuenta que mapslice tiene dim=1 como por columna slice whilst test[:,1] es la primera columna... así que lo contrario de R aunque tiene la misma indexación?

# 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]

Así que las diversiones son aproximadamente tan rápidas como las otras. A partir de la lectura de fragmentos de la lista de correo de Julia, parece que tienen la intención de hacer algo de trabajo en este fragmento de Julialang para que hacer cortes sea por referencia en lugar de hacer nuevas copias de cada corte (fila de columnas, etc.)...

 4
Author: Stephen Henderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-26 14:15:16