multidimensional take

Johannes Nix jnix at aster.homelinux.net
Wed Mar 19 18:59:37 EST 2003


Johannes Nix <jnix at medi.physik.uni-oldenburg.de> writes:

> Now I want to have a function defined as following:
> 
> >>> a
> array([[140, 455, 325, 360, 498],
>        [372, 647, 636, 365, 462],
>        [893, 141, 776, 238, 259]])
> 
> >>> mtake(a, [[1, 0], [ 1, 1], [2, 4]])
> array([372, 647, 259])
> 
> 

Below is the solution I got after some hours - i does not has any
interpreted loop.  It differs a bit from the list comprehension
definition in that if a e.g. has shape (1, 2, 3, 5, 7) and b has shape
(9, 11, 13), mtake(a, b) will have shape (1, 2, 3, 9) and not (9, 1,
2, 3) , ergo 

>>> a2 = array((a, 10 * a))
>>> mtake(a2, [[1, 0], [ 1, 1], [2, 4]])
array([[ 372,  647,  259],
       [3720, 6470, 2590]])
>>> a2.shape
(2, 3, 5)


I've omitted the axis parameter because it seems confusing to
me, if necessary the axes can be changed by Numeric.transpose . In my
application, shapes of a and b will be (10000, 3, 3) and 
(2, 43, 24, 50) so this will save a large amount of computing time.
Perhaps this would be a useful addition to Numeric ?

Johannes

-------------------------------------------------------------------------
def mtake(ar, indices):
    """similar to take but uses last dimension of indices for
       coordinate lookup along last axes of ar.
    """
    indices = array(indices)
    ar = array(ar)
    if len(indices.shape) == 1:
        return a[indices]
    elif (len(indices.shape) == 2) and (indices.shape[-1] == 1):
        return take(a, indices)

    numrdims = len(ar.shape) - indices.shape[-1]
    strides = multiply.accumulate(array(ar.shape[numrdims+1:] + 
        (1,))[::-1])[::-1]
    newshape = ar.shape[:numrdims] + (strides[0] * ar.shape[numrdims],)
    ar = reshape(ar, newshape)
    return take(ar, add.reduce(strides * indices, -1), -1)

--------------------------------------------------------------------------
    




More information about the Python-list mailing list