如何创建一个 NumPy 数组的视图?

106

我有一个二维的numpy数组。是否有一种方式可以创建一个视图,其中包括前k行和所有列?

关键是要避免复制底层数据(该数组非常大,因此无法进行部分复制)。

1个回答

256

当然,只需像平常一样索引即可。例如:y = x[:k, :] 这将返回原始数组的一个视图。不会复制任何数据,并且对y所做的任何更新将反映在x中,反之亦然。


编辑:

我通常使用超过10GB的3D uint8数组,所以我非常担心这个... 如果你记住一些要点,Numpy在内存管理方面可以非常高效。 以下是一些避免在内存中复制数组的技巧:

使用+=-=*=等操作符避免复制数组。例如,x += 10会就地修改数组,而x = x + 10会复制它并进行修改。(还可以看看numexpr)

如果你确实想用x = x + 10复制一个数组,请注意x = x + 10.0会导致x自动向上转换为浮点数组(如果它还不是的话)。但是,如果x是整数数组,则x += 10.0会将10.0下转换为与数组相同精度的整数。

此外,许多numpy函数都可以使用out参数,因此您可以像这样进行操作:np.abs(x, x)就地取x的绝对值。


第二个编辑,以下是有关numpy数组视图和副本的几个提示:

与Python列表不同,y = x [:] 不返回副本,而是返回视图。 如果您确实需要副本(这当然会将您使用的内存量加倍),请使用 y = x.copy()
通常会听到"numpy数组的高级索引"Fancy Indexing"。 使用列表(或整数数组)作为索引是"fancy indexing"。 它非常有用,但会复制数据。
例如:y = x[[0, 1, 2], :] 返回一个副本,而y = x[:3,:] 将返回一个视图。
即使是像x [4: 100: 5,:-10:-1,None] 这样的非常规索引也是"normal indexing",并且将返回一个视图,因此不要害怕在大型数组上使用各种切片技巧。 x.astype(<dtype>)将返回数据的新类型的副本,而x.view(<dtype>)将返回一个视图。
但是要小心...它非常强大和有用,但您需要了解底层数据如何存储在内存中。 如果您有一个浮点数组,并将其视为整数(或反之亦然),numpy将解释数组的底层位作为整数。
例如,这意味着64位小端系统上的1.0将被视为64位整数4607182418800017408,如果将其视为uint8,则为[0, 0, 0, 0, 0, 0, 240, 63]的数组。 这在需要对大型数组进行位操作时非常方便...您可以低级别地控制内存缓冲区的解释方式。

谢谢你提供这些非常好的技巧!我正在阅读Numpy用户指南,对于为什么x[np.array([1, 1, 3, 1])] += 1会修改x感到困惑。现在我明白了! - tnq177
1
不错的技巧!我还有一个问题。如何证明numpy不会触发复制,而只是视图?Python的id()似乎无法做到这一点。 - wuhaochi
4
如果ba的一个视图(view),那么b.base is a会返回True。任何数组的拷贝(copy)都会使得arr_copy.base is None成立。 - Jürg W. Spaak
1
我非常感谢这些建议—— 我已经使用numpy工作了几年,但是其中一些内容对我来说完全不知道! - corvus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接