Caching information in custom scipy distributions

Question:

I am trying to create a custom distribution in scipy (COM-Poisson).

import numpy as np
from mpmath import nsum, fac, inf
from scipy import stats


def pmf(k, mu, nu):
    return float((mu ** k) / ((fac(k) ** nu) * nsum(lambda j: (mu ** j) / (fac(j) ** nu), [0, inf])))


vectorized_pmf = np.vectorize(pmf)


class com_poisson_gen(stats.rv_discrete):
    def _argcheck(self, mu, nu):
        return mu >= 0 & nu >= 0

    def _pmf(self, k, mu, nu):
        return vectorized_pmf(k, mu, nu)


com_poisson = com_poisson_gen(name="com-poisson", longname='Conway-Maxwell-Poisson')
com_poisson.rvs(2, 4, size=100000)

I would like to cache the normalising constant so it is calculated only once, how can I achieve this?

Asked By: JavaStudent

||

Answers:

A suggestion of an lru_cahce decorator from the guys at scipy.stats helped solve this.

from functools import lru_cache

import numpy as np
from mpmath import nsum, fac
from numpy import inf
from scipy import stats
from scipy.special import factorial


class com_poisson_gen(stats.rv_discrete):
    @lru_cache(maxsize=None)
    def _normalization_factor(self, mu, nu):
        return float(nsum(lambda j: (mu ** j) / (fac(j) ** nu), [0, inf]))

    def _argcheck(self, mu, nu):
        return (np.asarray(mu) > 0) & (np.asarray(nu) > 0)

    def _pmf(self, k, mu, nu):
        broadcast = np.broadcast(mu, nu)
        normalization_factor = np.empty(broadcast.shape)
        normalization_factor.flat = [self._normalization_factor(x, y) for x, y in broadcast]
        return (mu ** k) / ((factorial(k) ** nu) * normalization_factor)

com_poisson = com_poisson_gen()
Answered By: JavaStudent
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.