4

I have an array called phases, let's say it looks like this:

phases = numpy.random.uniform(0,1,10)

I now want to populate a matrix where every row is some function f applied to a successive index of phases, and every column is a multiple of it, looking something like this:

[[ f(phases[0]) f(2*phases[0]) f(3*phases[0]) ]
 [ f(phases[1]) f(2*phases[1]) f(3*phases[1]) ]
       ...            ...           ...      
 [ f(phases[9]) f(2*phases[9]) f(3*phases[9]) ]]

We can say f is something simple for the sake of example, like f(x) = x+1.

So I figured I would just use numpy.fromfunction as follows:

numpy.fromfunction(lambda i,j: (j+1)*phases[i]+1,
                   (phases.size, 3), dtype=float)

but this gives me an error:

IndexError: arrays used as indices must be of integer (or boolean) type

How can I access the ith element of phases within fromfunction?

Or is this the wrong approach to take?

2 Answers 2

4

numpy.fromfunction does not work as expected, its documentation is also misleading. The function is not called for each cell, but once with all indices.

def fromfunction(function, shape, **kwargs):
    dtype = kwargs.pop('dtype', float)
    args = indices(shape, dtype=dtype)
    return function(*args,**kwargs)

So now, to get your result, you can do the following :

In [57]: vf = numpy.vectorize(f)

In [58]: vf(numpy.outer(phases, numpy.arange(1,4)))
Out[58]:
array([[ 1.87176928,  2.74353857,  3.61530785],
       [ 1.23090955,  1.4618191 ,  1.69272866],
       [ 1.29294723,  1.58589445,  1.87884168],
       [ 1.05863891,  1.11727783,  1.17591674],
       [ 1.28370397,  1.56740794,  1.85111191],
       [ 1.87210286,  2.74420573,  3.61630859],
       [ 1.08652975,  1.1730595 ,  1.25958925],
       [ 1.33835545,  1.6767109 ,  2.01506634],
       [ 1.74479635,  2.48959269,  3.23438904],
       [ 1.76381301,  2.52762602,  3.29143903]])

outer will perform the outer product of two vectors, exactly what you want except from the function.

Your function must be able to handle arrays. For non-trivial operations, you will have to vectorize the function, so that it will be applied cell-by-cell. In your example, you don't have to care.

Sign up to request clarification or add additional context in comments.

Comments

1

I think the easiest approach that follows NumPy idioms (and therefore vectorizes well) is to make the matrix you want first, and then apply your function f to it.

>>> phases = numpy.random.uniform(0,1,10)
>>> phases = phases.reshape((10, 1))
>>> phases = np.tile(phases, (1, 3))

This gives you the a matrix (actually an ndarray) of the form

[[ phases[0] 2*phases[0] 3*phases[0] ]
 [ phases[1] 2*phases[1] 3*phases[1] ]
    ...        ...        ...      
 [ phases[9] 2*phases[9] 3*phases[9] ]]

which you can then apply your function to.

>>> def f(x):
...     return numpy.sin(x)
>>> f(phases)
array([[ 0.56551297,  0.93280166,  0.97312359],
       [ 0.38704365,  0.71375602,  0.92921009],
       [ 0.62778184,  0.97731738,  0.89368501],
       [ 0.0806512 ,  0.16077695,  0.23985519],
       [ 0.4140241 ,  0.75374405,  0.95819095],
       [ 0.25929821,  0.50085902,  0.70815838],
       [ 0.25399811,  0.49133634,  0.69644753],
       [ 0.7754078 ,  0.97927926,  0.46134512],
       [ 0.53301912,  0.90197836,  0.99331443],
       [ 0.44019133,  0.79049912,  0.9793933 ]])

This only works if your function, f, is "vectorized", which is to say that it accepts an ndarray and operates element-wise on that array. If that's not the case, then you can use numpy.vectorize to get a version of that function that does so.

>>> import math
>>> def f(x):
...     return math.sin(x)
>>> f(phases)
TypeError: only length-1 arrays can be converted to Python scalars
>>> f = numpy.vectorize(f)
>>> f(phases)
array([[ 0.56551297,  0.93280166,  0.97312359],
       [ 0.38704365,  0.71375602,  0.92921009],
       [ 0.62778184,  0.97731738,  0.89368501],
       [ 0.0806512 ,  0.16077695,  0.23985519],
       [ 0.4140241 ,  0.75374405,  0.95819095],
       [ 0.25929821,  0.50085902,  0.70815838],
       [ 0.25399811,  0.49133634,  0.69644753],
       [ 0.7754078 ,  0.97927926,  0.46134512],
       [ 0.53301912,  0.90197836,  0.99331443],
       [ 0.44019133,  0.79049912,  0.9793933 ]])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.