Spec-Zone.ru › Julia 1.6

Пропущенные значения

Julia предоставляет поддержку для представления пропущенных значений в статистическом смысле, то есть для ситуаций, когда для переменной в наблюдении нет значения, но теоретически существует действительное значение. Пропущенные значения представляются через объект missing, который является одиночным экземпляром типа Missing. missing эквивалентен NULL в SQL и NA в R, и ведет себя подобно им в большинстве ситуаций.

Распространение пропущенных значений

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

julia> missing + 1
missing

julia> "a" * missing
missing

julia> abs(missing)
missing

Поскольку missing является обычным объектом Julia, это правило распространения работает только для функций, которые выбрали реализовать такое поведение. Это можно достичь либо с помощью специального метода для аргументов типа Missing, либо просто приняв аргументы этого типа и передав их функциям, которые их распространяют (например, стандартные математические операторы). Пакеты должны учитывать, имеет ли смысл распространять пропущенные значения при определении новых функций, и определять соответствующие методы, если это необходимо. Передача missing значения функции, для которой нет метода, принимающего аргументы типа Missing, вызывает MethodError, как и для любого другого типа.

Функции, которые не распространяют missing значения, могут быть заменены на те, которые их распространяют, обернув их в функцию passmissing, предоставляемую пакетом Missings.jl. Например, f(x) становится passmissing(f)(x).

Операторы равенства и сравнения

Стандартные операторы равенства и сравнения следуют правилу распространения, представленному выше: если какой-либо из операндов является missing, результат является missing. Вот несколько примеров

julia> missing == 1
missing

julia> missing == missing
missing

julia> missing < 1
missing

julia> 2 >= missing
missing

В частности, обратите внимание, что missing == missing возвращает missing, поэтому == нельзя использовать для проверки того, отсутствует ли значение. Чтобы проверить, является ли x missing, используйте ismissing(x).

Специальные операторы сравнения isequal и === являются исключениями из правила распространения: они всегда возвращают Bool значение, даже при наличии missing значений, рассматривая missing как равные missing и отличными от любого другого значения. Таким образом, они могут быть использованы для проверки того, является ли значение missing

julia> missing === 1
false

julia> isequal(missing, 1)
false

julia> missing === missing
true

julia> isequal(missing, missing)
true

Оператор isless является еще одним исключением: missing считается больше любого другого значения. Этот оператор используется sort, поэтому помещает missing значения после всех других значений.

julia> isless(1, missing)
true

julia> isless(missing, Inf)
false

julia> isless(missing, missing)
false

Логические операторы

Логические (или булевы) операторы |, & и xor являются еще одним особым случаем, поскольку они распространяют missing значения только когда это логически необходимо. Для этих операторов неопределенность результата зависит от конкретной операции, следуя хорошо установленным правилам трехзначной логики, которые также реализованы в NULL в SQL и NA в R. Это абстрактное определение фактически соответствует относительно естественному поведению, которое лучше всего объясняется конкретными примерами.

Проиллюстрируем этот принцип на примере логического оператора «или» |. В соответствии с правилами булевой логики, если один из операндов является true, значение другого операнда не влияет на результат, который всегда будет true

julia> true | true
true

julia> true | false
true

julia> false | true
true

Исходя из этого наблюдения, можно заключить, что если один из операндов является true, а другой missing, мы знаем, что результат равен true несмотря на неопределенность относительно фактического значения одного из операндов. Если бы мы смогли наблюдать фактическое значение второго операнда, оно могло быть только true или false, и в обоих случаях результат был бы true. Следовательно, в этом конкретном случае пропущенность не распространяется

julia> true | missing
true

julia> missing | true
true

Напротив, если один из операндов является false, результат может быть либо true, либо false, в зависимости от значения другого операнда. Следовательно, если этот операнд missing, результат должен быть missing тоже

julia> false | true
true

julia> true | false
true

julia> false | false
false

julia> false | missing
missing

julia> missing | false
missing

Поведение логического оператора «и» & аналогично поведению оператора |, с той разницей, что пропущенность не распространяется, когда один из операндов является false. Например, когда это относится к первому операнду

julia> false & false
false

julia> false & true
false

julia> false & missing
false

С другой стороны, пропущенность распространяется, когда один из операндов является true, например, первый

julia> true & true
true

julia> true & false
false

julia> true & missing
missing

Наконец, логический оператор «исключающее или» xor всегда распространяет missing значения, поскольку оба операнда всегда влияют на результат. Также обратите внимание, что оператор отрицания ! возвращает missing, когда операнд является missing, как и другие унарные операторы.

Управляющие структуры и операторы короткого замыкания

Операторы управляющих структур, включая if, while и тернарный оператор x ? y : z не допускают пропущенных значений. Это связано с неопределенностью того, было бы фактическое значение true или false если бы мы могли его наблюдать, что подразумевает, что мы не знаем, как программа должна себя вести. TypeError выбрасывается при обнаружении missing значения в этом контексте

