numpy 数组复制与广播机制
一、视图和复制
1. 完全不复制
下面的结果,是因为数组是一个可变的对象:
>>> a = np.arange(12)
>>> b = a # 不会创建新的数组对象,而是多了一个引用
>>> b is a # a和b只是同一个数组的两个名字
True
>>> b.shape = 3,4 # 会同时修改a的形状
>>> a.shape
(3, 4)
2. view视图
不同的数组对象可以共享同样的数据。view方法就可以实现这一操作:
>>> c = a.view() # 现在开始c是一个新的数组,并且和a共享数据
>>> c is a # 说明c和a是两个不同的对象
False
>>> c.base is a # c是a数组的数据视图
True
>>> c.flags.owndata # 可以看到c没有自己的数据
False
>>>
>>> c.shape = 2,6 # a的形状不会发生改变
>>> a.shape
(3, 4)
>>> c[0,4] = 1234 # 但是a的数据会跟着发生改变
>>> a
array([[ 0, 1, 2, 3],
[1234, 5, 6, 7],
[ 8, 9, 10, 11]])
理解view,只需要注意两者共享数据,此外其它所有都是独立的。
切片操作,则会返回一个数组的view视图:
>>> s = a[ : , 1:3]
>>> s[:] = 10 # s[:]是s的一个视图。注意与s=10区分开,不要混淆。
>>> a
array([[ 0, 10, 10, 3],
[1234, 10, 10, 7],
[ 8, 10, 10, 11]])
3. 深度拷贝
copy方法生成数组的一个完整的拷贝,包括其数据。
>>> d = a.copy()
>>> d is a
False
>>> d.base is a
False
>>> d[0,0] = 9999
>>> a
array([[ 0, 10, 10, 3],
[1234, 10, 10, 7],
[ 8, 10, 10, 11]])
二、广播机制
广播允许通用函数以有意义的方式处理异构的输入。也就是让形状不一样的数组在进行运算的时候,能够得到合理的结果。其规则如下:
- 让所有输入数组都向其中shape最长的数组看齐,shape中不足的部分都通过在前面加1补齐。
- 输出数组的shape是输入数组shape的各个轴上的最大值。
- 如果输入数组的某个轴和输出数组的对应轴的长度相同或者其长度为1时,这个数组能够用来计算,否则出错。
- 当输入数组的某个轴的长度为1时,沿着此轴运算时都用此轴上的第一组值。
应用广播规则后,所有数组的大小将会匹配。请看下面的例子,加深理解:
>>> a=np.array([[0,0,0], [10,10,10],[20,20,20],[30]*3])
>>> a
array([[ 0, 0, 0],
[10, 10, 10],
[20, 20, 20],
[30, 30, 30]])
>>> b = np.array([0,1,2])
>>> b
array([0, 1, 2])
>>> a + b
array([[ 0, 1, 2],
[10, 11, 12],
[20, 21, 22],
[30, 31, 32]])
>>> c= np.array([[1],[2],[3],[4]])
>>> c
array([[1],
[2],
[3],
[4]])
>>> a + c
array([[ 1, 1, 1],
[12, 12, 12],
[23, 23, 23],
[34, 34, 34]])