我有两个阵列形状,可以互相广播。
例如(2,2,1)和(2,3)
我想要一个函数,它接受这些形状,并给我一个迭代器,返回这些数组中的索引,并将这些形状一起广播,以及结果输出数组中的索引。
iter, output_shape = broadcast_indeces_iterator((2, 2, 1), (2, 3))
assert output_shape == (2, 2, 3)
for in1_ix, in_2_ix, out_ix in iter:
print (in1_ix, in_2_ix, out_ix) 产出结果:
(0, 0, 0), (0, 0), (0, 0, 0)
(0, 0, 0), (0, 1), (0, 0, 1)
(0, 0, 0), (0, 2), (0, 0, 2)
(0, 1, 0), (1, 0), (0, 1, 0)
(0, 1, 0), (1, 1), (0, 1, 1)
(0, 1, 0), (1, 2), (0, 1, 2)
(1, 0, 0), (0, 0), (1, 0, 0)
(1, 0, 0), (0, 1), (1, 0, 1)
(1, 0, 0), (0, 2), (1, 0, 2)
(1, 1, 0), (1, 0), (1, 1, 0)
(1, 1, 0), (1, 1), (1, 1, 1)
(1, 1, 0), (1, 2), (1, 1, 2)np.broadcast做了一些相近的事情,但需要实际创建的数组。
发布于 2014-11-29 02:12:35
import numpy as np
x = 10*np.arange(4).reshape((2, 2, 1))
y = 100*np.arange(6).reshape((2, 3))
z = np.nditer([x, y], flags=['multi_index', 'c_index'], order='C')
for a,b in z:
print(np.unravel_index(z.index % x.size, x.shape)
, np.unravel_index(z.index % y.size, y.shape)
, z.multi_index)收益率
((0, 0, 0), (0, 0), (0, 0, 0))
((0, 1, 0), (0, 1), (0, 0, 1))
((1, 0, 0), (0, 2), (0, 0, 2))
((1, 1, 0), (1, 0), (0, 1, 0))
((0, 0, 0), (1, 1), (0, 1, 1))
((0, 1, 0), (1, 2), (0, 1, 2))
((1, 0, 0), (0, 0), (1, 0, 0))
((1, 1, 0), (0, 1), (1, 0, 1))
((0, 0, 0), (0, 2), (1, 0, 2))
((0, 1, 0), (1, 0), (1, 1, 0))
((1, 0, 0), (1, 1), (1, 1, 1))
((1, 1, 0), (1, 2), (1, 1, 2))发布于 2014-11-28 23:13:53
彼得,这是个多么好的问题。这是你的回答:
import numpy as np
def get_broadcast_shape(*shapes):
'''
Given a set of array shapes, return the shape of the output when arrays of those
shapes are broadcast together
'''
max_nim = max(len(s) for s in shapes)
equal_len_shapes = np.array([(1, )*(max_nim-len(s))+s for s in shapes])
max_dim_shapes = np.max(equal_len_shapes, axis = 0)
assert np.all(np.bitwise_or(equal_len_shapes==1, equal_len_shapes == max_dim_shapes[None, :])), \
'Shapes %s are not broadcastable together' % (shapes, )
return tuple(max_dim_shapes)
def get_broadcast_indeces(*shapes):
'''
Given a set of shapes of arrays that you could broadcast together, return:
output_shape: The shape of the resulting output array
broadcast_shape_iterator: An iterator that returns a len(shapes)+1 tuple
of the indeces of each input array and their corresponding index in the
output array
'''
output_shape = get_broadcast_shape(*shapes)
base_iter = np.ndindex(output_shape)
def broadcast_shape_iterator():
for out_ix in base_iter:
in_ixs = tuple(tuple(0 if s[i] == 1 else ix for i, ix in enumerate(out_ix[-len(s):])) for s in shapes)
yield in_ixs + (out_ix, )
return output_shape, broadcast_shape_iterator()
output_shape, ix_iter = get_broadcast_indeces((2, 2, 1), (2, 3))
assert output_shape == (2, 2, 3)
for in1_ix, in_2_ix, out_ix in ix_iter:
print (in1_ix, in_2_ix, out_ix)返回
((0, 0, 0), (0, 0), (0, 0, 0))
((0, 0, 0), (0, 1), (0, 0, 1))
((0, 0, 0), (0, 2), (0, 0, 2))
((0, 1, 0), (1, 0), (0, 1, 0))
((0, 1, 0), (1, 1), (0, 1, 1))
((0, 1, 0), (1, 2), (0, 1, 2))
((1, 0, 0), (0, 0), (1, 0, 0))
((1, 0, 0), (0, 1), (1, 0, 1))
((1, 0, 0), (0, 2), (1, 0, 2))
((1, 1, 0), (1, 0), (1, 1, 0))
((1, 1, 0), (1, 1), (1, 1, 1))
((1, 1, 0), (1, 2), (1, 1, 2))如果有人知道任何解决这一问题的numpy构建,那就更好了。
发布于 2014-11-30 04:43:48
以下是一个开始:
array1 = np.arange(4).reshape(2,2,1)*10
array2 = np.arange(6).reshape(2,3)
I, J = np.broadcast_arrays(array1, array2)
print I.shape
K = np.empty(I.shape, dtype=int)
for ijk in np.ndindex(I.shape):
K[ijk] = I[ijk]+J[ijk]
print K生产
(2, 2, 3) # broadcasted shape
[[[ 0 1 2]
[13 14 15]]
[[20 21 22]
[33 34 35]]]I是(2,2,3),但是它与array1共享数据--它是一个广播视图,而不是副本(看看它的.__array_interface__)。
只要给出这些形状,你就可以在二维上迭代。
K = np.empty(I.shape, dtype=int)
for i,j in np.ndindex(I.shape[:2]):
K[i,j,:] = I[i,j,:]+J[i,j,:]
print K[i,j,:]通过查看broadcast_arrays和ndindex的代码,可以对其进行细化,以找到必要的部分。例如,在https://stackoverflow.com/a/25097271/901925中,我直接调用nditer来生成multi_index (一个可以适应于cython的操作)。
xx = np.zeros(y.shape[:2])
it = np.nditer(xx,flags=['multi_index'])
while not it.finished:
print y[it.multi_index],
it.iternext()
# [242 14 211] [198 7 0] [235 60 81] [164 64 236]要制作几乎没有成本的“虚拟数组”,我可以从ndindex获得线索,并从np.zeros(1)开始制作数组。
def make_dummy(shape):
x = as_strided(np.zeros(1),shape=shape, strides=np.zeros_like(shape))
return x
array1 = make_dummy((2,2,1))
array2 = make_dummy((2,3))我可以深入研究np.broadcast_arrays,以了解它如何组合来自2个输入数组的形状,从而生成I的形状。
你想要的解决方案和我的有区别,我已经掩盖了。
(0, 0, 0), (0, 0), (0, 0, 0)
(0, 0, 0), (0, 1), (0, 0, 1)
...
(1, 1, 0), (1, 1), (1, 1, 1)
(1, 1, 0), (1, 2), (1, 1, 2)期望每个数组都有不同的迭代器元组,一个在(2,2,1)上范围,另一个在(2,3)上,等等。
我的方法(我认为是numpy c代码使用的)(至少是基于nditer的部分)在(2,2,3)上生成一个迭代器,并通过as_strided对数组进行传递,以接受更大的范围。这样更容易实现一个通用的广播机制。它将广播复杂度从计算核中分离出来。
这里是nditer的一个很好的介绍
http://docs.scipy.org/doc/numpy/reference/arrays.nditer.html
https://stackoverflow.com/questions/27196672
复制相似问题