首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从形状看Numpy广播索引

从形状看Numpy广播索引
EN

Stack Overflow用户
提问于 2014-11-28 22:27:18
回答 3查看 379关注 0票数 2

我有两个阵列形状,可以互相广播。

例如(2,2,1)和(2,3)

我想要一个函数,它接受这些形状,并给我一个迭代器,返回这些数组中的索引,并将这些形状一起广播,以及结果输出数组中的索引。

代码语言:javascript
运行
复制
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)    

产出结果:

代码语言:javascript
运行
复制
(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做了一些相近的事情,但需要实际创建的数组。

  • 请注意,NumPy people:如果np.broadcast有一个额外的参数,允许您在过去的2维中不进行迭代,那就太好了。这也能解决我的问题。
EN

回答 3

Stack Overflow用户

发布于 2014-11-29 02:12:35

代码语言:javascript
运行
复制
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)

收益率

代码语言:javascript
运行
复制
((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))
票数 3
EN

Stack Overflow用户

发布于 2014-11-28 23:13:53

彼得,这是个多么好的问题。这是你的回答:

代码语言:javascript
运行
复制
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)

返回

代码语言:javascript
运行
复制
((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构建,那就更好了。

票数 1
EN

Stack Overflow用户

发布于 2014-11-30 04:43:48

以下是一个开始:

代码语言:javascript
运行
复制
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

生产

代码语言:javascript
运行
复制
(2, 2, 3)  # broadcasted shape

[[[ 0  1  2]
  [13 14 15]]    
 [[20 21 22]
  [33 34 35]]]

I(2,2,3),但是它与array1共享数据--它是一个广播视图,而不是副本(看看它的.__array_interface__)。

只要给出这些形状,你就可以在二维上迭代。

代码语言:javascript
运行
复制
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_arraysndindex的代码,可以对其进行细化,以找到必要的部分。例如,在https://stackoverflow.com/a/25097271/901925中,我直接调用nditer来生成multi_index (一个可以适应于cython的操作)。

代码语言:javascript
运行
复制
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)开始制作数组。

代码语言:javascript
运行
复制
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的形状。

你想要的解决方案和我的有区别,我已经掩盖了。

代码语言:javascript
运行
复制
(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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27196672

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档