Engee 文档
Notebook

Julia 中的缺失数据

简介

处理缺失数据是数据预处理中的一项常见任务。虽然有时缺失值表示数据中发生了有意义的事件,但它们往往代表了不可靠或不可用的数据点。在任何情况下,朱莉娅都有许多处理缺失数据的选项。

创建缺失数据

朱莉娅中,缺失数据可以用多种形式表示。例如,值NaN (NaN64) ( 非数字)

In [ ]:
x_64 = [NaN, 8, 15, 16, 23, 42]
println("Type of $(x_64[1]): ", typeof(x_64[1]))

x_64 = [NaN64, 8, 15, 16, 23, 42]
print("Type of $(x_64[1]): ", typeof(x_64[1]))
Type of NaN: Float64
Type of NaN: Float64

如有必要,可将NaN 指定为较小的浮点数:

In [ ]:
x_32 = [NaN32, 8, 15, 16, 23, 42]
Out[0]:
6-element Vector{Float32}:
 NaN
   8.0
  15.0
  16.0
  23.0
  42.0
In [ ]:
x_16 = [NaN16, 8, 15, 16, 23, 42]
Out[0]:
6-element Vector{Float16}:
 NaN
   8.0
  15.0
  16.0
  23.0
  42.0

谈到这种缺失数据表示形式的本质,我们可以得出这样的结论:这是浮点数据类型的具体值,在计算中具有传播能力。这些值通常是由于未定义的操作而出现的:

In [ ]:
x_nan = Inf*0
Out[0]:
NaN

通常,在 Julia 中,数值NaN 用于在计算中传播数值计算的不确定性。要具体处理缺失数据,更正确的做法是使用一个特殊对象missing ,它也在计算中传播。这种表示形式是Missing 类型的唯一实例:

In [ ]:
typeof(missing)
Out[0]:
Missing

这尤其意味着,包含missing 和其他值的数组在类型上是异构的:

In [ ]:
x_missing = [missing, 8, 15, 16, 23, 42]
Out[0]:
6-element Vector{Union{Missing, Int64}}:
   missing
  8
 15
 16
 23
 42

要处理missingMissings.jl 库可能会有用。因此,使用它可以创建包含此类对象的数组:

In [ ]:
import Pkg; Pkg.add("Missings") # загрузка библиотеки
In [ ]:
using Missings # подключение библиотеки

# создание массивов с отсутствующими значениями:
# массивы типа Missing
@show missings(1)
@show missings(3)
@show missings(3,1)

# массив объединения типов
@show missings(Int,3,3); 
missings(1) = [missing]
missings(3) = [missing, missing, missing]
missings(3, 1) = [missing; missing; missing;;]
missings(Int, 3, 3) = Union{Missing, Int64}[missing missing missing; missing missing missing; missing missing missing]

缺失数据的系统化

在对有缺失数据的数组进行排序时,请记住missing 的对象要比与之比较的任何对象都大:

In [ ]:
isless(Inf, missing)
Out[0]:
true

因此,缺失值将在排序时自动分离,并位于升序排序的末尾。如果您想在排序时更改缺失值的包含顺序,只需应用属性lt = missingsmallest 即可:

In [ ]:
sort(x_missing, rev=true, lt = missingsmallest)
Out[0]:
6-element Vector{Union{Missing, Int64}}:
 42
 23
 16
 15
  8
   missing

缺失数据归一化

让我们连接DataFrames.jlStatistics.jl库,查看处理表格数据中缺失数据的示例。

In [ ]:
Pkg.add(["DataFrames", "Statistics"])
using DataFrames, Statistics

让我们创建一个测试数据表进行处理:

In [ ]:
df_missing = DataFrame(
    имя     = ["NULL", "Коля", "Юра", "Миша"],
    возраст = [16, NaN, missing, 15],
    рост    = [171, 162, 999, 165],
)
Out[0]:
4×3 DataFrame
Rowимявозрастрост
StringFloat64?Int64
1NULL16.0171
2КоляNaN162
3Юраmissing999
4Миша15.0165

在处理合并到一个表中的不同格式的数据时,可能会出现缺失数据取值不同的情况。要使缺失数据的值标准化,可以使用Impute.jl库中的declaremissings() 函数:

In [ ]:
Pkg.add("Impute")
In [ ]:
using Impute

