Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix mode(Binomial) and modes(Binomial) #1931

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions src/univariate/discrete/binomial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,36 @@ params(d::Binomial) = (d.n, d.p)

mean(d::Binomial) = ntrials(d) * succprob(d)
var(d::Binomial) = ntrials(d) * succprob(d) * failprob(d)
function mode(d::Binomial{T}) where T<:Real

function mode(d::Binomial)
(n, p) = params(d)
v = (n + 1) * p
quasi_mode = floor(Int, v)
if quasi_mode == v
if p == 1
n
else
quasi_mode-1
end
else
quasi_mode
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT alternatives with fewer branches would be

Suggested change
v = (n + 1) * p
quasi_mode = floor(Int, v)
if quasi_mode == v
if p == 1
n
else
quasi_mode-1
end
else
quasi_mode
end
iszero(p) ? 0 : ceil(Int, (n + 1) * p) - 1

or

Suggested change
v = (n + 1) * p
quasi_mode = floor(Int, v)
if quasi_mode == v
if p == 1
n
else
quasi_mode-1
end
else
quasi_mode
end
max(0, ceil(Int, (n + 1) * p) - 1)

or

Suggested change
v = (n + 1) * p
quasi_mode = floor(Int, v)
if quasi_mode == v
if p == 1
n
else
quasi_mode-1
end
else
quasi_mode
end
clamp(ceil(Int, (n + 1) * p) - 1, 0, n)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is little to no difference in runtime between these options (or the option in the PR). The main difference is in the max runtime, and the PR options and the max(0, ceil(...)) have the shorter max runtime (the two are nearly identical with a max of about 10x the average runtime), while the max runtime for the other two options is about twice as long (about 20x the average runtime). The standard deviations show a similar pattern (but they are smaller than the average runtime).

Given there isn't much of a different in run times, I propose the PR version is preferable because it is easiest to read and reason about.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@devmotion Is there another reason to consider fewer branches other than runtime?

end

function modes(d::Binomial)
(n, p) = params(d)
n > 0 ? floor(Int, (n + 1) * d.p) : zero(T)
v = (n + 1) * p
quasi_mode = floor(Int, v)
if quasi_mode == v
if p == 1
Int[n]
else
Int[quasi_mode-1, quasi_mode]
end
else
Int[quasi_mode]
end
end
modes(d::Binomial) = Int[mode(d)]

function skewness(d::Binomial)
n, p1 = params(d)
Expand Down
15 changes: 11 additions & 4 deletions test/univariate/discrete/binomial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,18 @@ end
@test median(Binomial(45,3//10)) == 13
@test median(Binomial(65,3//10)) == 19
@test median(Binomial(85,3//10)) == 25

# Test mode
@test Distributions.mode(Binomial(100, 0.4)) == 40
@test Distributions.mode(Binomial(1, 0.51)) == 1
@test Distributions.mode(Binomial(1, 0.49)) == 0
@test mode(Binomial(100, 0.4)) == 40
@test mode(Binomial(1, 0.51)) == 1
@test mode(Binomial(1, 0.49)) == 0
@test mode(Binomial(4, 2//3)) == 3
@test mode(Binomial(6, 2//7)) == 1
@test mode(Binomial(7, 1//8)) == 0

@test modes(Binomial(4, 2//3)) == [3, 4]
marcusps marked this conversation as resolved.
Show resolved Hide resolved
@test modes(Binomial(6, 2//7)) == [1, 2]
@test modes(Binomial(7, 1//8)) == [0, 1]

@test isplatykurtic(Bernoulli(0.5))
@test ismesokurtic(Normal(0.0, 1.0))
Expand Down
Loading