Отсутствующие данные
В 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.