【问题标题】:How to do a reduction with numpy.nditer in the first axis如何在第一个轴上使用 numpy.nditer 进行缩减
【发布时间】:2012-09-30 17:05:48
【问题描述】:

我正在尝试了解如何与 nditer 合作 减少,在我的例子中,将 3d 数组转换为 2d 数组。

我按照这里的帮助 http://docs.scipy.org/doc/numpy/reference/arrays.nditer.html 和 设法创建了一个在最后一个轴上应用归约的函数 的输入。有了这个功能

def nditer_sum(data, red_axes):
    it = numpy.nditer([data, None],
            flags=['reduce_ok', 'external_loop'],
            op_flags=[['readonly'], ['readwrite', 'allocate']],
            op_axes=[None, red_axes])
    it.operands[1][...] = 0

    for x, y in it:
        y[...] = x.sum()

    return it.operands[1]

我可以得到与 data.sum(axis=2) 等价的东西

>>> data = numpy.arange(2*3*4).reshape((2,3,4))
>>> nditer_sum(data, [0, 1, -1])
[[ 6 22 38]
[54 70 86]]
>>> data.sum(axis=2)
[[ 6 22 38]
[54 70 86]]

所以要获得与 data.sum(axis=0) 等价的东西,我认为它 足以将参数 red_axes 更改为 [-1, 0,1] 但结果却大不相同。

>>> data = numpy.arange(2*3*4).reshape((2,3,4))
>>> data.sum(axis=0)
[[12 14 16 18]
 [20 22 24 26]
 [28 30 32 34]]
>>> nditer_sum(data, [-1, 0, 1])
[[210 210 210 210]
 [210 210 210 210] 
 [210 210 210 210]]

在 nditer_sum 内部的 for 循环中(对于其中的 x,y :),迭代器是 循环 2 次并每次给出一个长度为 12 的数组,而不是 循环 12 次,每次给出一个长度为 2 的数组。我有 多次阅读 numpy 文档并在 Google 上搜索到 徒劳无功。我正在使用 numpy 1.6 和 python 2.7

【问题讨论】:

  • -1 in op_axes 被记录为“新轴”,这是你想要做的吗?文档也将 [[size x]、[size y]、[size z]] 输入 op_axes,而您推送 [None, [size 3]],这是有意的吗?
  • documentation 说“操作数是从迭代器的维度到操作数的维度的映射”......不管这意味着什么。在当前示例中,我复制了iterating over arrays tutorial 中的代码,该代码有效,但仅适用于最后一个轴。在示例中,3d 数组的 op_axes None (这似乎相当于 [-1, -1, -1])和 2d 轴有 [0, 1, -1]
  • 我虽然将 [0,1,-1] 更改为 [-1, 0, 1] 会减少第一个轴,但它不起作用。我的问题是如何在任意轴上进行缩减。
  • 把这个问题发给开发者然后回到这里?我也想知道。

标签: python numpy


【解决方案1】:

如果将nditer 的顺序更改为Faxis=0 的情况会正常工作。现在有 12 个步骤,其中包含您想要的大小为 (2,) 的数组。

it = np.nditer([data, None],
        flags=['reduce_ok', 'external_loop'],
        op_flags=[['readonly'], ['readwrite', 'allocate']],
        order='F',     # ADDED to loop starting with the last dimension
        op_axes=[None, red_axes])

但是对于中间的axis=1案例,没有这样的解决方案。


对选定维度进行迭代的另一种方法是在降维数组上构造一个“multi_index”迭代器。我在https://stackoverflow.com/a/25097271/901925 中发现np.ndindex 使用这个技巧来执行“浅迭代”。

对于axis=0 的情况,此函数有效:

def sum_1st(data):
    y = np.zeros(data.shape[1:], data.dtype)
    it = np.nditer(y, flags=['multi_index'])
    while not it.finished:
        xindex = tuple([slice(None)]+list(it.multi_index))
        y[it.multi_index] = data[xindex].sum()
        it.iternext()
    return y

或推广到任意轴:

def sum_any(data, axis=0):
    yshape = list(data.shape)
    del yshape[axis]
    y = np.zeros(yshape, data.dtype)
    it = np.nditer(y, flags=['multi_index'])
    while not it.finished:
        xindex = list(it.multi_index)
        xindex.insert(axis, slice(None))
        y[it.multi_index] = data[xindex].sum()
        it.iternext()
    return y

【讨论】:

    【解决方案2】:

    将行 y[...] = x.sum() 更改为 y[...] += x 可以修复它(如示例中的 here)。

    【讨论】:

    • 但这不是我想做的。我正在使用一个更复杂的函数,它对 x 执行大量操作。想象一下,而不是总和是“将 x 的上下 10% 裁剪后的总和”
    • 我只是说修复使行为与指定任何轴的 numpy.sum 一致,这似乎是问题......也许你应该在问题中添加细节。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2017-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多