如何在Julia 1.0中用数组中的NaN替换Inf值?

如何在Julia 1.0中用数组中的NaN替换Inf值?,julia,Julia,我在网上看到了一些解决方案 a = [1 2 3; 4 5 Inf] a[isinf(a)] = NaN 但这给了我一个关于Julia 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 is

我在网上看到了一些解决方案

 a = [1 2 3; 4 5 Inf]
 a[isinf(a)] = NaN
但这给了我一个关于Julia 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>
ERROR:MethodError:没有与isinf匹配的方法(::数组{Float64,2})
最接近的候选人是:
在mpfr.jl:851处的isinf(::BigFloat)
isinf(::缺失)位于缺失处。jl:79
isinf(::ForwardDiff.Dual)位于

给出了什么?

您正在将整个数组传递给isinf,它对数组无效,对数字有效。试试这个:

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

编辑:有关此问题最有效的解决方法,请参阅@BogumilKaminski的优秀答案。这个答案解决了一个更一般的问题,即为什么
isinf
和相关函数不再在阵列上工作

您遇到了一个更普遍的问题,即v1.0之前在阵列上工作的许多函数不再在v1.0中的阵列上工作,因为您应该使用广播。v1.0的正确解决方案是:

a[isinf.(a)] .= NaN

我实际上在这里的两个地方广播。首先,我们在数组
a
上广播
isinf
,但我们也通过
=
将RHS上的标量
NaN
广播到LHS上数组中的所有索引位置。一般来说,点广播符号是难以置信的灵活和性能,也是我最喜欢的Julia最新版本的特征之一

作为补充评论。执行此操作的标准功能是
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>  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

这实际上创建了一个新数组,而不是更新当前数组。更多细节请参见我的答案。是的,很公平,你的答案更好。这是一个非常有用的答案。我键入我的答案时没有考虑到
isinf.(x)
将分配的事实。是的,在Julia中-相反,例如R-如果需要性能,通常会希望避免分配二进制向量来执行子集设置。在这种特殊情况下,循环比
replace在这种情况下,因为我们可以使用
ifelse
避免循环中的分支,并且由于我们执行的操作简单且
@inbounds
编译器可以显著优化其执行时间。非常有趣,感谢您的解释。我将引导读者阅读您的答案,但请保留我的答案,因为它解决了问题中想知道为什么
isinf
不再适用于数组的部分。您的答案是90%情况下最简单的方法,它足够好,并且是您需要知道的全部,所以+1:)。