[英]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.