Search code examples
pythonnumpyrandomprobability-density

Get reverse cumulative density function with NumPy?


I am interested in a particular density, and I need to sample it "regularly" in a way that represent its shape (not random).

Formally, f is my density function, F is the corresponding cumulative density function (F' = f), whose reverse function rF = F^-1 does exist. I am interested in casting a regular sample from [0, 1] into my variable domain through F^-1. Something like:

import numpy as np
uniform_sample = np.linspace(0., 1., 256 + 2)[1:-1] # source sample
shaped_sample = rF(uniform_sample) # this is what I want to get

Is there a dedicated way to do this with numpy, or should I do this by hand? Here is the 'by hand' way for exponential law:

l = 5. # exponential parameter
# f = lambda x: l * np.exp(-l * x) # density function, not used
# F = lambda x: 1 - np.exp(-l * x) # cumulative density function, not used either
rF = lambda y: np.log(1. / (1. - y)) / l # reverse `F^-1` function
# What I need is:
shaped_sample = rF(uniform_sample)

I know that, in theory, rF is internally used for drawing random samples when np.random.exponential is called, for example (a uniform, random sample from [0, 1] is transformed by rF to get the actual result). So my guess is that numpy.random does know the rF function for each distribution it offers.

How do I access it? Does numpy provide functions like:

np.random.<any_numpy_distribution>.rF

or

np.random.get_reverse_F(<any_custom_density_function>)

.. or should I derive / approximate them myself?


Solution

  • scipy has probability distribution objects for all (I think) of the probability distributions in numpy.random.

    http://docs.scipy.org/doc/scipy/reference/stats.html

    The all have a ppf() method that does what you want.

    http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.rv_continuous.ppf.html

    In your example:

    import scipy.stats as st
    
    l = 5. # exponential parameter
    dist = st.expon(0., l) # distribution object provided by scipy
    f  = dist.pdf # probability density function
    F  = dist.cdf # cumulative density function
    rF = dist.ppf # percent point function : reverse `F^-1` function
    shaped_sample = rF(uniform_sample)
    # and much more!