[SciPy-User] scipy.stats.truncnorm behaviour

Joe Mellor jcm71 at cantab.net
Tue Apr 2 12:36:16 EDT 2013


Hi all,

I have searched the mailing list, so hopefully I'm not repeating something
already on here.

I have been using both scipy.stats.norm and scipy.stats.truncnorm and have
found some (to me) unexpected differences in their behaviour.
The differences are in how each handles the size parameter given to the rvs
method.

for example
when I execute

from scipy.stats.norm

a = array([100.0,1000.0,10000.0])
b = norm.rvs(a,size=(10,3))

b is a (10,3) array where b[:,i] contains 10 samples whose mean is a[i]

However, when I do

from scipy.stats.truncnorm

a = array([100.0,1000.0,10000.0])
b = truncnorm.rvs(-a,inf,loc=a,size=(10,3))

I get a ValueError

----> 1 truncnorm.rvs(-a,inf,loc=a,size=(10,3))

/usr/local/lib/python2.7/dist-packages/scipy/stats/distributions.pyc in
rvs(self, *args, **kwds)
    702             return loc*ones(size, 'd')
    703
--> 704         vals = self._rvs(*args)
    705         if self._size is not None:
    706             vals = reshape(vals, size)

/usr/local/lib/python2.7/dist-packages/scipy/stats/distributions.pyc in
_rvs(self, *args)
   1226         ## Use basic inverse cdf algorithm for RV generation as
default.
   1227         U = mtrand.sample(self._size)
-> 1228         Y = self._ppf(U,*args)
   1229         return Y
   1230

/usr/local/lib/python2.7/dist-packages/scipy/stats/distributions.pyc in
_ppf(self, q, a, b)
   5118         return (_norm_cdf(x) - self._na) / self._delta
   5119     def _ppf(self, q, a, b):
-> 5120         return norm._ppf(q*self._nb + self._na*(1.0-q))
   5121     def _stats(self, a, b):
   5122         nA, nB = self._na, self._nb

ValueError: operands could not be broadcast together with shapes (3) (30)


Presumably the problem being that self._nb and q are of different sizes.
Whereas scipy.stats.norm is ok as its implementation of _rvs just returns
self._size standard normal samples which get reshaped in rv_generic.rvs
before being scaled and shifted.

It would be useful if they acted consistently.

I had a look at the code and the size parameter to rvs (which is really
more the shape parameter) is not passed down to the relevant methods
_rvs (and therefore not to _ppf).

I thought that perhaps either giving _rvs access to the size parameter by
storing it in a field like self._shape so that instead of the code

      def _rvs(self, *args):
        ## Use basic inverse cdf algorithm for RV generation as default.
        U = mtrand.sample(self._size)
        Y = self._ppf(U,*args)
        return Y

it would be

    def _rvs(self, *args):
        ## Use basic inverse cdf algorithm for RV generation as default.
        U = mtrand.sample(self._shape)
        Y = self._ppf(U,*args)
        return Y


Alternatively truncnorm._ppf could work out how to expand self._nb by
looking at the size of _nb and q.

I'm not that familiar with the code, so there are probably problems with
both.

I'm using version 11.0 of scipy.


Thanks
Joe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.scipy.org/pipermail/scipy-user/attachments/20130402/d2995ec2/attachment.html>


More information about the SciPy-User mailing list