Документация Engee

Отсутствующие данные

В Julia для представления отсутствующих значений используется особый объект missing, который является одинарным экземпляром типа Missing.

julia> missing
missing

julia> typeof(missing)
Missing

Тип Missing позволяет создавать векторы и столбцы DataFrame с отсутствующими значениями. Здесь мы создаем вектор с отсутствующим значением, а возвращаемый вектор имеет тип элемента Union{Missing, Int64}.

julia> x = [1, 2, missing]
3-element Vector{Union{Missing, Int64}}:
 1
 2
  missing

julia> eltype(x)
Union{Missing, Int64}

julia> Union{Missing, Int}
Union{Missing, Int64}

julia> eltype(x) == Union{Missing, Int}
true

Значения missing могут быть исключены при выполнении операций с помощью функции skipmissing, которая возвращает итератор, оптимально использующий память.

julia> skipmissing(x)
skipmissing(Union{Missing, Int64}[1, 2, missing])

Вывод skipmissing можно передавать напрямую в функции в качестве аргумента. Например, можно найти сумму (sum) всех существующих значений или собрать (collect) существующие значения в новый вектор без пропусков.

julia> sum(skipmissing(x))
3

julia> collect(skipmissing(x))
2-element Vector{Int64}:
 1
 2

Функцию coalesce можно использовать для замены отсутствующих значений другим значением (обратите внимание на точку, указывающую, что замена должна быть применена ко всем записям в x):

julia> coalesce.(x, 0)
3-element Vector{Int64}:
 1
 2
 0

Функции dropmissing и dropmissing! можно использовать для удаления строк, содержащих значения missing, из фрейма данных и создания нового DataFrame или изменения исходного фрейма данных на месте, соответственно.

julia> using DataFrames

julia> df = DataFrame(i=1:5,
                      x=[missing, 4, missing, 2, 1],
                      y=[missing, missing, "c", "d", "e"])
5×3 DataFrame
 Row │ i      x        y
     │ Int64  Int64?   String?
─────┼─────────────────────────
   1 │     1  missing  missing
   2 │     2        4  missing
   3 │     3  missing  c
   4 │     4        2  d
   5 │     5        1  e

julia> dropmissing(df)
2×3 DataFrame
 Row │ i      x      y
     │ Int64  Int64  String
─────┼──────────────────────
   1 │     4      2  d
   2 │     5      1  e

Можно указать столбец (столбцы), в котором нужно искать строки, содержащие значения missing, подлежащие удалению.

julia> dropmissing(df, :x)
3×3 DataFrame
 Row │ i      x      y
     │ Int64  Int64  String?
─────┼───────────────────────
   1 │     2      4  missing
   2 │     4      2  d
   3 │     5      1  e

По умолчанию функции dropmissing и dropmissing! сохраняют тип элемента Union{T, Missing} в столбцах, выбранных для удаления строк. Чтобы удалить часть Missing (если она имеется), задайте именованному аргументу disallowmissing значение true (в будущем это станет поведением по умолчанию).

julia> dropmissing(df, disallowmissing=true)
2×3 DataFrame
 Row │ i      x      y
     │ Int64  Int64  String
─────┼──────────────────────
   1 │     4      2  d
   2 │     5      1  e

Иногда бывает полезно разрешить или запретить поддержку отсутствующих значений в некоторых столбцах фрейма данных. Эти операции поддерживаются функциями allowmissing, allowmissing!, disallowmissing и disallowmissing!. Вот пример:

julia> df = DataFrame(x=1:3, y=4:6)
3×2 DataFrame
 Row │ x      y
     │ Int64  Int64
─────┼──────────────
   1 │     1      4
   2 │     2      5
   3 │     3      6

julia> allowmissing!(df)
3×2 DataFrame
 Row │ x       y
     │ Int64?  Int64?
─────┼────────────────
   1 │      1       4
   2 │      2       5
   3 │      3       6

Теперь df разрешает отсутствующие значения во всех своих столбцах. Можно воспользоваться этим фактом и задать некоторые значения в df как отсутствующие (missing), например:

julia> df[1, 1] = missing
missing

julia> df
3×2 DataFrame
 Row │ x        y
     │ Int64?   Int64?
─────┼─────────────────
   1 │ missing       4
   2 │       2       5
   3 │       3       6

Обратите внимание, что селектор столбцов можно передать в функции allowmissing и allowmissing! в качестве второго позиционного аргумента, чтобы ограничить изменение только некоторыми столбцами во фрейме данных.

Теперь выполним обратную операцию, запретив отсутствующие значения в df. Мы знаем, что столбец :y не содержит отсутствующие значения, поэтому можем использовать функцию disallowmissing, передав селектор столбцов в качестве второго позиционного аргумента:

julia> disallowmissing(df, :y)
3×2 DataFrame
 Row │ x        y
     │ Int64?   Int64
─────┼────────────────
   1 │ missing      4
   2 │       2      5
   3 │       3      6

Эта операция создала новый DataFrame. Если требуется обновить df на месте, следует использовать функцию disallowmissing!.

При попытке запретить отсутствующие значения во всем фрейме данных с помощью disallowmissing(df) возникнет ошибка. Однако часто целесообразно запретить отсутствующие значения во всех столбцах, которые их не содержат, но оставить столбцы, в которых есть значения missing, без изменений, не перечисляя их явным образом. Для этого можно передать именованный аргумента error=false:

julia> disallowmissing(df, error=false)
3×2 DataFrame
 Row │ x        y
     │ Int64?   Int64
─────┼────────────────
   1 │ missing      4
   2 │       2      5
   3 │       3      6

Пакет Missings.jl предоставляет несколько вспомогательных функций для работы с отсутствующими значениями.

Одной из самых распространенных является passmissing. Это функция более высокого порядка, которая принимает в качестве аргумента некоторую функцию f и возвращает новую функцию, которая возвращает missing, если любой из ее позиционных аргументов равен missing, и в противном случае применяет к этим аргументам функцию f. Эта функциональность полезна в сочетании с функциями, которые не поддерживают передачу значений missing в качестве своих аргументов. Например, попытка применить uppercase(missing) приведет к ошибке, а следующий вариант сработает:

julia> passmissing(uppercase)("a")
"A"

julia> passmissing(uppercase)(missing)
missing

Функция Missings.replace возвращает итератор, который заменяет элементы missing другим значением:

julia> using Missings

julia> Missings.replace(x, 1)
Missings.EachReplaceMissing{Vector{Union{Missing, Int64}}, Int64}(Union{Missing, Int64}[1, 2, missing], 1)

julia> collect(Missings.replace(x, 1))
3-element Vector{Int64}:
 1
 2
 1

julia> collect(Missings.replace(x, 1)) == coalesce.(x, 1)
true

Функция nonmissingtype возвращает тип элемента T в Union{T, Missing}.

julia> eltype(x)
Union{Missing, Int64}

julia> nonmissingtype(eltype(x))
Int64

Функция missings создает векторы (Vector) и массивы (Array), поддерживающие отсутствующие значения, используя необязательный первый аргумент для указания типа элемента.

julia> missings(1)
1-element Vector{Missing}:
 missing

julia> missings(3)
3-element Vector{Missing}:
 missing
 missing
 missing

julia> missings(1, 3)
1×3 Matrix{Missing}:
 missing  missing  missing

julia> missings(Int, 1, 3)
1×3 Matrix{Union{Missing, Int64}}:
 missing  missing  missing

Дополнительные сведения об отсутствующих значениях см. в руководстве по Julia.