一、引言
在我们操作数组的时候,返回的是新数组还是原数组的链接,我们就需要了解对象副本和视图的区别。
向量化和广播是numpy内部实现的基础。
二、对象副本和视图
我们应该注意到,在操作数组的时候返回的不是视图就是副本。
副本:复制
视图:链接
1.所有的赋值运算不会为此创建副本。把数组a赋值给了数组b,实际上不是为数组a创建副本,b只是调用a的另一种方式。实际上,修改了b数组的第二个元素,a数组的第二个数组也随之被改变。
In [1]: a = np.array([1,2,3,4,5]) In [2]: a Out[2]: array([1, 2, 3, 4, 5]) In [3]: b = a In [4]: b Out[4]: array([1, 2, 3, 4, 5]) #修改b数组的第二个元素,a数组的第二个元素也随即改变 In [5]: b[1] = 6 In [6]: a Out[6]: array([1, 6, 3, 4, 5])
2.切片操作得到的结果也是指向相同的对象。
In [9]: c = a[0:2] In [10]: c Out[10]: array([1, 6]) In [11]: c[0] = 5 In [12]: a Out[12]: array([5, 6, 3, 4, 5])
3.为数组创建副本,使用copy()
In [12]: a Out[12]: array([5, 6, 3, 4, 5]) In [13]: a = np.array([1,2,3,4]) In [14]: d = a.copy() In [15]: d Out[15]: array([1, 2, 3, 4]) In [16]: d[0] = 5 #数组d元素的改变并不会影响数组a In [17]: a Out[17]: array([1, 2, 3, 4])
三、向量化
有了向量化,编写code时无需使用循环,因为他在内部已经实现了。向量化使得代码更简洁,可读性更强。
数组相乘可以:a * b 而不需要for遍历数组相乘。
四、广播机制
1、广播机制实现了对两个或以上数组的运算或函数处理,即使这些数组的形状或长短不完全相同。
2、广播机制条件(满足其一即可):1.两个数组的每一维等长 2.其中一个数组为一维数组
3、广播机制有两条规则:
1)为确实的维度补上个1.如果这时满足了兼容性条件,就可以使用广播机制了。
2)扩展最小数组,使得它与最大的数组大小相同,以便使用元素级的函数或运算符。
In [17]: a = np.array([1,2,3]) Out[17]: array([1, 2, 3,]) In [18]: b = np.arange(0,9).reshape(3,3) In [19]: b Out[19]: array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) #假定为数组a用已有的值进行了填充 #array([[1, 2, 3,], # [1, 2, 3,], # [1, 2, 3,]]) In [20]: a+b Out[20]: array([[1, 3, 5], [4, 6, 8], [7, 9, 11]])
假定(一维数组)使用了原有的值填充,使得与另一个数组维度相同,他们的值就可以相加了。
即使更复杂的数组,两个数组形状不同、维度不同、互有长短。也仍然相互兼容,因此广播规则仍然适用。
In [21]: m = np.arange(6).reshape(3,1,2) In [22]: n = np.arange(6).reshape(3,2,1) In [23]: m Out[23]: array([[[0, 1]], [[2, 3]], [[4, 5]]]) In [24]: n Out[24]: array([[[0], [1]], [[2], [3]], [[4], [5]]]) In [26]: m + n Out[26]: array([[[ 0, 1], [ 1, 2]], [[ 4, 5], [ 5, 6]], [[ 8, 9], [ 9, 10]]])