julia> if missing
           println("here")
       end
ERROR: TypeError: non-boolean (Missing) used in boolean context

По той же причине, в отличие от логических операторов, представленных выше, операторы короткого замыкания булевой логики && и || не допускают missing значений в ситуациях, когда значение операнда определяет, будет ли вычисляться следующий операнд или нет. Например

julia> missing || false
ERROR: TypeError: non-boolean (Missing) used in boolean context

julia> missing && false
ERROR: TypeError: non-boolean (Missing) used in boolean context

julia> true && missing && false
ERROR: TypeError: non-boolean (Missing) used in boolean context

С другой стороны, ошибка не выбрасывается, когда результат может быть определен без missing значений. Это происходит, когда код выполняет короткое замыкание до вычисления missing операнда, и когда missing операнд является последним

julia> true && missing
missing

julia> false && missing
false

Массивы с пропущенными значениями

Массивы, содержащие пропущенные значения, могут быть созданы как и другие массивы

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

Как показывает этот пример, тип элементов таких массивов — Union{Missing, T}, где T — тип ненулевых значений. Это просто отражает тот факт, что элементы массива могут быть либо типа T (здесь, Int64) либо типа Missing. Этот тип массива использует эффективное хранение памяти, эквивалентное Array{T} содержащему фактические значения в сочетании с Array{UInt8} указывающим тип элемента (т. е., является ли он Missing или T).

Массивы, допускающие пропущенные значения, могут быть созданы с помощью стандартной синтаксической конструкции. Используйте Array{Union{Missing, T}}(missing, dims) для создания массивов, заполненных пропущенными значениями:

julia> Array{Union{Missing, String}}(missing, 2, 3)
2×3 Matrix{Union{Missing, String}}:
 missing  missing  missing
 missing  missing  missing

Использование undef или similar в настоящее время может привести к массиву, заполненному missing, но это не правильный способ получить такой массив. Используйте конструктор missing вместо этого.

Массив, допускающий missing значения, но не содержащий таких значений, может быть преобразован обратно в массив, не допускающий пропущенных значений, с помощью convert. Если массив содержит missing значения, во время преобразования будет вызвано MethodError

julia> x = Union{Missing, String}["a", "b"]
2-element Vector{Union{Missing, String}}:
 "a"
 "b"

julia> convert(Array{String}, x)
2-element Vector{String}:
 "a"
 "b"

julia> y = Union{Missing, String}[missing, "b"]
2-element Vector{Union{Missing, String}}:
 missing
 "b"

julia> convert(Array{String}, y)
ERROR: MethodError: Cannot `convert` an object of type Missing to an object of type String

Пропуск пропущенных значений

Поскольку missing значения распространяются со стандартными математическими операторами, функции сокращения возвращают missing при вызове на массивах, содержащих пропущенные значения

julia> sum([1, missing])
missing

В этой ситуации используйте функцию skipmissing для пропуска пропущенных значений

julia> sum(skipmissing([1, missing]))
1

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

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

julia> maximum(x)
3

julia> mean(x)
2.0

julia> mapreduce(sqrt, +, x)
4.146264369941973

Объекты, созданные путем вызова skipmissing на массиве, могут быть индексированы с помощью индексов из родительского массива. Индексы, соответствующие пропущенным значениям, не являются допустимыми для этих объектов, и при попытке их использования возникает ошибка (они также пропускаются keys и eachindex).

julia> x[1]
3

julia> x[2]
ERROR: MissingException: the value at index (2,) is missing
[...]

Это позволяет функциям, которые работают с индексами, работать совместно с skipmissing. Это особенно актуально для функций поиска и нахождения, которые возвращают индексы, действительные для объекта, возвращаемого MethodError , которые также являются индексами соответствующих элементов в родительском массиве

julia> findall(==(1), x)
1-element Vector{Int64}:
 4

julia> findfirst(!iszero, x)
1

julia> argmax(x)
1

Используйте collect, чтобы извлечь значения, отличные от missing , и сохранить их в массиве

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

Логические операции над массивами

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

julia> [1, missing] == [2, missing]
false

julia> [1, missing] == [1, missing]
missing

julia> [1, 2, missing] == [1, missing, 2]
missing

Что касается отдельных значений, используйте isequal, чтобы рассматривать значения missing как равные другим значениям missing , но отличные от значений, не являющихся пропущенными

julia> isequal([1, missing], [1, missing])
true

julia> isequal([1, 2, missing], [1, missing, 2])
false

Функции any и all также следуют правилам трехзначной логики, возвращая missing , когда результат нельзя определить

julia> all([true, missing])
missing

julia> all([false, missing])
false

julia> any([true, missing])
true

julia> any([false, missing])
missing

© 2009–2021 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/v1.6.0/manual/missing/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API