Discrete Quantile Policies

| Home | Libraries | People | FAQ | More

#### Discrete Quantile Policies

If a statistical distribution is discrete then the random variable can only have integer values - this leaves us with a problem when calculating quantiles - we can either ignore the discreteness of the distribution and return a real value, or we can round to an integer. As it happens, computing integer values can be substantially faster than calculating a real value, so there are definite advantages to returning an integer, but we do then need to decide how best to round the result. The `discrete_quantile` policy defines how discrete quantiles work, and how integer results are rounded:

    enum discrete_quantile_policy_type
    {
       real,
       integer_round_outwards, // default
       integer_round_inwards,
       integer_round_down,
       integer_round_up,
       integer_round_nearest
    };

    template <discrete_quantile_policy_type>
    struct discrete_quantile;

The values that `discrete_quantile` can take have the following meanings:

###### real

Ignores the discreteness of the distribution, and returns a real-valued result. For example:

    #include <boost/math/distributions/negative_binomial.hpp>
    using boost::math::negative_binomial_distribution;

    using namespace boost::math::policies;

    typedef negative_binomial_distribution<
          double,
          policy<discrete_quantile<real> >
       > dist_type;

    // Lower 5% quantile:
    double x = quantile(dist_type(20, 0.3), 0.05);
    // Upper 95% quantile:
    double y = quantile(complement(dist_type(20, 0.3), 0.05));

Results in `x = 27.3898` and `y = 68.1584`.

###### integer_round_outwards

This is the default policy: an integer value is returned so that:

- Lower quantiles (where the probability is less than 0.5) are rounded down.
- Upper quantiles (where the probability is greater than 0.5) are rounded up.

This is normally the safest rounding policy, since it ensures that both one and two sided intervals are guaranteed to have at least the requested coverage. For example:

    #include <boost/math/distributions/negative_binomial.hpp>
    using boost::math::negative_binomial;

    // Use the default rounding policy integer_round_outwards.
    // Lower quantile rounded down:
    double x = quantile(negative_binomial(20, 0.3), 0.05); // rounded up 27 from 27.3898
    // Upper quantile rounded up:
    double y = quantile(complement(negative_binomial(20, 0.3), 0.05)); // rounded down to 69 from 68.1584

Results in `x = 27` (rounded down from 27.3898) and `y = 69` (rounded up from 68.1584).

The variables x and y are now defined so that:

    cdf(negative_binomial(20), x) <= 0.05
    cdf(negative_binomial(20), y) >= 0.95

In other words we guarantee at least 90% coverage in the central region overall, and also no more than 5% coverage in each tail.

###### integer_round_inwards

This is the opposite of integer_round_outwards: an integer value is returned so that:

- Lower quantiles (where the probability is less than 0.5) are rounded up.
- Upper quantiles (where the probability is greater than 0.5) are rounded down.

For example:

    #include <boost/math/distributions/negative_binomial.hpp>
    using boost::math::negative_binomial_distribution;

    using namespace boost::math::policies;

    typedef negative_binomial_distribution<
          double,
          policy<discrete_quantile<integer_round_inwards> >
       > dist_type;

    // Lower quantile rounded up:
    double x = quantile(dist_type(20, 0.3), 0.05); // 28 rounded up from 27.3898
    // Upper quantile rounded down:
    double y = quantile(complement(dist_type(20, 0.3), 0.05)); // 68 rounded down from 68.1584

Results in `x = 28` (rounded up from 27.3898) and `y = 68` (rounded down from 68.1584).

The variables x and y are now defined so that:

    cdf(negative_binomial(20), x) >= 0.05
    cdf(negative_binomial(20), y) <= 0.95

In other words we guarantee at no more than 90% coverage in the central region overall, and also at least 5% coverage in each tail.

###### integer_round_down

Always rounds down to an integer value, no matter whether it's an upper or a lower quantile.

###### integer_round_up

Always rounds up to an integer value, no matter whether it's an upper or a lower quantile.

###### integer_round_nearest

Always rounds to the nearest integer value, no matter whether it's an upper or a lower quantile. This will produce the requested coverage in the average case, but for any specific example may results in either significantly more or less coverage than the requested amount. For example:

For example:

    #include <boost/math/distributions/negative_binomial.hpp>
    using boost::math::negative_binomial_distribution;

    using namespace boost::math::policies;

    typedef negative_binomial_distribution<
          double,
          policy<discrete_quantile<integer_round_nearest> >
       > dist_type;

    // Lower quantile rounded (down) to nearest:
    double x = quantile(dist_type(20, 0.3), 0.05); // 27
    // Upper quantile rounded (down) to nearest:
    double y = quantile(complement(dist_type(20, 0.3), 0.05)); // 68

Results in `x = 27` (rounded from 27.3898) and `y = 68` (rounded from 68.1584).