df_missing = Impute.declaremissings(df_missing; values=(NaN, 999, "NULL"))
Out[0]:
4×3 DataFrame
Rowимявозрастрост
String?Float64?Int64?
1missing16.0171
2Коляmissing162
3Юраmissingmissing
4Миша15.0165

现在,我们可以看到,缺失数据被简化为一种形式--对象missing

搜索缺失数据

要确定数值NaN ,可以方便地使用函数 isnan()

In [ ]:
isnan.(x_64)
Out[0]:
6-element BitVector:
 1
 0
 0
 0
 0
 0

还有一个类似函数 可以确定对象missing

In [ ]:
ismissing.(x_missing)
Out[0]:
6-element BitVector:
 1
 0
 0
 0
 0
 0

让我们来确定表格中缺失值的位置:

In [ ]:
df_mask = ismissing.(df_missing)
Out[0]:
4×3 DataFrame
Rowимявозрастрост
BoolBoolBool
1truefalsefalse
2falsetruefalse
3falsetruetrue
4falsefalsefalse

通常情况下,missing 会给数据处理带来问题。为此,可以省略、排除或替换这些对象。

跳过缺失数据

要过滤NaN 值的向量,只需使用 Julia 基础库中的 filter() 函数。

In [ ]:
filter(!isnan, x_64)
Out[0]:
5-element Vector{Float64}:
  8.0
 15.0
 16.0
 23.0
 42.0

如果使用对象missing 过滤数组,结果数组的类型不会改变。您可以使用 Missings.jl 库的 disallowmissing() 函数将数组类型转换为过滤值的类型。

In [ ]:
@show x = filter(!ismissing, x_missing)
disallowmissing(x)
x = filter(!ismissing, x_missing) = Union{Missing, Int64}[8, 15, 16, 23, 42]
Out[0]:
5-element Vector{Int64}:
  8
 15
 16
 23
 42

以下代码显示了如何使用函数filter() 从表格数据中筛选missing

In [ ]:
filter(:имя => !ismissing, df_missing)
Out[0]:
3×3 DataFrame
Rowимявозрастрост
String?Float64?Int64?
1Коляmissing162
2Юраmissingmissing
3Миша15.0165

应用基础库中的 skipmissing() 函数也能得到同样的结果:

In [ ]:
collect(skipmissing(x_missing))
Out[0]:
5-element Vector{Int64}:
  8
 15
 16
 23
 42

要跳过表格数据中的missingDataFrames.jl 库有一个更方便的函数 - dropmissing()

In [ ]:
dropmissing(df_missing)
Out[0]:
1×3 DataFrame
Rowимявозрастрост
StringFloat64Int64
1Миша15.0165

为了过滤掉missing 包含在特定列中的行,该函数的第二个参数是该列的名称:

In [ ]:
dropmissing(df_missing, :имя)
Out[0]:
3×3 DataFrame
Rowимявозрастрост
StringFloat64?Int64?
1Коляmissing162
2Юраmissingmissing
3Миша15.0165

在这种情况下,函数dropmissing() 将返回一个新表。如果不需要为要解决的任务保存原始表,可以使用 dropmissing!() 删除数据缺失的行。

替换缺失数据

如果需要替换数组中的缺失数据,使用函数Missings.replace() 会很方便:

In [ ]:
рост = collect(Missings.replace(df_missing.рост, 170))
Out[0]:
4-element Vector{Int64}:
 171
 162
 170
 165

要替换表格中的缺失数据,可以使用函数replace!()

In [ ]:
replace!(df_missing.возраст, missing => 15)
Out[0]:
4-element Vector{Union{Missing, Float64}}:
 16.0
 15.0
 15.0
 15.0

请注意,结果列的数据格式不会改变。另一种方法是使用函数coalesce()

In [ ]:
df_missing.имя = coalesce.(df_missing.имя, "Ваня")
df_missing.рост = coalesce.(df_missing.рост, mean(skipmissing(df_missing.рост)))
df_missing
Out[0]:
4×3 DataFrame
Rowимявозрастрост
StringFloat64?Real
1Ваня16.0171
2Коля15.0162
3Юра15.0166.0
4Миша15.0165

结论

本案例研究探讨了如何在 Julia 中创建、组织、规范化、搜索、查找、跳过和替换缺失数据。