Repository navigation
Add a NegativeBinomial distribution built with the SymPy factory - #446
Open
alejandroschuler wants to merge 1 commit into
Open
alejandroschuler wants to merge 1 commit into
alejandroschuler wants to merge 1 commit into
Conversation
NegativeBinomial models overdispersed counts with the mean mu and the dispersion n, both on the log scale, and variance mu + mu**2 / n. n is the n of scipy.stats.nbinom, and the p of scipy is n / (n + mu). The fit starts from the method of moments and finds the maximum likelihood estimate, with n kept in [1e-4, 1e6]. The Fisher Information has no closed form in n, so the factory uses its Monte Carlo metric. Two changes to make_distribution were necessary: - A value of scipy_kwarg_map can be an expression in the parameters, so the predicted distributions get pmf, cdf, ppf and interval from scipy. Expressions need a fit_fn. - The default sample(m) for distributions with a scipy class called rvs(size=m), which failed for more than one row (also for Beta). It now draws as the hand-written distributions do. Replaces #356 by @ashler-herrick. Closes #281. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 27, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #281. Replaces #356 by @ashler-herrick, which this PR credits.
This PR is stacked on #445. Its base branch is
fix/sympy-factory-pickle, so the diff shows only the negative binomial work. GitHub will change the base tomasterwhen #445 is merged.The distribution
NegativeBinomialis for regression on overdispersed counts, where the variance is larger than the mean.muand the dispersionn, both on the log scale.mu + mu**2 / n, so it approaches the Poisson asngrows.nis thenofscipy.stats.nbinom(sizein R andthetainMASS::glm.nb), and thepof scipy isn / (n + mu).The new file
ngboost/distns/negative_binomial.pybuilds the distribution withmake_distributionfrom the negative log-likelihood. Itsfit_fnstarts from the method of moments and then finds the maximum likelihood estimate. It keepsnin [1e-4, 1e6], because the maximum likelihood estimate ofnis infinite for data without overdispersion. It raisesValueErrorfor values that are not counts.Changes to the factory
scipy_kwarg_map. scipy does not takemu, so the map can now hold an expression:{"n": n, "p": n / (n + mu)}. The predicted distributions therefore getpmf,cdf,ppf,interval,meanandvarfrom scipy. An expression needs afit_fn, because the factory cannot invert it to fit with scipy, andmake_distributionraisesValueErrorif there is none.sample(m). For factory distributions that use a scipy class,sample(m)calledself.dist.rvs(size=m). That fails for more than one row: on master,Beta(params).sample(5)with 3 rows raisesValueError. It also stopped the Monte Carlo metric of any such distribution that has no closed-form Fisher Information, and the negative binomial is one of those.sample(m)now draws as the hand-written distributions do.Fisher Information
In (log mu, log n), the Fisher Information is diagonal, with
I_mu = mu n / (n + mu)andI_n = n² (E[ψ'(n) − ψ'(Y + n)] − mu / (n (n + mu))). The expectation has no closed form, so the factory uses its Monte Carlo metric with 100 draws.I also tried an exact metric, which sums the series for each row up to a high quantile.
mufrom 0.1 to 1000 andnfrom 0.05 to 1e4.For these reasons I kept the default. In a fit to 5000 rows with 300 trees, the metric takes about 80% of the time.
Checks
mu = exp(1 + x1)andn = 2, a fit with 300 trees gave a correlation of 0.95 between the predicted and true means, and a median fittednof 1.95.-scipy.stats.nbinom.logpmf, andmean,varandppfagree with scipy.TEST_GRAD), the pickling tests from Make SymPy factory distributions picklable #445, a fit test, a slow regression test, a sample shape test, and a test of thefit_fncheck.pytest --slow: 187 passed, 2 xfailed, 22 xpassed).🤖 Generated with Claude Code