Как заменить значения Inf на NaN в массиве в Julia 1.0? - PullRequest
0 голосов
/ 25 ноября 2018

Я видел в Интернете в нескольких местах решение

 a = [1 2 3; 4 5 Inf]
 a[isinf(a)] = NaN

Но это дает мне ошибку на Юлии 1.0.1:

 ERROR: MethodError: no method matching isinf(::Array{Float64,2})
 Closest candidates are:
   isinf(::BigFloat) at mpfr.jl:851
   isinf(::Missing) at missing.jl:79
   isinf(::ForwardDiff.Dual) at <path on my local machine>

Что дает?

Ответы [ 3 ]

0 голосов
/ 25 ноября 2018

РЕДАКТИРОВАТЬ: Для наиболее эффективных подходов к этой проблеме см. Отличный ответ @BogumilKaminski.Этот ответ обращается к более общему вопросу о том, почему isinf и связанные с ним функции больше не работают с массивами.

Вы столкнулись с более общей проблемой, заключающейся в том, что многие функции, работавшие с массивами до v1.0, больше не работают с массивами в v1.0, поскольку предполагается, что вы используете широковещательную рассылку.Правильное решение для v1.0:

a[isinf.(a)] .= NaN

Я здесь вещаю в двух местах.Во-первых, мы транслируем isinf по массиву a, но мы также транслируем скаляр NaN по RHS на все проиндексированные местоположения в массиве на LHS через .=.В общем, нотация точечного вещания невероятно гибкая и производительная, и одна из моих любимых функций в последней итерации Джулии.

0 голосов
/ 25 ноября 2018

В качестве дополнительного комментария.Стандартная функция для выполнения этого действия - replace!.Вы можете использовать его так:

julia>  a = [1 2 3; 4 5 Inf]
2×3 Array{Float64,2}:
 1.0  2.0    3.0
 4.0  5.0  Inf

julia> replace!(a, Inf=>NaN)
2×3 Array{Float64,2}:
 1.0  2.0    3.0
 4.0  5.0  NaN

Он будет работать лучше, чем широковещательная передача для больших массивов.

Если вам действительно нужна скорость, вы можете написать простую функцию, подобную этой:

function inf2nan(x)
    for i in eachindex(x)
        @inbounds x[i] = ifelse(isinf(x[i]), NaN, x[i])
    end
end

Теперь давайте просто сравним производительность трех вариантов:

julia> function bench()
           x = fill(Inf, 10^8)
           @time x[isinf.(x)] .= NaN
           x = fill(Inf, 10^8)
           @time replace!(x, Inf=>NaN)
           x = fill(Inf, 10^8)
           @time inf2nan(x)
       end
bench (generic function with 1 method)

julia> bench()
  0.980434 seconds (9 allocations: 774.865 MiB, 0.16% gc time)
  0.183578 seconds
  0.109929 seconds

julia> bench()
  0.971408 seconds (9 allocations: 774.865 MiB, 0.03% gc time)
  0.184163 seconds
  0.102161 seconds
0 голосов
/ 25 ноября 2018

Вы передаете весь свой массив в isinf, он не работает с массивами, он работает с числами.Попробуйте это:

[isinf(i) ? NaN : i for i in a]
...