【发布时间】:2011-09-09 10:17:24
【问题描述】:
如何创建一个 numpy 矩阵,其元素是其索引的函数?
比如一个乘法表:a[i,j] = i*j
Un-numpy 和 un-pythonic 将创建一个零数组,然后循环。
毫无疑问,有更好的方法可以做到这一点,而无需循环。
不过,最好直接创建矩阵。
【问题讨论】:
如何创建一个 numpy 矩阵,其元素是其索引的函数?
比如一个乘法表:a[i,j] = i*j
Un-numpy 和 un-pythonic 将创建一个零数组,然后循环。
毫无疑问,有更好的方法可以做到这一点,而无需循环。
不过,最好直接创建矩阵。
【问题讨论】:
这是一种方法:
>>> indices = numpy.indices((5, 5))
>>> a = indices[0] * indices[1]
>>> a
array([[ 0, 0, 0, 0, 0],
[ 0, 1, 2, 3, 4],
[ 0, 2, 4, 6, 8],
[ 0, 3, 6, 9, 12],
[ 0, 4, 8, 12, 16]])
为了进一步解释,numpy.indices((5, 5)) 生成两个数组,其中包含一个 5x5 数组的 x 和 y 索引,如下所示:
>>> numpy.indices((5, 5))
array([[[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
[3, 3, 3, 3, 3],
[4, 4, 4, 4, 4]],
[[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]]])
当你将这两个数组相乘时,numpy 将两个数组在每个位置的值相乘并返回结果。
【讨论】:
f 的表达式是矢量化的。
我现在不在我的 python 上,但是这个有用吗?
array( [ [ i*j for j in xrange(5)] for i in xrange(5)] )
【讨论】:
np.array(( ( i*j for j in xrange(4096)) for i in xrange(4096)) ),因为它的结果是出乎意料的。 jim-holmstroem.github.io/numpy/2014/11/23/…
只是想补充一点,@Senderle 的响应可以推广到任何功能和维度:
dims = (3,3,3) #i,j,k
ii = np.indices(dims)
然后您可以将a[i,j,k] = i*j*k 计算为
a = np.prod(ii,axis=0)
或a[i,j,k] = (i-1)*j*k:
a = (ii[0,...]-1)*ii[1,...]*ii[2,...]
等
【讨论】:
对于乘法
np.multiply.outer(np.arange(5), np.arange(5)) # a_ij = i * j
一般来说
np.frompyfunc(
lambda i, j: f(i, j), 2, 1
).outer(
np.arange(5),
np.arange(5),
).astype(np.float64) # a_ij = f(i, j)
基本上,您通过np.frompyfunc 创建一个np.ufunc,然后使用索引创建outer。
不同解决方案之间的速度比较。
小矩阵:
Eyy![1]: %timeit np.multiply.outer(np.arange(5), np.arange(5))
100000 loops, best of 3: 4.97 µs per loop
Eyy![2]: %timeit np.array( [ [ i*j for j in xrange(5)] for i in xrange(5)] )
100000 loops, best of 3: 5.51 µs per loop
Eyy![3]: %timeit indices = np.indices((5, 5)); indices[0] * indices[1]
100000 loops, best of 3: 16.1 µs per loop
更大的矩阵:
Eyy![4]: %timeit np.multiply.outer(np.arange(4096), np.arange(4096))
10 loops, best of 3: 62.4 ms per loop
Eyy![5]: %timeit indices = np.indices((4096, 4096)); indices[0] * indices[1]
10 loops, best of 3: 165 ms per loop
Eyy![6]: %timeit np.array( [ [ i*j for j in xrange(4096)] for i in xrange(4096)] )
1 loops, best of 3: 1.39 s per loop
【讨论】:
一个通用的解决方案是使用np.fromfunction()
来自文档:
numpy.fromfunction(function, shape, **kwargs)通过在每个坐标上执行一个函数来构造一个数组。这 因此,结果数组在坐标 (x, y, z)。
下面的行应该提供所需的矩阵。
numpy.fromfunction(lambda i, j: i*j, (5,5))
输出:
array([[ 0., 0., 0., 0., 0.],
[ 0., 1., 2., 3., 4.],
[ 0., 2., 4., 6., 8.],
[ 0., 3., 6., 9., 12.],
[ 0., 4., 8., 12., 16.]])
函数的第一个参数是对每个坐标执行的可调用对象。如果foo 是作为第一个参数传递的函数,则foo(i,j) 将是(i,j) 的值。这也适用于更高的维度。坐标数组的形状可以通过shape参数修改。
【讨论】:
numpy 不会为每个坐标调用您的函数,而是将 x 和 y 坐标作为数组传递一次。例如,如果你想使用函数构造一个矩阵:lambda x,y: 2*x if x > y else y/2。在这种情况下,朴素的方法是唯一的选择,这是真的吗?
fromfunction() 的唯一优势是它将生成索引列表,而不是用户显式生成它。