在循环中切片NumPy数组

bla*_*laz 6 python arrays numpy

我需要一个很好的解释(参考)来解释(for)循环中的NumPy切片.我有三个案子.

def example1(array):
    for row in array:
        row = row + 1
    return array

def example2(array):
    for row in array:
        row += 1
    return array

def example3(array):
    for row in array:
        row[:] = row + 1
    return array
Run Code Online (Sandbox Code Playgroud)

一个简单的案例:

ex1 = np.arange(9).reshape(3, 3)
ex2 = ex1.copy()
ex3 = ex1.copy()
Run Code Online (Sandbox Code Playgroud)

收益:

>>> example1(ex1)
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

>>> example2(ex2)
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

>>> example3(ex3)
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
Run Code Online (Sandbox Code Playgroud)

可以看出,第一个结果与第二个和第三个不同.

MSe*_*ert 4

第一个例子:

您提取一行并向其添加 1。然后您重新定义指针 row但不重新定义其中array包含的内容!所以不会影响原来的数组。

第二个例子:

您进行就地操作 - 显然这会影响原始数组 - 只要它是一个数组。

如果你正在做一个双循环,它就不再工作了:

def example4(array):
    for row in array:
        for column in row:
            column += 1
    return array

example4(np.arange(9).reshape(3,3))
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为您不调用np.ndarray's __iadd__(以修改数组指向的数据),而是调用 pythonint__iadd__. 所以这个例子才有效,因为你的行是 numpy 数组。

第三个例子:

row[:] = row + 1这被解释为类似row[0] = row[0]+1, row[1] = row[1]+1, ...再次起作用,因此这会影响原始数组。

底线

如果您正在操作可变对象,例如lists 或者np.ndarray您需要小心更改的内容。这样的对象仅指向实际数据存储在内存中的位置 - 因此更改此指针( example1) 不会影响保存的数据。您需要跟随指针(直接通过[:]example3)或间接通过array.__iadd__example2))来更改保存的数据。