[Numpy-discussion] Use-case for np.choose

David Goldsmith d.l.goldsmith@gmail....
Sun Nov 8 04:00:27 CST 2009

```On Sun, Nov 8, 2009 at 12:57 AM, Anne Archibald
<peridot.faceted@gmail.com>wrote:

> 2009/11/8 David Goldsmith <d.l.goldsmith@gmail.com>:
> > On Sat, Nov 7, 2009 at 11:59 PM, Anne Archibald <
> peridot.faceted@gmail.com>
> > wrote:
> >>
> >> 2009/11/7 David Goldsmith <d.l.goldsmith@gmail.com>:
> >> > So in essence, at least as it presently functions, the shape of 'a'
> >> > *defines* what the individual choices are within 'choices`, and if
> >> > 'choices'
> >> > can't be parsed into an integer number of such individual choices,
> >> > that's
> >> > when an exception is raised?
> >>
> >> Um, I don't think so.
> >>
> >> Think of it this way: you provide np.choose with a selector array, a,
> >> and a list (not array!) [c0, c1, ..., cM] of choices. You construct an
> >> output array, say r, the same shape as a (no matter how many
> >> dimensions it has).
> >
> > Except that I haven't yet seen a working example with 'a' greater than
> 1-D,
> > Josef's last two examples notwithstanding; or is that what you're saying
> is
> > the bug.
>
> There's nothing magic about A being one-dimensional.
>
> C = np.random.randn(2,3,5)
> A = (C>-1).astype(int) + (C>0).astype(int) + (C>1).astype(int)
>
> R = np.choose(A, (-1, -C, C, 1))
>

OK, now I get it: np.choose(A[0,:,:], (-1,-C,C,-1)) and
np.choose(A[0,:,0].reshape((3,1)), (-1,-C,C,1)), e.g., also work, but
np.choose(A[0,:,0], (-1,-C,C,-1)) doesn't - what's necessary for choose's
arguments is that both can be broadcast to a common shape (as you state
below), but choose won't reshape the arguments for you to make this
possible, you have to do so yourself first, if necessary.  That does appear
to be what's happening now; but do we want choose to be smarter than that
(e.g., for np.choose(A[0,:,0], (-1,-C,C,-1)) to work, so that the user
doesn't need to include the .reshape((3,1)))?

DG

> Requv = np.minimum(np.abs(C),1)
>
> or:
>
> def wedge(*functions):
>     """Return a function whose value is the minimum of those of
> functions"""
>     def wedgef(X):
>          fXs = [f(X) for f in functions]
>          A = np.argmin(fXs, axis=0)
>          return np.choose(A,fXs)
>     return wedgef
>
> so e.g. np.abs is -wedge(lambda X: X, lambda X: -X)
>
> This works no matter what shape of X the user supplies - so a wedged
> function can be somewhat ufunclike - by making A the same shape.
>
> >> The (i0, i1, ..., iN) element of the output array
> >> is obtained by looking at the (i0, i1, ..., iN) element of a, which
> >> should be an integer no larger than M; say j. Then r[i0, i1, ..., iN]
> >> = cj[i0, i1, ..., iN]. That is, each element of the selector array
> >> determines which of the choice arrays to pull the corresponding
> >> element from.
> >
> > That's pretty clear (thanks for doing my work for me). ;-), Yet, see
> above.
> >
> >> For example, suppose that you are processing an array C, and have
> >> constructed a selector array A the same shape as C in which a value is
> >> 0, 1, or 2 depending on whether the C value is too small, okay, or too
> >> big respectively. Then you might do something like:
> >>
> >> C = np.choose(A, [-inf, C, inf])
> >>
> >> This is something you might want to do no matter what shape A and C
> >> have. It's important not to require that the choices be an array of
> >> choices, because they often have quite different shapes (here, two are
> >> scalars) and it would be wasteful to broadcast them up to the same
> >> shape as C, just to stack them.
> >
> > OK, that's a pretty generic use-case, thanks; let me see if I understand
> it
> > correctly: A is some how created independently with a 0 everywhere C is
> too
> > small, a 1 everywhere C is OK, and a 2 everywhere C is too big; then
> > np.choose(A, [-inf, C, inf]) creates an array that is -inf everywhere C
> is
> > too small, inf everywhere C is too large, and C otherwise (and since -inf
> > and inf are scalars, this implies broadcasting of these is taking place).
> > This is what you're asserting *should* be the behavior.  So, unless there
> is
> > rationally be held) np.choose definitely presently has a bug, namely, the
> > index array can't be of arbitrary shape.
>
> There seems to be some disagreement between versions, but both Josef
> and I find that the index array *can* be arbitrary shape. In numpy
> 1.2.1 I find that all the choose items must be the same shape as it,
> which I think is a bug.
>
> What I suggested might be okay was if the index array was not
> broadcasted, so that the outputs always had exactly the same shape as
> the index array. But upon reflection it's useful to be able to use a
> 1-d array to select rows from a set of matrices, so I now think that
> all of A and the elements of choose should be broadcast to the same
> shape. This seems to be what Josef observes in his version of numpy,
> so maybe there's nothing to do.
>
> Anne
>
> > DG
> >
> >>
> >> Anne
> >> _______________________________________________
> >> NumPy-Discussion mailing list
> >> NumPy-Discussion@scipy.org
> >> http://mail.scipy.org/mailman/listinfo/numpy-discussion
> >
> >
> > _______________________________________________
> > NumPy-Discussion mailing list
> > NumPy-Discussion@scipy.org
> > http://mail.scipy.org/mailman/listinfo/numpy-discussion
> >
> >
> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion@scipy.org
> http://mail.scipy.org/mailman/listinfo/numpy-discussion
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.scipy.org/pipermail/numpy-discussion/attachments/20091108/2b4484a6/attachment-0001.html
```