使用fromfunction和数组填充numpy矩阵
我有一个叫做 phases
的数组,假设它看起来是这样的:
phases = numpy.random.uniform(0,1,10)
现在我想创建一个矩阵,这个矩阵的每一行都是某个函数 f
应用到 phases
中的每个元素上,而每一列则是这个元素的倍数,最终的样子大概是这样的:
[[ 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
我该如何在 fromfunction
中访问 phases
的第 i
个元素呢?
或者说,这样做是不是不对的方式呢?
2 个回答
1
我觉得最简单的方法是先创建你想要的矩阵,然后再把你的函数 f
应用到这个矩阵上,这样做符合 NumPy 的使用习惯,也能很好地进行向量化处理。
>>> 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 ]])
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
函数会计算两个向量的外积,正好是你想要的效果,只不过是用不同的方式。
你的函数必须能够处理数组。对于比较复杂的操作,你需要将函数“向量化”,这样它才能逐个单元格地应用。在你的例子中,你不需要太担心这个问题。