在 NumPy 中跟踪多索引和修改值

Posted

技术标签:

【中文标题】在 NumPy 中跟踪多索引和修改值【英文标题】:Tracking Multi-Index and Modifying Values in NumPy 【发布时间】:2018-07-22 02:41:45 【问题描述】:

我有一个二维数组,我正在对其进行迭代,以便使用索引值进行计算,然后将计算出的值分配给所述索引。

在 NumPy 文档中,an example 用于使用迭代器修改值:

for x in np.nditer(a, op_flags=['readwrite']):
    x[...] = 2 * x

但是,当使用 the following method 跟踪索引时,这似乎不起作用:

it = np.nditer(a, flags=['multi_index'])
while not it.finished:
    it[...] = . . .
    it.iternext()

然而,我能够使用it.multi_index 值,但它似乎不必要地冗长。有没有更简单的方法来实现这一点,通过不同的方法或不同的语法?

it = np.nditer(a, flags=['multi_index'])
while not it.finished:
    matrix[it.multi_index[0]][it.multi_index[1]] = . . .
    it.iternext()

编辑

这是一个 multi_index 迭代尝试使用迭代器索引修改值但失败的示例。

matrix = np.zeros((5,5))
it = np.nditer(matrix, flags=['multi_index'])
while not it.finished:
  it[...] = 1
  it.iternext()

产生的错误是

TypeError                                 Traceback (most recent call last)
<ipython-input-79-3f4cabcbfde6> in <module>()
     25 it = np.nditer(matrix, flags=['multi_index'])
     26 while not it.finished:
---> 27   it[...] = 1
     28   it.iternext()

TypeError: invalid index type for iterator indexing

【问题讨论】:

“这似乎行不通”这种陈述最好跟在minimal reproducible example... 【参考方案1】:

在您的第一个迭代示例中:

In [1]: arr = np.arange(12).reshape(3,4)
In [2]: for x in np.nditer(arr, op_flags=['readwrite']):
   ...:     print(x, type(x))
   ...:     x[...] = 2 * x
   ...:     
0 <class 'numpy.ndarray'>
1 <class 'numpy.ndarray'>
2 <class 'numpy.ndarray'>
3 <class 'numpy.ndarray'>
4 <class 'numpy.ndarray'>
....
11 <class 'numpy.ndarray'>
In [3]: x
Out[3]: array(22)
In [4]: arr
Out[4]: 
array([[ 0,  2,  4,  6],
       [ 8, 10, 12, 14],
       [16, 18, 20, 22]])

开启multi_index:

In [9]: it = np.nditer(arr, flags=['multi_index'],op_flags=['readwrite'])
In [10]: while not it.finished:
    ...:     print(it[0], it.multi_index)
    ...:     it.iternext()
    ...:     
0 (0, 0)
2 (0, 1)
4 (0, 2)
...
20 (2, 2)
22 (2, 3)

通过arr 的元素进行相同的迭代,但也会生成二维索引元组。 itnditer 对象,具有各种方法和属性。在这种情况下,它有一个multi_index 属性。而当前迭代变量在it[0]

我可以使用[...] 就地修改元素,也可以通过在arr 中的索引来修改元素:

In [11]: it = np.nditer(arr, flags=['multi_index'],op_flags=['readwrite'])
In [13]: while not it.finished:
    ...:     it[0][...] *= 2
    ...:     arr[it.multi_index] += 100
    ...:     it.iternext()
    ...:     

In [14]: arr       # values are doubled and add by 100
Out[14]: 
array([[100, 104, 108, 112],
       [116, 120, 124, 128],
       [132, 136, 140, 144]])

没有multi_index 我仍然可以创建一个nditer 对象,并使用while not finished 语法进行迭代。而不是访问x[...],我必须使用it[0][...]


np.ndindex 是一种更方便的生成multi_index 的方法。看它的代码。它是少数使用np.nditer 的 numpy 函数之一。

In [26]: for idx in np.ndindex(arr.shape):
    ...:     print(idx)
    ...:     arr[idx] -= 100
    ...:     
(0, 0)
(0, 1)
...
(2, 3)
In [27]: arr
Out[27]: 
array([[ 0,  4,  8, 12],
       [16, 20, 24, 28],
       [32, 36, 40, 44]])

但是

虽然使用nditer 很有趣,但它并不实用,至少在纯 Python 代码中不可行。它最适合作为在cython 或纯c 代码中使用它的垫脚石。请参阅迭代页面的最后一个示例。

【讨论】:

以上是关于在 NumPy 中跟踪多索引和修改值的主要内容,如果未能解决你的问题,请参考以下文章

Python Pandas 按多索引和列排序

合并具有多索引和列值的数据框

使用 pandas 进行多索引和绘图

pandas:选择索引,然后选择多索引切片上的列

将 numpy 数组复制到 Panda 多索引中(大小相同)

带有多索引和 parse_date 的 pandas read_excel;如何?