在这里插入图片描述

1. 首先我们来看视图view
先看看NumPy文档里对ndarray.view方法的说明:
  • ndarray.view(dtype=None, type=None)
  • New view of array with the same data。
  • 返回数据的新视图。
先不看它的参数,我们先使用参数均为None的版本,它返回数据的一个新视图。除了view()方法,还有我们熟悉的reshape()方法也可以返回一个视图,至于其他也能返回视图的方法我们后文再提。等等,上面的中英文说明还是没说清楚视图到底是个啥概念啊?这里先不作多余的解释,直接上代码 + 图吧。
import numpy as np
a = np.arange(10)

b = a.reshape(5,2)  

c = a.view()  
c.shape = (2,5)

a_base = a.base
b_base = b.base
c_base = c.base
a_base, b_base, c_base
(None,
 array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
 array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
对程序的说明,
  • 首先创建一个具有10个数据的1维数组a,shape为(10, )。
  • b是reshape方法返回的a的一个视图(view),此时b是一个2维数组,它的shape为(5,2)。
  • c是view方法返回的a的一个视图,此时c的shape为(10, ),当执行c.shape = (2, 5)后c的shape变为(2, 5)。
  • b_base和c_base说明b和c只是a的一个视图,共享数据,虽然它们的shape各不相同。
所谓有图有真相,我们还是来看下程序运行后的情况。

在这里插入图片描述

看上图,好像a、b、c指向了不同的数组,但是a、b.base、c.base指向同一个地方。这是什么个情况呢?
这里的base是什么东西,我们下文再讲。先只要知道a、b.base、c.base指向同一个地方说明其实它们指向同一份数据,只是不同的人眼里看成不同的样子,好比人都有自己的三观,会用不同的角度去看待同一个事情。
在回顾一下代码,当运行到c = a.view()这步时,结果如下图所示,此时c的三观还是和a保持一致的,

在这里插入图片描述

经过三观改造后,即执行c.shape = (2,5),视图c有新的shape。

在这里插入图片描述

接着我们来看看各个数组的base,
a.base is None
True
b.base is a
True
c.base is a
True
ndarray.base
  • NumPy文档说明: Base object if memory is from some other object.
  • base对象说明数据是否来自别的对象。
  • 上面这个例子,a.base是None,说明a自己拥有数据,不是来自别人的,而b和c的base都是a,说明它们都没有自己的数据,都是a的。
下面代码的运行结果表明,这三个数组中只有a是数据的所有者,而b和c都不是。
a.flags.owndata, b.flags.owndata, c.flags.owndata
(True, False, False)
比喻,a是一位具有共享精神的土豪,花钱买了设备和数据并且共享给别人用;b和c都没有自己的数据,它们通过联网可以访问a家的数据,他们从不同角度去看这些数据,比如用不同维度去解读这些数据,甚至还可以修改a家的数据。
b[1,1] = 88
此时,b轻敲键盘,把原来的3改成了88。结果我们看下图,三个数组里的3同时被改成88了。因为它们本来就是同一个,a共享给b和c共同维护这屁数据。

在这里插入图片描述

2. 接下来我们来看看copy
等b或者c有钱了,也可以买个移动硬盘啥的从a那里copy拷数据,直接拿到家里,这样就和a家里的数据完全分开啦。
b = a.copy().reshape(5,2)
b[1,1] = 3
b_base = b.base
上面代码说明:b花钱买了个移动硬盘,从a那里copy了一份数据,然后b还是喜欢以shape(5,2)来看数据(人到了一定年纪,三观基本定型了呀)。并且偷偷又把88改回3,此时大家再看内存中的数据,a和c看到的仍然是同一份数据,b已经脱离小伙伴,自己一个人在家里玩了,b.base不是a了,而是a的一份copy。

在这里插入图片描述

最后我们来对比一下view()和copy()的效率,
%%timeit
b = a.view()
132 ns ± 0.622 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%%timeit
b = a.copy()
267 ns ± 0.387 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
小结一下,view vs copy:
  • 修改view的数据,它base的数据也跟着变了, 而修改copy的数据,并不影响它base的数据。
  • 一个base数组(array)的不同view具有相同的base,但同一个数组的不同copy却各有其base。
  • 效率不同,copy()需要花费的时间大概是view()的2倍左右。
我们尽量保持短文形式,以方便大家利用零碎时间阅读。
本文获得原文作者授权,转载自公众号“机器学习与数学”。

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