使用fromfunction和数组填充numpy矩阵

时间:2014-07-14 15:34:24

标签: python arrays numpy

我有一个名为phases的数组,让我们说它看起来像这样:

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

我现在想要填充一个矩阵,其中每一行都是一个函数f应用于连续的阶段索引,每列都是它的倍数,看起来像这样:

[[ 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]) ]]

我们可以说f就像示例一样简单,例如f(x) = x+1

所以我认为我只会使用numpy.fromfunction,如下所示:

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

但这给了我一个错误:

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

如何在i内访问phases的{​​{1}}元素?

或者这是错误的做法?

2 个答案:

答案 0 :(得分:4)

numpy.fromfunction无法正常工作,其文档也具有误导性。 不为每个单元调用该函数,而是对所有索引调用一次。

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

现在,要获得结果,您可以执行以下操作:

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将执行两个向量的外积,正是你想要的除了函数之外。

您的函数必须能够处理数组。对于非平凡的操作,您必须对函数进行矢量化,以便逐个单元地应用它。在您的示例中,您不必关心。

答案 1 :(得分:1)

我认为遵循NumPy惯用法(因此矢量化很好)的最简单方法是首先制作你想要的矩阵,然后将你的函数f应用到它。

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

这为您提供了表格

的矩阵(实际上是ndarray
[[ phases[0] 2*phases[0] 3*phases[0] ]
 [ phases[1] 2*phases[1] 3*phases[1] ]
    ...        ...        ...      
 [ phases[9] 2*phases[9] 3*phases[9] ]]

然后您可以将您的功能应用到。

>>> 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 ]])

这仅适用于您的函数f是“向量化”的,也就是说它接受ndarray并在该数组上按元素操作。如果情况并非如此,那么您可以使用numpy.vectorize来获取该功能的版本。

>>> 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 ]])