# On beauty of Distributions.jl pdf interface

**URL:** <https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895>\
**Category:** General Usage\
**Tags:** syntax, design, community, distributions, probability\
**Created:** [September 8, 2021, 7:58pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895 "2021-09-08T19:58:02Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![thisismygitrepo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thisismygitrepo/32/28593_2.png) [@thisismygitrepo](https://discourse.julialang.org/u/thisismygitrepo)\
**Post date:** [September 8, 2021, 7:58pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/1 "2021-09-08T19:58:02Z")

</div>

Julia is often touted for its syntax that resembles math notation. I have a kind of objection here.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/4/9/4926d2aa7f4b1af229873c7bf14cfd22568ea992.png)

Getting values of this density function with this syntax is awkward to say the least. Shouldn’t this be simply `p(0:0.01:1)` ? In fact, this is the case in almost all other languages.

---

<div class="post-metadata">

**Author:** ![Paulo\_Jabardo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paulo_jabardo/32/3196_2.png) [@Paulo\_Jabardo](https://discourse.julialang.org/u/Paulo_Jabardo)\
**Post date:** [September 8, 2021, 8:18pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/2 "2021-09-08T20:18:41Z")

</div>

This really is a matter of taste. The issue is that you are considering `p` a density function. I see it as a distribution where different things can be done with it, including, but not limited to, calculating the density function or generating random numbers from this distribution.

Now, if you really want to use as a density function, you could resort to type piracy and define the function yourself:

```julia
(p::Distribution)(x) = pdf(p, x)

```

And now,

```julia-repl
julia> p = Beta(2,3)
Beta{Float64}(α=2.0, β=3.0)

julia> p.(x) == pdf.(p, x)
true

```

But I wouldn’t recommend it. It will work with the simpler distributions.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [September 8, 2021, 8:41pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/3 "2021-09-08T20:41:18Z")

</div>

This is a choice a _package_ (Distributions.jl) made for its API; it very well could have chosen to use `p(x)` for this.

Since that syntax _is available_ for packages to use, I’ve moved this out of #dev and into #usage and I’ve made the title a bit more focused.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [September 8, 2021, 9:10pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/5 "2021-09-08T21:10:07Z")

</div>

No. The other API clearly could work (since you can emulate it with 1 line of code). The question is just what it should mean to call a distribution. IMO, sampling would be the more natural behavior of a function call, and the reason Distributions chooses to make it explicit is that there isn’t a clear right answer.

---

<div class="post-metadata">

**Author:** ![thisismygitrepo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thisismygitrepo/32/28593_2.png) [@thisismygitrepo](https://discourse.julialang.org/u/thisismygitrepo)\
**Post date:** [September 8, 2021, 9:16pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/6 "2021-09-08T21:16:26Z")

</div>

Thanks for the comment. But there is a way of resolving this, right? We aim at making this look like math notiation. In statistics, `p`, a distribution, is nothing but a function. `p(0)` is unanimously agreed on to represent density at `x=0`. Sampling would be represented by something like `x ~ p`. Back to the point, `pdf(p, 2)` is not remotely close to what we write in math notation.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [September 8, 2021, 9:28pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/7 "2021-09-08T21:28:45Z")

</div>

There are various notations in statistics. For example, f\_X(5) is pretty similar to `pdf(x, 5)`. It could be better if we had a nicer way to make partial functions like `pdf(x::Distribution)`. That is a Julia syntax issue.

---

<div class="post-metadata">

**Author:** ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)\
**Post date:** [September 8, 2021, 9:34pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/8 "2021-09-08T21:34:25Z")

</div>

So why wouldn’t `p()` be the proper interface for sampling? Or maybe `p(0.5)` should be the logpdf instead (as is often used by bayesians)? A distribution is a mathematical object which you can “do stuff” to. And in Julia, “stuff” usually means functions with multiple-dispatch.

Personally, I think the `p(x)` etc. should only be used for function-like use, but there are probably some DSLs where that is worth deviating from.

FWIW, I often write F \sim N(0,1) etc. and then \int g(x) d F(x) so to me the CDF is more natural than the PDF?

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [September 8, 2021, 9:35pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/9 "2021-09-08T21:35:28Z")

</div>

not really a Julia syntax issue, all you need to do is define

```julia
pdf(d::Distribution) = p(x)->pdf(d, x)
p = pdf(Beta(2,3))
p.(x)

```

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [September 8, 2021, 9:36pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/10 "2021-09-08T21:36:15Z")

</div>

Fair enough. Though Distributions.jl didn’t do that, and we can’t do it without piracy.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [September 8, 2021, 10:42pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/11 "2021-09-08T22:42:53Z")

</div>

> [@thisismygitrepo](#):
>
> In fact, this is the case in almost all other languages.

Which languages are they? Certainly neither Python, R, Matlab or Mathematica, to mention the most comparable.

> [@thisismygitrepo](#):
>
> In statistics, `p` , a distribution, is nothing but a function.

That’s not what I learned in my statistics courses. There are a number of functions that can describe a probability distribution, such as the pdf or cdf, but they aren’t the distribution itself.

> [@thisismygitrepo](#):
>
> `p(0)` is unanimously agreed on to represent density at `x=0` .

I don’t think I’ve ever heard this before. The _density function of_ a distribution has this property, not the distribution itself.

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [September 8, 2021, 10:52pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/12 "2021-09-08T22:52:31Z")

</div>

Here’s a illustrative table prepared by @Albert_Zevelev :

> **[Future Post Random Variables in Julia compared to...](https://azev77.github.io/posts/2021/04/blog-post-2/)**
>
> This post compares the way random variables are handled in Julia/MATLAB/R/STATA/Mathematica/Python.It was inspired by Bruce Hansen’s recent textbookwhich compares statistical commands in Matlab/R/STATA on page 114. This post will focus on the main...

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [September 8, 2021, 10:52pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/13 "2021-09-08T22:52:55Z")

</div>

If `Normal()` just returned the pdf function of the standard normal distribution, it would be far less powerful. Calculating the cdf from this function would mean having to numerically integrate the pdf. Even just calculating the mean or other moments would entail numerical integration, because you wouldn’t have access to the distribution parameters, only the function itself.

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [September 8, 2021, 11:07pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/14 "2021-09-08T23:07:26Z")

</div>

> [@jzr](#):
>
> fX(5)f\_X(5) is pretty similar to `pdf(x, 5)`

I really like that characterization. It’s more elegant, and more flexible.

---

<div class="post-metadata">

**Author:** ![thisismygitrepo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thisismygitrepo/32/28593_2.png) [@thisismygitrepo](https://discourse.julialang.org/u/thisismygitrepo)\
**Post date:** [September 8, 2021, 11:29pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/16 "2021-09-08T23:29:24Z")

</div>

Thanks for that. I personally see that `scipy` is the most elegant, least amount of composition and brackets.

---

<div class="post-metadata">

**Author:** ![ptoche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ptoche/32/23554_2.png) [@ptoche](https://discourse.julialang.org/u/ptoche)\
**Post date:** [September 8, 2021, 11:36pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/17 "2021-09-08T23:36:26Z")

</div>

I don’t find your arguments for making the pdf representation of a distribution the fundamental object particularly compelling. Every probability distribution on a subset of the reals has a cumulative distribution function, which uniquely defines the distribution. By contrast, a probability density function exists only for (absolutely) continuous probability distributions. It’s a matter of taste, but I find the API of `Distributions.jl` well inspired.

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [September 8, 2021, 11:38pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/18 "2021-09-08T23:38:51Z")

</div>

Suppose you want to switch the distribution in some model. In Julia (and Mathematica) it does not take much. Simply switch out the distribution in say `cdf(Normal(4, 10), x)` to `cdf(TDist(r), x)`. In other frameworks you have to worry about how many parameters the distribution has, and then order, etc, no?  
eg:

```julia
const dist = Normal(4, 10)

# compute probability -3 <= x <= 3:
prob = cdf(dist, 3) - cdf(dist, -3)

```

Simply redefine the distribution at the top and nothing else has to change in the rest of the script.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [September 9, 2021, 7:46am UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/19 "2021-09-09T07:46:43Z")

</div>

> [@thisismygitrepo](#):
>
> I personally see that `scipy` is the most elegant, least amount of composition and brackets.

I think that blog post actually gives scipy a bit of an unfair advantage.

```julia
# scipy
norm.cdf(x)

```

vs

```julia
# Distributions.jl
cdf(Normal(0,1),x)

```

as it assumes default values being used for scipy but not for Distributions.jl. A more fair comparison would be:

scipy:

```julia
import scipy.stats as st
st.norm(2, 3).cdf(0.9)
# with default values
st.norm.cdf(0.9)

```

I could perhaps do

```julia
from scipy.stats import norm

```

But that isn’t normally idiomatic python as far as I know.

Distributions.jl

```julia
using Distributions
cdf(Normal(2, 3), 0.9)
# with default values
cdf(Normal(), 0.9)

```

There’s no less punctuation in the scipy version. Actually, scipy and Distributions.jl are not that different, in that you have a distribution object that you call various functions/methods on. This is very nice compared to the Matlab approach:

```julia
>> normcdf(0.9, 2, 3) 
# with default values
>> normcdf(0.9)

```

It is terse, but awkward, since you need to know the _name_ of the distribution to get its various properties.

A brief comment on the idea that the pdf contains all the information about a distribution:  
This may be true _in principle_ (for most distributions, at least), but the information is very hard to retrieve. Let’s do a thought experiment: I give you a variable, called `f`. I tell you that it holds the pdf of some statistical distribution. How would you go about finding the _mean_ of the distribution described by `f`? I would contend that, _in general_, this is impossible, or would take infinite time. If you are _lucky_, it is centered around zero, and you could start doing some indefinite integration, searching for the outer limits of the pdf. But, what if it is centered around -10^64 instead, and is extremely narrow? And maybe it’s a mixed distribution? And maybe it’s multi-dimensional?

So what do you do?

---

<div class="post-metadata">

**Author:** ![thisismygitrepo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thisismygitrepo/32/28593_2.png) [@thisismygitrepo](https://discourse.julialang.org/u/thisismygitrepo)\
**Post date:** [September 9, 2021, 9:02pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/21 "2021-09-09T21:02:04Z")

</div>

Thanks for the perspective. This restored my belief in Julia.  
Hopefully the accident was not caused by Julia.

---

<div class="post-metadata">

**Author:** ![thisismygitrepo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thisismygitrepo/32/28593_2.png) [@thisismygitrepo](https://discourse.julialang.org/u/thisismygitrepo)\
**Post date:** [September 9, 2021, 9:04pm UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/22 "2021-09-09T21:04:00Z")

</div>

Thank you for the detailed response. This has certainly dissuaded my position.

---

<div class="post-metadata">

**Author:** ![TheLateKronos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thelatekronos/32/12824_2.png) [@TheLateKronos](https://discourse.julialang.org/u/TheLateKronos)\
**Post date:** [September 14, 2021, 6:52am UTC](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895/23 "2021-09-14T06:52:25Z")

</div>

I just wrote some code last week, because I also felt that the `pdf(X, 1)` syntax was tedious.  
My premise is that the `f_X` syntax means the pdf of the distribution `X`. I also assume that I will mostly define my distributions as `X`. As a final thing, it seemed like 0-based indexing was beneficial, so I constructed the return value with an `OffsetArray` with default `offset = -1`:

```julia
using OffsetArrays
using Distributions

f_X(; offset = -1) = OffsetArray((pdf(eval(:X))), offset)
f_X(ind::Real; offset = -1) = OffsetArray(pdf(eval(:X)), offset)[ind]
f_X(inds::AbstractArray; offset = -1) = f_X.(inds; offset)

```

It is possible that this only makes sense for discrete distributions - my lecture on continuos ones are today 🙂

This allows

```julia
julia> X = Binomial(1000, 0.9)
Binomial{Float64}(n=1000, p=0.9)
julia> f_X() == pdf(X) # Acutally f_X(offset=0) == pdf(X)
true

```

Now if I redefine `X` and call the function again, it evaluates to whatever `X` is currently defined as through metaprogramming:

```julia
julia> X = DiscreteUniform()
DiscreteUniform(a=0, b=1)
julia> f_X() == pdf(X) # Acutally f_X(offset=0) == pdf(X)
true

```

Note that the offsets are set to 0 for comparison - otherwise I prefer 0-based indexing for this technical domain.

Part of the reason for all this is that I am currently more interested in indexing the pdf than evaluating it at a given value. I was expecting the second argument to `pdf` to be the index, but it is instead the input value. So what I want is

```julia
julia> pdf(X)[1:3]
3-element Vector{Float64}:
 0.34867844010000004
 0.387420489
 0.19371024449999996

```

This can be acieved with only one set of brackets and zero-based indexing with my function:

```julia
julia> f_X(0:2) .== pdf(X)[1:3]
3-element BitVector:
 1
 1
 1

```

In case you should find that useful 🙂

[Next page](https://discourse.julialang.org/t/on-beauty-of-distributions-jl-pdf-interface/67895.md?page=2)
