Создание сэмплеров и распределений
Хотя данный пакет уже содержит большую коллекцию готовых распределений, возможны ситуации, когда необходимо создать собственное распределение (например, если в приложении требуется распределение особого типа или вы хотите внести свой вклад в пакет).
Как правило, не требуется реализовывать каждый метод API, описанный в документации. Данный пакет предоставляет ряд универсальных функций, которые превращают небольшой набор внутренних методов в доступные пользователям методы API. Достаточно реализовать этот ограниченный набор внутренних методов для своих распределений.
По умолчанию поддерживающие выборку объекты Discrete
поддерживают тип Int
, а поддерживающие выборку объекты Continuous
— тип Float64
. Если это допущение не соблюдается для вашего нового распределения или сэмплера либо если его тип ValueSupport
отличен от Discrete
и Continuous
, в дополнение к перечисленным ниже методам следует также реализовать метод eltype
.
Примечание. Методы, требующие реализации, различаются в зависимости от размерности распределения.
Создание сэмплера
В отличие от полноценных распределений, сэмплер, как правило, предоставляет ограниченные возможности, в первую очередь связанные с выборкой.
Одномерный сэмплер
Чтобы реализовать одномерный сэмплер, можно определить подтип (например, Spl
) типа Sampleable{Univariate,S}
(где S
может быть Discrete
или Continuous
) и предоставить метод rand
:
function rand(rng::AbstractRNG, s::Spl)
# ... генерируем одну выборку из s
end
В пакете уже реализована векторизированная версия функций rand!
и rand
, которая многократно вызывает скалярную версию для генерирования нескольких выборок, а также версия с одним аргументом, которая использует генератор случайных чисел по умолчанию.
Многомерный сэмплер
Чтобы реализовать многомерный сэмплер, можно определить подтип типа Sampleable{Multivariate,S}
и предоставить методы length
и _rand!
:
Base.length(s::Spl) = ... # возвращаем длину каждой выборки
function _rand!(rng::AbstractRNG, s::Spl, x::AbstractVector{T}) where T<:Real
# ... генерируем одну векторную выборку из x
end
Эта функция может предполагать, что измерение x
верное и выполнять проверку измерений не нужно.
В пакете функции rand
и rand!
реализованы следующим образом (в общем случае реализовывать их самостоятельно не нужно):
function _rand!(rng::AbstractRNG, s::Sampleable{Multivariate}, A::DenseMatrix)
for i = 1:size(A,2)
_rand!(rng, s, view(A,:,i))
end
return A
end
function rand!(rng::AbstractRNG, s::Sampleable{Multivariate}, A::AbstractVector)
length(A) == length(s) ||
throw(DimensionMismatch("Output size inconsistent with sample length."))
_rand!(rng, s, A)
end
function rand!(rng::AbstractRNG, s::Sampleable{Multivariate}, A::DenseMatrix)
size(A,1) == length(s) ||
throw(DimensionMismatch("Output size inconsistent with sample length."))
_rand!(rng, s, A)
end
rand(rng::AbstractRNG, s::Sampleable{Multivariate,S}) where {S<:ValueSupport} =
_rand!(rng, s, Vector{eltype(S)}(length(s)))
rand(rng::AbstractRNG, s::Sampleable{Multivariate,S}, n::Int) where {S<:ValueSupport} =
_rand!(rng, s, Matrix{eltype(S)}(length(s), n))
Если есть более эффективный способ генерирования нескольких векторных выборок за один раз, следует предоставить следующий метод:
function _rand!(rng::AbstractRNG, s::Spl, A::DenseMatrix{T}) where T<:Real
# ... генерируем несколько векторных выборок за один раз
end
Напомним, что каждый столбец A — это выборка.
Сэмплер матричной размерности
Чтобы реализовать многомерный сэмплер, можно определить подтип типа Sampleable{Multivariate,S}
и предоставить методы size
и _rand!
:
Base.size(s::Spl) = ... # размер каждой матричной выборки
function _rand!(rng::AbstractRNG, s::Spl, x::DenseMatrix{T}) where T<:Real
# ... генерируем одну матричную выборку из x
end
Обратите внимание: в _rand!
может предполагаться, что x
имеет правильные измерения и что выполнять проверку измерений не нужно. Универсальные функции rand
и rand!
будут автоматически выполнять проверку измерений и выделение памяти для массивов.
Создание распределения
Большинство распределений должны реализовывать метод sampler
для повышения эффективности пакетной выборки.
#
Distributions.sampler
— Method
sampler(d::Distribution) -> Sampleable
sampler(s::Sampleable) -> s
Сэмплеры часто используют предварительно вычисленные значения (сами по себе не являющиеся параметрами) для повышения эффективности. Для такого сэмплера можно предоставить метод sampler
, который будет использоваться для пакетной выборки. Общий резервный метод — sampler(d::Distribution) = d
.
Одномерное распределение
Тип одномерного распределения должен определяться как подтип типа DiscreteUnivarateDistribution
или ContinuousUnivariateDistribution
.
Для каждого типа одномерного распределения необходимо реализовать следующие методы:
Кроме того, рекомендуется реализовать следующие статистические функции.
Узнать в подробностях, как реализованы универсальные функции для одномерных распределений, можно в файле исходного кода src/univariates.jl
.
Создание многомерного распределения
Тип многомерного распределения должен определяться как подтип типа DiscreteMultivarateDistribution
или ContinuousMultivariateDistribution
.
Для каждого типа многомерного распределения необходимо реализовать следующие методы:
Обратите внимание: если существуют более быстрые методы пакетных вычислений, следует переопределить _logpdf!
и _pdf!
.
Кроме того, универсальная функция loglikelihood
многократно вызывает _logpdf
. Если есть более эффективный способ вычисления логарифмического правдоподобия, следует переопределить loglikelihood
.
Кроме того, рекомендуется реализовать следующие статистические функции.