-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
ENH: Support array-like n
in random.random.multinomial
#9710
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
Conversation
@@ -4549,7 +4549,7 @@ cdef class RandomState: | |||
|
|||
Parameters | |||
---------- | |||
n : int | |||
n : int or array_like of ints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs .. versionchanged:: 1.14.0
with a note that allowing array_like here is new. You can find examples in the file.
numpy/random/mtrand/mtrand.pyx
Outdated
mnix[i+d-1] = dn | ||
|
||
i = i + d | ||
for k from 0 <= k < m: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is outdated syntax for Pyrex compatibility
I'm wary of adding another Can we make it work as:
I'm also wondering if accepting an ND |
I removed what I think was the pyrex compatibility, but I'm not sure I understand your point about broadcasting? Would you guess the right approach is (in case |
I tried a bit to use |
This maybe feels like a feature? Force the user to make the integers Essentially, there are two different ways we could go with broadcasting. Here I'm using
Version 2 is more complex, but it does preserve the meanings of dimensions, which is often handy |
|
Looking at the |
Actually this is totally possible, there's just a quirk in the python-side interface to nditer ( #9808) that makes it non-obvious. Here's what I believe is a python implementation of what I'm describing. Caveat: I have no idea what I'm doing with import numpy as np
from numpy.lib.stride_tricks import as_strided
from numpy.random import multinomial as m_old
def multinomial(n, p):
it = np.nditer(
(n, p, None),
flags=[
"zerosize_ok", 'multi_index', 'reduce_ok' # no idea if these are needed
],
op_flags=[
['readonly'],
['readonly'],
['writeonly', 'allocate']
]
)
n, p, out = it.operands
p_shape = np.array(p.shape)
n_shape = np.array(p.shape)
out_shape = np.array(out.shape)
# axes containing probabilities, counted from the end
p_axs = p_shape != 1 # todo: let this be passed in
p_axs, = p_axs.nonzero()
p_axs -= p.ndim
if not np.all(n_shape[p_axs] == 1):
raise ValueError("Axes of n must be length 1 where probabilities are not")
# don't iterate over these
for ax_i in p_axs:
it.remove_axis(it.ndim + ax_i)
it.remove_multi_index() # I think this just makes things faster?
# it.enable_external_loop() # TODO: maybe a speedup to be had by using this
# convert to arrays so we can index these
p_strides = np.array(p.strides)
out_strides = np.array(out.strides)
while not it.finished:
ni, pi, outi = it.value
# workaround for gh-9808
pi = as_strided(pi, shape=p_shape[p_axs], strides=p_strides[p_axs])
outi = as_strided(outi, shape=out_shape[p_axs], strides=out_strides[p_axs])
outi[...] = m_old(ni, pi.ravel()).reshape(p.shape)
it.iternext()
return out |
Digging this up and asking if there is anything I could do to help this along? |
Add broadcasting to multinomial xref numpy/numpy#9710
Closing, |
This changes the
numpy.random.multinomial
API to be more similar to the API fornumpy.random.binomial
. In particular, something like this:I did some light benchmarking, and it seems like the current use case is equally fast, while this provides at least some speed up over
np.array([np.random.multinomial(n, pvals) for n in nvals])
.