Как написать функцию в Julia v1.1, которая вводит многомерный массив? - PullRequest
0 голосов
/ 01 февраля 2019

Я пытаюсь написать функцию в Julia, которая принимает многомерный массив (куб данных) и изменяет масштаб каждой записи от 0 до 1. Однако всякий раз, когда я запускаю код в atom, я получаю ошибку

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, и я просто хочу изменить масштаб записей с нуля до единицы.Тем не менее, ошибка, которую я упомянул, продолжает появляться.Я был бы очень признателен за любую помощь с этим кодом!

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Этот код немного быстрее и проще (он делает только два прохода по входной матрице, а не пять в предыдущем ответе):

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))

Это тоже не самое быстрое решение, по причинам, которые я не понимаю.Я действительно думаю, что это должно быть быстро и может быть ускорено в будущей версии Джулии.

0 голосов
/ 01 февраля 2019

Попробуйте использовать точечный синтаксис для выполнения некоторых операций в массиве!

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