如何在Julia v1.1中编写输入多维数组的函数?

时间:2019-01-31 23:01:49

标签: function multidimensional-array julia

我试图用Julia编写一个函数,该函数采用多维数组(数据立方体),并将每个条目从0缩放到1。但是,每当我在原子中运行代码时,都会出现错误

LoadError: MethodError: no method matching -(::Array{Float64,2}, ::Float64)
Closest candidates are:
  -(::Float64, ::Float64) at float.jl:397
  -(::Complex{Bool}, ::Real) at complex.jl:298
  -(::Missing, ::Number) at missing.jl:97
  ...
Stacktrace:
[1] rescale_zero_one(::Array{Float64,2}) at D:\Julio\Documents\Michigan_v2\CS\EECS_598_Data_Science\codex\Codex_3\svd_video.jl:40
[2] top-level scope at D:\Julio\Documents\Michigan_v2\CS\EECS_598_Data_Science\codex\Codex_3\svd_video.jl:50 [inlined]
[3] top-level scope at .\none:0
in expression starting at D:\Julio\Documents\Michigan_v2\CS\EECS_598_Data_Science\codex\Codex_3\svd_video.jl:48

我具有函数必须执行的操作的基本知识,但是我真的不理解某些表示法以及错误说明或解决方法。

function rescale_zero_one(A::Array)
    B = float(A)
    B -= minimum(B)
    B /= maximum(B)
    return B
end

m,n,j = size(movie_cube)
println(j)
C = Array{Float64}(UndefInitializer(),m,n,j)
for k in 1:j
    println(k)
    C[:,:,j] = rescale_zero_one(movie_cube[:,:,j])
end

变量movie_cube是Float64条目的3维数据数组,我只想将条目从零重新缩放为一。但是,我提到的错误不断出现。我非常感谢您提供此代码的帮助!

2 个答案:

答案 0 :(得分:1)

尝试使用点语法在数组中执行某些操作!

function rescale_zero_one(A::Array)
    B = float.(A)
    B .-= minimum(B)
    B ./= maximum(B)
    return B
end

答案 1 :(得分:1)

这段代码更快,更简单(它只对输入矩阵进行两次传递,而不是先前答案中的五次传递):

function rescale(A::Matrix)
    (a, b) = extrema(A)
    return (A .- a) ./ (b - a)
end

这可以概括为三个维度,因此您不需要C中的维度上的外部循环。警告:此解决方案实际上有点慢,因为使用extrema关键字时maximum / minimum / dims的速度很慢,这很奇怪:

function rescale(A::Array{T, 3}) where {T}
    mm = extrema(A, dims=(1,2))
    a, b = first.(mm), last.(mm)
    return  (A .- a) ./ (b .- a)
end

现在您可以只写C = rescale(movie_cube)。您甚至可以进一步概括:

function rescale(A::Array{T, N}; dims=ntuple(identity, N)) where {T,N}
    mm = extrema(A, dims=dims)
    a, b = first.(mm), last.(mm)
    return  (A .- a) ./ (b .- a)
end

现在,您可以按照自己喜欢的任何维度对多维数组进行标准化。当前行为变为

C = rescale(movie_cube, dims=(1,2))

重新缩放每一行是

C = rescale(movie_cube, dims=(1,))

默认行为是重新缩放整个数组:

C = rescale(movie_cube)

还有一件事,这有点奇怪:

C = Array{Float64}(UndefInitializer(),m,n,j)

没错,但是更短更优雅的方式更常见:

C = Array{Float64}(undef, m, n, j)

您还可以考虑简单地写:C = similar(movie_cube)C = similar(movie_cube, Float64)

编辑:另一个通用的解决方案是不在rescale函数中实现尺寸处理,而要利用mapslices。然后:

function rescale(A::Array)
    (a, b) = extrema(A)
    return (A .- a) ./ (b - a)
end

C = mapslices(rescale, A, dims=(1,2))

由于我不了解的原因,这也不是最快的解决方案。我真的认为这应该很快,并且可能会在Julia的未来版本中加快。