Julia中missing、nothing、undef和NaN之间的用法和约定差异
我正在寻找一些关于何时在Julia中使用Julia中missing、nothing、undef和NaN之间的用法和约定差异,julia,Julia,我正在寻找一些关于何时在Julia中使用missing、nothing、undef和NaN的指导 例如,对于预分配数组或从try/catch返回,所有这些似乎都是合理的选择。我将这些选项总结如下。我写的是从“阅读价值观”的角度出发,但这也是“写作价值观”的指导 nothing表示“值不存在”(例如,findfirst在集合中找不到值时返回nothing);它是一个单独的类型Nothing missing表示“值本身存在,但我们不知道它”(我希望通常只有从外部来源获取数据时,数据中才会出现miss
missing
、nothing
、undef
和NaN
的指导
例如,对于预分配数组或从
try
/catch
返回,所有这些似乎都是合理的选择。我将这些选项总结如下。我写的是从“阅读价值观”的角度出发,但这也是“写作价值观”的指导
nothing
表示“值不存在”(例如,findfirst
在集合中找不到值时返回nothing
);它是一个单独的类型Nothing
missing
表示“值本身存在,但我们不知道它”(我希望通常只有从外部来源获取数据时,数据中才会出现missing
,例如,您有患者数据记录,体温缺失(显然存在-只是没有记录);我不认为Base中的任何函数都可以返回它,除非它得到缺少作为参数);它是一个单独的类型缺失
NaN
-只是一个数字数据(与无
和缺失
相反);如果对数值的某些操作的结果返回了NaN
,它会向用户发出信号;根据我的经验,这是数据中出现NaN
的唯一情况(例如0/0
)undef
不是您将看到的值,它仅以Vector{Int}(undef,10)
等形式使用,以创建数组而不初始化其值(因此这只是性能优化);只有当您立即想要用一些您计划计算的值初始化数组的元素时,才应该使用它(如果数组的元素类型不是位类型或位类型的并集,则使用undef
将导致#undef
项;对于位类型,使用undef
初始化数组只会产生一些垃圾)NaN
来表示集合中的缺失
或无
。这不是推荐的做法,但它有一个好处,您可以在本例中看到:
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
。在某些情况下,您可能希望选择x1
而不是x2
,因为执行操作要快一点对照(例如,检查缺失的可能性
的开销最小)但这是一种通常不应该进行的性能优化,因为其他人在阅读Julia code时通常认为NaN
是真正的NaN
,而不是表示缺失或无内容的占位符
- 如果您从事统计工作,则可能希望
missing
表示集合中缺少特定数据
- 如果要定义浮点数数组,但稍后初始化单个元素,出于性能原因,可能需要使用
unde
(以避免花费时间将元素设置为一个值,该值将在以后被覆盖):
在相同的情况下,但遵循一种不太注重性能而更注重安全的方法,您还可以将所有元素初始化为NaN
,以便利用NaN
的传播行为来帮助识别在忘记在数组中设置某个值时可能发生的错误:
fill(NaN, n)
- 在Julia的API的某些部分中,您可能会遇到
nothing
,表示无法计算有意义的值的情况。但它通常不用于包含数字数据的数组(这里似乎是您的用例)
以下是我对这些选项之间差异的看法:
missing
用于表示统计意义上的值,即理论上存在但您不知道的值。missing
在精神上(在大多数情况下在行为上)与R中类似。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
missing # (as a consequence of not knowing the value of y
missing
的一个重要特征是它有自己的特定类型:missing
。这特别意味着在其他数值中包含missing
值的数组在类型上是不一致的:
julia> [1, missing, 3]
3-element Array{Union{Missing, Int64},1}: # not Array{Int64, 1}
1
missing
3
请注意,尽管Julia编译器已经非常擅长处理此类小型联合的异构数组,但具有不同类型的元素存在固有的性能问题,因为我们无法提前知道元素的类型
nothing
也有自己的类型:nothing
。与missing
相比,它往往用于。这就是为什么与missing
相比,使用nothing
进行计算没有意义,并且出错的原因:
julia> 3*nothing
ERROR: MethodError: no method matching *(::Int64, ::Nothing)
nothing
主要用作不返回任何内容的函数的返回值,这可能是因为它们只有副作用,也可能是因为它们无法计算任何有意义的结果:
julia> @show println("OK") # Only side effects
OK
println("OK") = nothing
julia> @show findfirst('a', "Hello") # No meaningful result
findfirst('a', "Hello") = nothing
nothing
的另一个值得注意的用法是在函数参数或对象字段中,不总是为其提供值。这通常在类型系统中表示为联合{MeaningfulType,nothing}
julia> @show println("OK") # Only side effects
OK
println("OK") = nothing
julia> @show findfirst('a', "Hello") # No meaningful result
findfirst('a', "Hello") = nothing
struct TreeNode
child1 :: Union{TreeNode, Nothing}
child2 :: Union{TreeNode, Nothing}
end
leaf = TreeNode(nothing, nothing)
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> Vector{Float64}(undef, 3)
3-element Array{Float64,1}:
6.94567437726575e-310
6.94569509953624e-310
6.94567437549977e-310
julia> mutable struct Foo end
julia> Vector{Foo}(undef, 3)
3-element Array{Foo,1}:
#undef
#undef
#undef