Skip to content

Commit

Permalink
Merge pull request #39 from bgctw/dev2
Browse files Browse the repository at this point in the history
support fitting ScaledLogNormal of LogNormal(-x)
  • Loading branch information
bgctw authored Aug 31, 2024
2 parents 50962e9 + 9b5162f commit fb7b10d
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 2 deletions.
27 changes: 27 additions & 0 deletions docs/src/lognormal.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,33 @@ d = fit_mean_relerror(LogNormal, 2, 0.2)
(true, true)
```

## ScaledLogNormal: LogNormal(-x)
To support the use case of a distribution of strictly negative values, the
fitting of a mirrored LogNormal on `-x` is supported.

There is a type-alias
`ScaledLogNormal = LocationScale{T, Continuous, LogNormal{T}} where T`,
denoting a scaled and shifted LogNormal distribution.

There are fitting function dispatched by this type that fit
such a mirrored distribution.

```jldoctest; output = false, setup = :(using DistributionFits)
d = fit_mean_Σ(ScaledLogNormal, -1, log(1.1))
(mean(d), σstar(d)) .≈ (-1.0, 1.1)
# output
(true, true)
```

```jldoctest; output = false, setup = :(using DistributionFits)
d = fit(ScaledLogNormal, -1.0, @qp_ll(-1.32), Val(:mode))
(mode(d), quantile(d, 0.025)) .≈ (-1.0, -1.32)
# output
(true, true)
```
Note the usage of lower quantile for the mirrored distribution, here.


## Detailed API

```@docs
Expand Down
2 changes: 1 addition & 1 deletion ext/DistributionFitsOptimExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function DistributionFits.optimize(f, ::OptimOptimizer, lower, upper)
end

function __init__()
@info "DistributionFits: setting OptimOptimizer"
#@info "DistributionFits: setting OptimOptimizer"
#DistributionFits.set_optimizer(DistributionFitsOptimExt.OptimOptimizer())
DistributionFits.set_optimizer(OptimOptimizer())
end
Expand Down
1 change: 1 addition & 0 deletions inst/scratch.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

2 changes: 1 addition & 1 deletion src/DistributionFits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export
# optimize, set_optimizer

# LogNormal
export AbstractΣstar, Σstar, σstar
export AbstractΣstar, Σstar, σstar, ScaledLogNormal

# LogitNormal
export fit_mode_flat, shifloNormal
Expand Down
29 changes: 29 additions & 0 deletions src/univariate/continuous/lognormal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,32 @@ function fit_mean_relerror(::Type{LogNormal}, mean, relerror)
σ = sqrt(log(w))
LogNormal(μ, σ)
end


#---- support LogNormal(-x) of negative values ------------
const ScaledLogNormal{T} = LocationScale{T, Continuous, LogNormal{T}} where T

σstar(d::ScaledLogNormal) = exp(params(d.ρ)[2])


function fit_mean_Σ(::Type{ScaledLogNormal}, mean::T1, σ::T2) where {T1 <: Real,T2 <: Real}
_T = promote_type(T1, T2)
fit_mean_Σ(ScaledLogNormal{_T}, mean, σ)
end
function fit_mean_Σ(d::Type{ScaledLogNormal{T}}, mean::Real, σ::Real) where T
mean < 0 && return(-1 * fit_mean_Σ(LogNormal{T}, -mean, σ))
1 * fit_mean_Σ(LogNormal{T}, mean, σ)
end

function fit_mode_quantile(::Type{ScaledLogNormal}, mode::T, qp::QuantilePoint) where T<:Real
fit_mode_quantile(ScaledLogNormal{T}, mode, qp)
end
function fit_mode_quantile(::Type{ScaledLogNormal{T}}, mode::Real, qp::QuantilePoint) where T
if mode < 0
return(-1 * fit_mode_quantile(LogNormal{T}, -mode, QuantilePoint(-qp.q,1-qp.p)))
#return(-1 * fit_mode_quantile(LogNormal{T}, -mode, qp))
end
1 * fit_mode_quantile(LogNormal{T}, mode, qp)
end


20 changes: 20 additions & 0 deletions test/univariate/continuous/lognormal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,23 @@ end;
@test mode(d) 0.5
@test quantile(d, 0.95) 0.9
end;

@testset "fitting ScaledLogNormal" begin
d2 = fit_mean_Σ(ScaledLogNormal, -1, log(1.1))
@test d2 isa ScaledLogNormal
@test σstar(d2) == 1.1

d2 = fit_mean_Σ(ScaledLogNormal, 1.0, log(1.1))
@test d2 isa ScaledLogNormal
@test mean(d2) == 1.0
@test σstar(d2) == 1.1

# take care to specify qp_ll here, its lower than mode
d3 = fit(ScaledLogNormal, -1.0, @qp_ll(-1.32), Val(:mode))
@test d3 isa ScaledLogNormal
@test mode(d3) == -1.0
@test quantile(d3, 0.025) -1.32

d3 = fit(ScaledLogNormal, 1.0, @qp_uu(1.32), Val(:mode))
@test d3 isa ScaledLogNormal
end;

0 comments on commit fb7b10d

Please sign in to comment.