Julia语言想在数据分析领域分一杯羹还需要做很多的事情,其中一个事情就算对缺失值的处理。在数据分析中,观测样本存在缺失值是非常常见的,如果一个分析工具缺少应对机制,那么这个工具用起来会磕磕绊绊。
R语言的缺失值处理
R语言自上个世纪90年代起步,发展历史较长,所以对缺失值的处理机制比较完善。
> a <- c(1,NA,2,3,NA)
> a
[1] 1 NA 2 3 NA
> a+1
[1] 2 NA 3 4 NA
> mean(a)
[1] NA
> mean(a,na.rm = T)
[1] 2
常见的数据结构是dataframe,那么在这类数据中存在缺失值该如何处理?
R的处理还是很便捷的,具体代码如下。
> df <- data.frame(a,b=LETTERS[1:5])
> df
a b
1 1 A
2 NA B
3 2 C
4 3 D
5 NA E
> mean(df[,"a"])
[1] NA
> mean(df[,"a"],na.rm = T)
[1] 2
原生的Julia
Julia原生对缺失值的表示和处理还不成熟。具体示例如下。
julia> a=[1 Nullable() 2 3 Nullable()]
1×5 Array{Nullable{Int64},2}:
1 #NULL 2 3 #NULL
julia> a+1
WARNING: a::AbstractArray + b::Number is deprecated, use broadcast(+, a, b) instead.
julia> broadcast(+, a, 1)
ERROR: MethodError: no method matching +(::Nullable{Int64}, ::Int64)
Closest candidates are:
+(::Any, ::Any, ::Any, ::Any...) at operators.jl:468
+(::Complex{Bool}, ::Real) at complex.jl:275
+(::Char, ::Integer) at char.jl:40
...
Nulls包的处理
现在是第三方包Nulls.jl来表示和处理缺失值。
julia> using Nulls
julia> a=[1 null 2 3 null]
1×5 Array{Union{Nulls.Null, Int64},2}:
1 null 2 3 null
julia> a+1
1×5 Array{Any,2}:
2 null 3 4 null
julia> mean(a)
null
这样,Julia对缺失值的表示和处理前进了一大步。不过,在R语言中NULL是表示空,NA是表示缺失值。
上面对含有缺失值的a向量求均值,结果为空。目前mean函数还没有对Null类型进行处理。
help?> mean
search: mean mean! median median! RemoteChannel SegmentationFault macroexpand @macroexpand @macroexpand1 module_parent
mean(f::Function, v)
Apply the function f to each element of v and take the mean.
julia> mean(√, [1, 2, 3])
1.3820881233139908
julia> mean([√1, √2, √3])
1.3820881233139908
mean(v[, region])
Compute the mean of whole array v, or optionally along the dimensions in region.
| Note
|
| Julia does not ignore NaN values in the computation. For applications requiring the handling of missing
| data, the DataArrays.jl package is recommended.
所以只能如下操作。Nulls.skip函数是由Nulls包提供。
julia> mean(Nulls.skip(a))
2.0
现在最新的DataFrames也转为Nulls包的方法来表示和处理缺失值。
julia> using DataFrames
julia> df = DataFrame(A = [1, null, 2, 3, null], B = ["a", "b", "c", "d", "e"])
5×2 DataFrames.DataFrame
│ Row │ A │ B │
├─────┼──────┼───┤
│ 1 │ 1 │ a │
│ 2 │ null │ b │
│ 3 │ 2 │ c │
│ 4 │ 3 │ d │
│ 5 │ null │ e │
julia> df[:A]
5-element Array{Union{Nulls.Null, Int64},1}:
1
null
2
3
null
julia> mean(df[:A])
null
julia> mean(Nulls.skip(df[:A]))
2.0
个人的猜想是等Julia自身或者第三方对缺失值的表示方法成熟稳定后,一些涉及处理可能出现缺失值的对象的函数应该增写方法(见Julia手册的Methods章节),以更简洁的方式处理此类对象。目前采用Nulls.skip方法应该不是长久之计。
进一步阅读
版本信息
R version 3.4.2 (2017-09-28) -- "Short Summer"
Julia
Version 0.7.0-DEV.2098 (2017-10-10 11:37 UTC)
Commit 546a801260* (16 days old master)
- DataFrames 0.10.1+ master
- Nulls 0.1.2+ master
其中Julia的第三方包是直接手动Clone最新的代码。
=========
补充:
现在Version 0.7.0-DEV.3095 (2017-12-19 01:41 UTC)中,missing已经成为Julia内置类型。原先的Nulls包也更名为Missings。
这样Julia更加适合统计与数据分析的场景。
# Version 0.7.0-DEV.3095 (2017-12-19 01:41 UTC)
julia> missing
missing
julia> missing + 1
missing
julia> true | missing
true
julia> false | missing
missing
julia> false & missing
false
julia> true & missing
missing
julia> sum([1,2,3,missing])
missing
julia> sum(skipmissing([1,2,3,missing]))
6