繁体   English   中英

理解 numpy 自引用赋值

[英]Understanding numpy self-referencing assignment

给定一个像这样的自引用赋值:

x = np.array(range(5))
y = x[:-1]
print(x, y)
y[0] = 9
print(x, y)
x[1:] = y
print(x, y)

我最终得到以下 output:

[0 1 2 3 4] [0 1 2 3]
[9 1 2 3 4] [9 1 2 3]
[9 9 1 2 3] [9 9 1 2]

有人可以解释一下 numpy 在将其值分配给x之前避免覆盖y的幕后操作吗? 例如,如果我们将赋值x[1:] = y替换为 for 循环,则 output 的最后一行不同:

x = np.array(range(5))
y = x[:-1]
print(x, y)
y[0] = 9
print(x, y)

for idx in range(1, len(x)):
    x[idx] = y[idx-1]
print(x,y)
[0 1 2 3 4] [0 1 2 3]
[9 1 2 3 4] [9 1 2 3]
[9 9 9 9 9] [9 9 9 9]

一般来说,在更改内存映射 ndarray 的宽度时,我可以依赖观察到的行为吗? 或者,如果 numpy 在分配之前创建视图的副本,这是否毫无意义?

所以你有一个简单的一维数组:

In [358]: x = np.array(range(5))
In [359]: x
Out[359]: array([0, 1, 2, 3, 4])
In [360]: x = np.arange(5)
In [361]: x
Out[361]: array([0, 1, 2, 3, 4])

y是一个视图 - 除了最后一个:

In [362]: y = x[:-1]
In [363]: y
Out[363]: array([0, 1, 2, 3])
In [364]: y[0] = 9
In [365]: x
Out[365]: array([9, 1, 2, 3, 4])

修改y也会改变x

In [366]: x[1:]
Out[366]: array([1, 2, 3, 4])
In [367]: x[1:] = y
In [368]: x
Out[368]: array([9, 9, 1, 2, 3])

此分配被缓冲。 该缓冲的详细信息通常没有记录,但np.add.at等函数的文档暗示了这一点。 虽然这解释了您看到的行为,但我不知道假设它是否安全。 添加副本足够便宜:

x[1:] = y.copy()

add.at所示,人们通常会被缓冲所困扰,至少在某些索引重复的情况下是这样。 我想不出一个.at的方式来做你的迭代案例。


有一种形式的view复制会咬人——例如尝试切换二维数组的行:

In [392]: arr = np.arange(12).reshape(3,4)
In [393]: arr
Out[393]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
In [394]: arr[0],arr[1] = arr[1],arr[0]
In [395]: arr
Out[395]: 
array([[ 4,  5,  6,  7],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

这里arr[0]arr[1]之前更新。 这种分配适用于列表,但因为arr[i]是一个view ,它在列表中失败。

高级索引解决了这个问题。 RHS 是一个副本,因此在分配过程中不会搞砸。

In [396]: arr = np.arange(12).reshape(3,4)
In [397]: arr[[0,1]] = arr[[1,0]]
In [398]: arr
Out[398]: 
array([[ 4,  5,  6,  7],
       [ 0,  1,  2,  3],
       [ 8,  9, 10, 11]])

我不知道是否可以用您的 1d x构建这样的示例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM