Применить функцию к парам столбцов в Юлии - PullRequest
2 голосов
/ 12 мая 2019

У меня есть пара матриц, скажем Ws, Xs, равной размерности и функция myFunc(w, x), которая принимает два вектора в качестве входных данных.Я хочу применить эту функцию к парам столбцов (представьте, что это zip -с столбцами) и сопоставить им эту функцию.

Есть ли не итеративный способ сделать это?Если бы в каждом из Ws, Xs было только два столбца, я могу сделать

allCols = permutedims(reshape(hcat(Ws, Xs), d, 2), [1, 3, 2])
mapslices(x -> myFunc(x[:, 1], x[:, 2]), allCols, dims=[1, 2])

, но у меня возникают проблемы при переходе к произвольному количеству столбцов.

Редактировать : с использованием vcat и правильные размеры, кажется, исправить это:

# assume d is column size
wxArray = reshape(vcat(Ws, Xs), 2, d)  # group pairs of columns together
mapslices(x -> myFunc(x[:, 1], x[:, 2]), wxArray, dims=[1,2])

1 Ответ

2 голосов
/ 12 мая 2019

Вы можете использовать функцию eachcol следующим образом (я даю три способа, чтобы показать различные возможные подходы, но eachcol имеет решающее значение во всех из них):

julia> Ws = rand(2,3)
2×3 Array{Float64,2}:
 0.164036  0.233236  0.937968
 0.724233  0.102248  0.55047

julia> Xs = rand(2,3)
2×3 Array{Float64,2}:
 0.0493071  0.735849  0.643352
 0.909295   0.276808  0.396145

julia> using LinearAlgebra

julia> dot.(eachcol(Ws), eachcol(Xs))
3-element Array{Float64,1}:
 0.6666296397421881
 0.19992972241709792
 0.8215096642236619

julia> dot.(eachcol.((Ws, Xs))...)
3-element Array{Float64,1}:
 0.6666296397421881
 0.19992972241709792
 0.8215096642236619

julia> map(dot, eachcol(Ws), eachcol(Xs))
3-element Array{Float64,1}:
 0.6666296397421881
 0.19992972241709792
 0.8215096642236619

Для этого требуется Julia 1.1.

РЕДАКТИРОВАТЬ

Если вы используете Julia 1.0 и хотите избежать итерации, не обращая внимания на некоторые дополнительные выделения (решение выше позволяет избежать выделений), вы также можете использовать функцию cat (что немногоя думаю, что это проще, чем ваш подход):

julia> Ws = rand(2,3)
2×3 Array{Float64,2}:
 0.975749  0.660932  0.391192
 0.619872  0.278402  0.799096

julia> Xs = rand(2,3)
2×3 Array{Float64,2}:
 0.0326003  0.272455  0.713046
 0.389058   0.886105  0.950822

julia> mapslices(x -> (x[:,1], x[:,2]), cat(Ws, Xs; dims=3), dims=[1,3])[1,:,1]
3-element Array{Tuple{Array{Float64,1},Array{Float64,1}},1}:
 ([0.975749, 0.619872], [0.0326003, 0.389058])
 ([0.660932, 0.278402], [0.272455, 0.886105])
 ([0.391192, 0.799096], [0.713046, 0.950822])

конечно, вы также можете просто сделать это:

julia> map(i -> (Ws[:,i], Xs[:,i]), axes(Ws, 2))
3-element Array{Tuple{Array{Float64,1},Array{Float64,1}},1}:
 ([0.975749, 0.619872], [0.0326003, 0.389058])
 ([0.660932, 0.278402], [0.272455, 0.886105])
 ([0.391192, 0.799096], [0.713046, 0.950822])

или более необычно:

julia> (i -> (Ws[:,i], Xs[:,i])).(axes(Ws, 2))
3-element Array{Tuple{Array{Float64,1},Array{Float64,1}},1}:
 ([0.975749, 0.619872], [0.0326003, 0.389058])
 ([0.660932, 0.278402], [0.272455, 0.886105])
 ([0.391192, 0.799096], [0.713046, 0.950822])
...