Julia中missing,nothing,undef和NaN之间的用法和约定差异

问题描述 投票:4回答:2

我正在寻找有关何时在Julia中使用missingnothingundefNaN的一些指导。

例如,对于预分配数组或从try / catch返回,似乎都是合理的选择。

julia
2个回答
3
投票

TLDR:

  • 如果您从事统计工作,可能是希望missing表示集合中没有特定数据。

  • 如果要定义浮点数数组,但稍后再初始化单个元素,则出于性能方面的考虑,可能要使用undef(以避免花时间将元素设置为一个值,此后将被覆盖):

    Vector{Float64}(undef, n)
    

    [对于性能不太注重而对安全性更高的方法,您也可以将所有元素初始化为NaN,以便利用Nan的传播行为来帮助识别如果忘记设置一些错误可能会发生的错误。数组中的值:

    fill(NaN, n)
    
  • 您可能会在Julia自己的API的某些部分遇到nothing,但通常不会在数组中使用它,否则会获取数字数据(这里似乎是您的用例)


这是我对这些选项之间的区别的看法:

missing用于以统计意义表示missing values,即理论上存在的值,但您不知道。 missing的实质(在大多数情况下,在行为上)与R中的NA相似。NA值的定义特征是可以在计算中使用它们:

missing

julia> x = 1 # x has a known value: 1 1 julia> y = missing # y has a value, but it is unknown missing julia> z = x * y # no error: z has a value, that just happens to be unknown (as a consequence of not knowing the value of y missing 的一个重要特征是它具有自己的特定类型:missing。特别是这意味着包含Missing值和其他数值的数组在类型上不是同质的:

missing


julia> [1, missing, 3] 3-element Array{Union{Missing, Int64},1}: # not Array{Int64, 1} 1 missing 3 也有自己的类型:nothing。与Nothing相比,它倾向于用于没有价值的事物。这就是为什么与missing相比,使用missing进行计算没有意义,并且出错的原因:

nothing

julia> 3*nothing ERROR: MethodError: no method matching *(::Int64, ::Nothing) 主要用作不返回任何东西的函数的返回值,要么是因为它们仅具有副作用,要么是因为它们无法计算任何其他有意义的结果:

nothing

另一个julia> typeof(println("OK")) # Only side effects OK Nothing julia> typeof(findfirst('a', "Hello")) # No other meaningful result Nothing 位于函数参数或对象字段中,但不能始终为其提供值。例如,在下面对二叉树结构的定义中,叶子(按照定义,它是没有子节点的节点)将被表示为其子节点为notable use of nothing的节点:

nothing


与前两个nothing不同,它没有自己的特定类型。 struct TreeNode child1 :: Union{TreeNode, Nothing} child2 :: Union{TreeNode, Nothing} end leaf = TreeNode(nothing, nothing) 仅仅是NaN类型的特定值(并且NaN类似地存在于Float64中)。您可能知道,这些值在浮点运算中确实具有特殊含义,这使它们传播(与NaN32值大致相同)。但是除了算术行为外,这些都是正常的浮点值。特别是,浮点值的向量可以包含Float32,而不会影响其类型:

missing


NaN与到目前为止提到的所有内容都非常不同。它不是一个真正的值(至少不是在具有值的数字的意义上),而是一个“标志”,可以将其传递给数组构造函数以告诉Julia不要初始化数组中的值(通常出于性能考虑) )。在下面的示例中,数组元素将不会设置为任何特定值,但是,由于在Julia中不存在没有任何值的数字之类的东西,因此元素将具有任意值(来自向量在内存中发生的一切)被分配)。

julia> [1., NaN, 2.]
3-element Array{Float64,1}: # Note how this differs from the example with missing above
 1.0
 NaN
 2.0

[当元素具有更复杂的类型并且已初始化和未初始化的元素之间存在区别时,Julia用undef表示后者

julia> Vector{Float64}(undef, 3)
3-element Array{Float64,1}:
 6.94567437726575e-310
 6.94569509953624e-310
 6.94567437549977e-310

2
投票

我将总结以下选项。我写的是从“读取值”的角度来看的,但这也是“写入值”时的指导。

  1. #undef表示“ 该值不存在”(例如,julia> mutable struct Foo end julia> Vector{Foo}(undef, 3) 3-element Array{Foo,1}: #undef #undef #undef 在集合中找不到值时返回nothing);它是单独的类型findfirst
  2. nothing的意思是“ 值本身存在,但我们不知道它>”(我希望通常只有从外部来源获取数据时,您才能在数据中获得Nothing。缺少患者数据和体温的记录(显然它存在-只是没有记录);我不认为Base的任何函数都可以返回它,除非它以missing作为参数。它是单独的类型missing
  3. missing-仅仅是数字数据(与MissingNaN相反);如果对返回的数字值进行某些运算的结果,则向用户发出信号;根据我的经验,这是nothing应该出现在数据中的唯一情况(例如missing的结果)
  4. NaN不是您会看到的值,它仅以例如NaN创建数组而不初始化其值(因此,这只是性能优化);仅当您要立即使用计划计算的某些值初始化数组的元素时,才应使用它(并且如果数组的元素类型不是位类型或联合,则使用0/0将导致undef条目位类型;对于使用Vector{Int}(undef, 10)初始化数组的位类型,只会给您带来一些垃圾)

这些是标准规则。现在是一个例外(这是其他一些语言的典型做法),有时您可能希望使用undef来表示集合中的#undefundef。不建议这样做,但是它有一个好处,您可以在此示例中看到:

NaN

并且您可以看到missing是浮点值,nothing数组的元素类型只是julia> x1 = [1.0, NaN] 2-element Array{Float64,1}: 1.0 NaN julia> x2 = [1.0, missing] 2-element Array{Union{Missing, Float64},1}: 1.0 missing ,而在NaN数组中,元素类型是x1。在某些情况下,您可能希望选择Float64而不是x2,因为针对它执行操作会更快(例如,检查Union的可能性具有最小的开销)。但这是通常不应该执行的性能优化,因为其他人在阅读Julia代码时通常会认为x1是真正的x2,而不是表示missingNaN的占位符。

© www.soinside.com 2019 - 2024. All rights reserved.