2
2
3
3
4
4
"""
5
- MvBinnedDist <: Distribution{Multivariate,Continuous}
5
+ MvBinnedDist <: StatsBase. Distribution{Multivariate,Continuous}
6
6
7
- Wraps a multi-dimensional histograms and presents it as a binned multivariate
8
- distribution.
7
+ A binned multivariate distribution, usually derived from a histogram.
9
8
10
- Constructor :
9
+ Constructors :
11
10
12
- MvBinnedDist(h::Histogram{<:Real,N})
11
+ ```julia
12
+ MvBinnedDist(h::StatsBase.Histogram{<:Real,N})
13
+ MvBinnedDist{T<:Real}(h::StatsBase.Histogram{<:Real,N})
14
+ ```
15
+
16
+ You can convert a `MvBinnedDist` back to a histogram via
17
+
18
+ ```julia
19
+ convert(StatsBase.Histogram, dist::MvBinnedDist)
20
+ StatsBase.Histogram(dist::MvBinnedDist)
21
+ ```
13
22
"""
14
23
struct MvBinnedDist{
15
24
T <: Real ,
16
25
N,
17
- H <: Histogram{<:Real, N} ,
26
+ U <: Real ,
27
+ ET <: NTuple{N,AbstractVector{<:Real}} ,
18
28
VT <: AbstractVector{T} ,
19
- MT <: AbstractMatrix{T}
29
+ MT <: AbstractMatrix{T} ,
30
+ VU <: AbstractVector{U} ,
31
+ AU <: AbstractArray{U,N}
20
32
} <: Distributions.Distribution{Multivariate,Continuous}
21
- hist :: H
22
- _edges :: NTuple{N, <:AbstractVector{T}}
23
- _cart_inds :: CartesianIndices{N, NTuple{N, Base.OneTo{Int}}}
24
- _probability_edges :: VT
33
+ _edges :: ET
34
+ _bin_pdf :: AU
35
+ _bin_linidx_cdf :: VU
36
+ _closed_left :: Bool
25
37
_mean:: VT
26
38
_mode:: VT
27
39
_var:: VT
31
43
export MvBinnedDist
32
44
33
45
34
- function MvBinnedDist (h:: StatsBase. Histogram{<:Real, N} , T :: DataType = Float64 ) where {N }
46
+ function MvBinnedDist {T} (h:: Histogram{<:Real} ) where {T <: Real }
35
47
nh = normalize (h)
36
48
37
- probabilty_widths = nh. weights * inv (sum (nh. weights))
38
- probabilty_edges:: Vector{T} = Vector {Float64} (undef, length (h. weights) + 1 )
39
- probabilty_edges[1 ] = 0
40
- for (i, w) in enumerate (probabilty_widths)
41
- v = probabilty_edges[i] + probabilty_widths[i]
42
- probabilty_edges[i+ 1 ] = v > 1 ? 1 : v
43
- end
49
+ edges = nh. edges
50
+ bin_pdf = nh. weights
51
+
52
+ closed_left = nh. closed == :left
53
+
54
+ Y = nh. weights
55
+ X = _bin_centers .(nh. edges)
56
+ W = _bin_widths .(nh. edges)
57
+
58
+ bin_linidx_cdf = cumsum (broadcast (idx -> Y[idx] .* prod (map (getindex, W, idx. I)), vec (CartesianIndices (Y))))
59
+ @assert last (bin_linidx_cdf) ≈ 1
60
+ bin_linidx_cdf[end ] = 1
44
61
45
- mean_est = _mean (h)
46
- mode_est = _mode (nh)
47
- var_est = _var (h, mean = mean_est)
48
- cov_est = _cov (h, mean = mean_est)
62
+ mean_est_tpl = _mean (nh)
63
+ mean_est = [T .(mean_est_tpl)... ]
64
+ mode_est = [T .(_mode (nh))... ]
65
+ var_est = [T .(_var (nh, mean_est_tpl))... ]
66
+ cov_est = T .(_cov (nh, mean_est_tpl))
49
67
50
68
return MvBinnedDist (
51
- nh,
52
- collect .(nh. edges),
53
- CartesianIndices (nh. weights),
54
- probabilty_edges,
55
- mean_est,
56
- mode_est,
57
- var_est,
58
- cov_est
69
+ edges, bin_pdf, bin_linidx_cdf, closed_left,
70
+ mean_est, mode_est, var_est, cov_est
59
71
)
60
72
end
61
73
74
+ MvBinnedDist (h:: Histogram{<:Real} ) = MvBinnedDist {float(promote_type(map(eltype, h.edges)...))} (h)
62
75
63
- Base. convert (:: Type{Histogram} , d:: MvBinnedDist ) = d. hist
76
+
77
+ function Adapt. adapt_structure (to, d:: MvBinnedDist )
78
+ MvBinnedDist (
79
+ map (e -> adapt (to, e), d. _edges), adapt (to, d. _bin_pdf), adapt (to, d. _bin_linidx_cdf),
80
+ adapt (to, d. _closed_left), adapt (to, d. _mean), adapt (to, d. _mode), adapt (to, d. _var), adapt (to, d. _cov)
81
+ )
82
+ end
64
83
65
84
66
- Base. length (d:: MvBinnedDist{T, N} ) where {T, N} = N
67
- Base. size (d:: MvBinnedDist{T, N} ) where {T, N} = (N,)
68
- Base. eltype (d:: MvBinnedDist{T, N} ) where {T, N} = T
85
+ Histogram (d:: MvBinnedDist ) = Histogram (map (Array, d. _edges), Array (d. _bin_pdf), (d. _closed_left ? :left : :right ), true )
86
+ Base. convert (:: Type{Histogram} , d:: MvBinnedDist ) = Histogram (d)
69
87
70
- Statistics. mean (d:: MvBinnedDist{T, N} ) where {T, N} = d. _mean
71
- StatsBase. mode (d:: MvBinnedDist{T, N} ) where {T, N} = d. _mode
72
- Statistics. var (d:: MvBinnedDist{T, N} ) where {T, N} = d. _var
73
- Statistics. cov (d:: MvBinnedDist{T, N} ) where {T, N} = d. _cov
74
88
89
+ Base. length (d:: MvBinnedDist{T,N} ) where {T,N} = N
90
+ Base. size (d:: MvBinnedDist{T,N} ) where {T,N} = (N,)
91
+ Base. eltype (d:: MvBinnedDist{T,N} ) where {T,N} = T
75
92
76
- function Distributions. _rand! (r:: AbstractRNG , d:: MvBinnedDist{T,N} , A:: AbstractVector{<:Real} ) where {T, N}
77
- rand! (r, A)
78
- next_inds:: UnitRange{Int} = searchsorted (d. _probability_edges:: Vector{T} , A[1 ]:: T )
79
- cell_lin_index:: Int = min (next_inds. start, next_inds. stop)
80
- cell_car_index = d. _cart_inds[cell_lin_index]
81
- for idim in Base. OneTo (N)
82
- i = cell_car_index[idim]
83
- sub_int = d. _edges[idim][i: i+ 1 ]
84
- sub_int_width:: T = sub_int[2 ] - sub_int[1 ]
85
- A[idim] = sub_int[1 ] + sub_int_width * A[idim]
93
+ Statistics. mean (d:: MvBinnedDist ) = d. _mean
94
+ StatsBase. mode (d:: MvBinnedDist ) = d. _mode
95
+ Statistics. var (d:: MvBinnedDist ) = d. _var
96
+ Statistics. cov (d:: MvBinnedDist ) = d. _cov
97
+
98
+
99
+ function Distributions. _rand! (rng:: AbstractRNG , d:: MvBinnedDist{T,N} , A:: AbstractVector{<:Real} ) where {T,N}
100
+ @assert length (eachindex (A)) == N
101
+ u = rand (rng)
102
+ i = searchsortedfirst (d. _bin_linidx_cdf, u)
103
+ idx_lo = CartesianIndices (d. _bin_pdf)[i]
104
+ idx_hi = idx_lo + CartesianIndex (1 , 1 )
105
+ x_lo = map (getindex, d. _edges, idx_lo. I)
106
+ x_hi = map (getindex, d. _edges, idx_hi. I)
107
+ for i in 1 : N
108
+ A[i] = _rand_uniform (rng, T, x_lo[i], x_hi[i])
86
109
end
87
110
return A
88
111
end
89
112
90
- function Distributions. _rand! (r :: AbstractRNG , d:: MvBinnedDist{T,N} , A:: AbstractMatrix{<:Real} ) where {T, N}
91
- Distributions. _rand! .((r, ), (d,), nestedview (A))
113
+ function Distributions. _rand! (rng :: AbstractRNG , d:: MvBinnedDist{T,N} , A:: AbstractMatrix{<:Real} ) where {T,N}
114
+ Distributions. _rand! .(Ref (rng ), (d,), nestedview (A))
92
115
return A
93
116
end
94
117
@@ -104,17 +127,24 @@ end
104
127
end
105
128
106
129
107
- function Distributions. pdf (d:: MvBinnedDist{T,N} , x:: AbstractVector{<:Real} ) where {T,N}
130
+ function Distributions. pdf (d:: MvBinnedDist{T,N,U } , x:: AbstractVector{<:Real} ) where {T,N,U }
108
131
length (eachindex (x)) == N || throw (ArgumentError (" Length of variate doesn't match dimensionality of distribution" ))
109
- x_tpl = _unsafe_unroll_tuple (x, Val (N))
110
- _pdf (d. hist, x_tpl)
132
+ xs = _unsafe_unroll_tuple (x, Val (N))
133
+
134
+ idxs = _find_bin (d. _edges, d. _closed_left, xs)
135
+ if checkbounds (Bool, d. _bin_pdf, idxs... )
136
+ @inbounds r = d. _bin_pdf[idxs... ]
137
+ convert (U, r)
138
+ else
139
+ zero (U)
140
+ end
111
141
end
112
142
113
143
114
- function Distributions. logpdf (d:: MvBinnedDist{T, N} , x:: AbstractArray{<:Real, 1} ) where {T, N}
144
+ function Distributions. logpdf (d:: MvBinnedDist{T,N} , x:: AbstractArray{<:Real, 1} ) where {T,N}
115
145
return log (pdf (d, x))
116
146
end
117
147
118
- function Distributions. _logpdf (d:: MvBinnedDist{T,N} , x:: AbstractArray{<:Real, 1} ) where {T, N}
148
+ function Distributions. _logpdf (d:: MvBinnedDist{T,N} , x:: AbstractArray{<:Real, 1} ) where {T,N}
119
149
return logpdf (d, x)
120
150
end
0 commit comments