# Empirical distribution type for continuous variables

**URL:** <https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676>\
**Category:** Statistics\
**Tags:** question, proposal\
**Created:** [September 1, 2017, 11:34pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676 "2017-09-01T23:34:44Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [September 1, 2017, 11:34pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/1 "2017-09-01T23:34:44Z")

</div>

Is there a functionality somewhere in StatsBase.jl or Distributions.jl for computing statistics from an empirical distribution type? Specifically, suppose I have samples in the real line, and that I want to compute the quantile at another location. An empirical distribution type would interpolate the inverse CDF between the sample points.

StatsBase.jl provides `ecdf` for empirical CDF, would it be interesting to have a distribution type on top of it? Please let me know if something is already available.

---

<div class="post-metadata">

**Author:** ![andreasnoack](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andreasnoack/32/27_2.png) [@andreasnoack](https://discourse.julialang.org/u/andreasnoack)\
**Post date:** [September 2, 2017, 1:29am UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/2 "2017-09-02T01:29:35Z")

</div>

`Distributions.EmpiricalUnivariateDistribution` might be what you are looking for.

---

<div class="post-metadata">

**Author:** ![andreasnoack](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andreasnoack/32/27_2.png) [@andreasnoack](https://discourse.julialang.org/u/andreasnoack)\
**Post date:** [September 2, 2017, 1:38am UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/3 "2017-09-02T01:38:29Z")

</div>

Took a closer look at the `EmpiricalUnivariateDistribution` and I might be a little careful with that distribution. There seems to be a couple of issues with it.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [September 2, 2017, 2:30am UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/4 "2017-09-02T02:30:08Z")

</div>

@andreasnoack on the spot, exactly what I need. What are the issues that you are seeing with it?

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [September 2, 2017, 2:39am UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/5 "2017-09-02T02:39:17Z")

</div>

The quantile is not doing interpolation, that is the issue you meant, right? It is just picking the closest point in the samples.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [September 2, 2017, 2:41am UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/6 "2017-09-02T02:41:25Z")

</div>

Also, the rand is incorrect, it is not doing the inverse sampling, I will submit a PR.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [September 2, 2017, 3:55pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/7 "2017-09-02T15:55:13Z")

</div>

[https://github.com/JuliaStats/Distributions.jl/pull/662](https://github.com/JuliaStats/Distributions.jl/pull/662)

I have changed the EmpiricalUnivariteDistribution to be discrete instead of continuous because it relies on `ecdf` from `StatsBase.jl`, which doesn’t perform interpolation. Please let me know if something is missing or incorrect.

What do you think of defining two empirical distribution types? One for continuous and one for discrete variables. The former would use some interpolation model (e.g. piecewise linear) to get the CDF and inverse CDF. Please let me know if that would be interesting, I need this functionality in my GeoStats.jl package, but I will implement it in Distributions.jl if it is useful to others.

---

<div class="post-metadata">

**Author:** ![andreasnoack](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andreasnoack/32/27_2.png) [@andreasnoack](https://discourse.julialang.org/u/andreasnoack)\
**Post date:** [September 2, 2017, 5:37pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/8 "2017-09-02T17:37:58Z")

</div>

I agree that the `ecdf` based empirical distribution is a discrete distribution. However, I don’t think interpolating the ecdf is the better way to produce a continuous version. I think it would be better to define distributions based on density estimates, i.e. `Histogram` and `KDE`.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [September 2, 2017, 5:47pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/9 "2017-09-02T17:47:00Z")

</div>

That is a very nice idea @andreasnoack, could you please add this functionality with KDEs? It sounds great.

I am particularly interested in the quantile method for empirical distributions, I need to transform samples from a distribution type A to a distribution type B. The way I do it is as follows:

```julia
"""
    transform(x, dist)

Transform the empirical distribution of samples `x` into `dist`.
"""
function transform(x::Vector, dist::ContinuousUnivariateDistribution)
    idx = sortperm(x)
    
    N = length(x)
    xcdf = [1:N-1; .99N] / N
   
    quantile(dist, xcdf[idx])
end

```

I can currently use this function with parametric distributions like Normal(), Gamma(), etc. But because we don’t have a EmpiricalContinuousDistribution yet, I cannot transform back. As you can see, the transformation only relies on the quantile.

---

<div class="post-metadata">

**Author:** ![taqtiqa-mark](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/taqtiqa-mark/32/4383_2.png) [@taqtiqa-mark](https://discourse.julialang.org/u/taqtiqa-mark)\
**Post date:** [April 28, 2019, 8:53am UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/10 "2019-04-28T08:53:00Z")

</div>

> [@andreasnoack](#):
>
> `Distributions.EmpiricalUnivariateDistribution` might be what you are looking for.

For others who come along this path…  
`Distributions.EmpiricalUnivariateDistribution` has been [removed](https://github.com/JuliaStats/Distributions.jl/pull/800) (Dec 2018).

It appears that `Distributions.DiscreteNonParametric` might be closest available, [with a caveat](https://github.com/JuliaStats/Distributions.jl/pull/800#issuecomment-445490724).

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [November 13, 2019, 12:57pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/11 "2019-11-13T12:57:59Z")

</div>

> [@taqtiqa-mark](#):
>
> `Distributions.DiscreteNonParametric`

Where you get documentation for the `Distributions.DiscreteNonParametric` ?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 13, 2019, 1:01pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/12 "2019-11-13T13:01:43Z")

</div>

It should have a docstring, eg

[https://github.com/JuliaStats/Distributions.jl/blob/f0cf26385ae47ab411a6e99d34cf49f2c651e440/src/univariate/discrete/discretenonparametric.jl#L1](https://github.com/JuliaStats/Distributions.jl/blob/f0cf26385ae47ab411a6e99d34cf49f2c651e440/src/univariate/discrete/discretenonparametric.jl#L1)

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [November 13, 2019, 1:45pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/13 "2019-11-13T13:45:34Z")

</div>

Thank you. I was looking in the package documentation instead of using the Julia integrated documentation system… my error…

If anyone is interested… how to create the distribution object from a sample of data:

```julia
using StatsBase, StatsPlots, Distributions
# Creating original samples...
N = Normal(0,1)
obs = rand(N,10000)
# Cdf..
myCdf = ecdf(obs)
cdf_obs = map(x -> myCdf(x), sort(obs))
# Cdf --> Pmf..
pmf_obs = Float64[]
for i in 1:length(obs)
    if i == 1 
        append!(pmf_obs,cdf_obs[1])
    else
        append!(pmf_obs,cdf_obs[i]-cdf_obs[i-1])
    end
end
# Creating a full distribution object..
d = DiscreteNonParametric(sort(obs),pmf_obs)
# Sampling from the distribution object..
out = rand(d,100)
# Test it...
plot(sort(out))
quantile(d,0.5)
quantile(d,1-0.025)
cdf(d,0)

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 13, 2019, 2:49pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/14 "2019-11-13T14:49:25Z")

</div>

> [@sylvaticus](#):
>
> I was looking in the package documentation instead of using the Julia integrated documentation system…

It seems to be documented in the generated docs, too:

[https://juliastats.org/Distributions.jl/latest/univariate/#Distributions.DiscreteNonParametric](https://juliastats.org/Distributions.jl/latest/univariate/#Distributions.DiscreteNonParametric)

---

<div class="post-metadata">

**Author:** ![hdavid16](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hdavid16/32/11531_2.png) [@hdavid16](https://discourse.julialang.org/u/hdavid16)\
**Post date:** [August 11, 2020, 5:49pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/15 "2020-08-11T17:49:23Z")

</div>

thanks for sharing @sylvaticus. I’ve cleaned it up a bit and wrapped it in a function in case any body needs it:

```julia
using StatsBase, Distributions
"""
    EmpiricalDistribution(data::Vector{T} where T <: Real)

Create a discrete empirical distribution based on observations.
"""
function EmpiricalDistribution(data::Vector{T} where T <: Real)
    sort!(data) #sort the observations
    empirical_cdf = ecdf(data) #create empirical cdf
    data_clean = unique(data) #remove duplicates to avoid allunique error
    cdf_data = empirical_cdf.(data_clean) #apply ecdf to data
    pmf_data = vcat(cdf_data[1],diff(cdf_data)) #create pmf from the cdf
    DiscreteNonParametric(data_clean,pmf_data) #define distribution
end
```

---

<div class="post-metadata">

**Author:** ![oschulz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oschulz/32/2998_2.png) [@oschulz](https://discourse.julialang.org/u/oschulz)\
**Post date:** [May 1, 2021, 7:37pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/16 "2021-05-01T19:37:33Z")

</div>

Maybe we could add something like that to [EmpiricalDistributions.jl](https://github.com/oschulz/EmpiricalDistributions.jl)? Currently, it only has binned distributions, but it doesn’t have to stay limited to that. EmpiricalDistributions could be moved into the JuliaStatistics org.

---

<div class="post-metadata">

**Author:** ![hdavid16](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hdavid16/32/11531_2.png) [@hdavid16](https://discourse.julialang.org/u/hdavid16)\
**Post date:** [May 1, 2021, 8:13pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/17 "2021-05-01T20:13:15Z")

</div>

Hi @oschulz , if you are referring to the previous post, that is what I did in the PR: [Add empirical discrete distribution by hdavid16 · Pull Request #16 · oschulz/EmpiricalDistributions.jl · GitHub](https://github.com/oschulz/EmpiricalDistributions.jl/pull/16#pullrequestreview-636290731)

---

<div class="post-metadata">

**Author:** ![oschulz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oschulz/32/2998_2.png) [@oschulz](https://discourse.julialang.org/u/oschulz)\
**Post date:** [May 2, 2021, 12:48am UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/18 "2021-05-02T00:48:43Z")

</div>

Ah, right, sorry, I forgot - you showed that `DiscreteNonParametric` in Distributions might do the trick already (but should support more functions).

---

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [February 14, 2023, 2:48pm UTC](https://discourse.julialang.org/t/empirical-distribution-type-for-continuous-variables/5676/19 "2023-02-14T14:48:24Z")

</div>

Sorry to revive an old topic. I was looking for a way to get an approximate interpolation of an empirical histogram, as a continuous density (PDF) that I can evaluate on new points.

Was a replacement of `Distributions.EmpiricalUnivariateDistribution` added later on to `Distributions`? Or is `EmpiricalDistributions.UvBinnedDist` the current recommended way to do this?

Unfortunately `EmpiricalDistributions.UvBinnedDist` does not do any kind of smoothing. Is there another method I can use that does some smoothed interpolation?

Thanks.
