numpy数组可以使用简单的数组表达式进行多种数据操作任务,而无需使用大量循环语句。这种使用数组表达式替代循环的操作方法,称为向量化。通过向量化,可以一次性地在一个复杂对象上操作,或者将函数应用于一个复杂对象,避免了在对象的单个元素上使用复杂循环语句完成操作任务,达到代码更紧凑,执行速度更快的代码实现效果。
numpy中关于ndarry对象的循环操作是通过高效优化的c代码实现,执行速度远快于纯python。通常,向量化的数组操作比纯python的等价实现在速度上快1~2个数量级。这为实现高效的数值计算奠定了基础。
import numpy as np
import time
a = np.arange(10000, dtype = float)
b = np.arange(10000, 0, -1, dtype = float)
begin = time.time() #未使用向量化
results = []
for i,j in zip(a,b)
results.append(i*j)
end=time.time()
print('纯python运行时间:', begin-end)
begin = time.time() #使用向量化
results = a*b
end = time.time()
print('向量化运行时间:', begin-end)
#纯python运行时间:0.02645111083984375
#向量化运行时间:0.0027115345001220703
运行一下,可以看出,与纯python的循环语句实现相比,使用numpy的数组向量化操作完成同样的功能,运算效率提高了将近10倍。
numpy的广播机制是实现向量化计算的有效方式。当需要处理的数组维度不一致时,numpy广播机制提供了不同形状的数组仍然能够计算的实现机制。
作为多维向量的组合,数组(或者称向量)计算大多在相同形状的数组之间进行,要求被处理的数组维度以及每个维度大小是相同的,这时的数组操作应用在元素上,即数组元素——对应操作。但是,许多计算可能涉及到一个维度与其他所有维度之间的操作,此时被操作的数组大小不同。当两个形状并不相同的数组参与运算时,可以使用扩展数组的方式实现相加、相减、相乘等操作,这种机制成为广播(broadcasting)。numpy采用广播机制来实现不同形状的数组间运算。
import numpy as np
x = np.array([[2,2,3][1,2,3]])
y = np.array([[1,2,3][2,2,4]])
print(x*y) #numpy数组相乘是对应元素的乘积,与线性代数的矩阵相乘不一样
#[[2,2,9][2,4,12]]
两个numpy数组的相加、相减和相乘都是对应元素的操作。如果像个数组x和y的形状相同,即满足a.shape == b.shape ,那么x*y的运算结果是数组x和y数组对应元素相乘。这里要求两个数组维数相同,且各维度的长度相同。
import numpy as np
np.arange(6).reshape(2,3).shape
#(2,3)
np.arange(10).reshape(2,5).shape
#(2,5)
np.arange(6).reshape((3,2))+np.arange(10).reshape(5.2)
#------ValueError Traceback (most recent call last)
in
----> 1 np.arange(6).reshape((3,2))+np.arange(10).reshape(5.2)
ValueError: operands could not be broacast together with shapes(3,2)(5,2)
当参与运算的两个数组形状不一致时,如果数组形状符合广播机制的要求,numpy将自动触发广播机制。通俗地说,首先将两个数组的维度大小右对齐,然后比较对应维度上的数值,如果数值相等或其中有一个为1或者为空,那么能够进行广播运算,并且输出维度的大小取数值大的维度值。否则不能进行数组运算。
广播机制遵循的规则:
第一,所有输入的数组都向其中shape最长的数组看齐,shape不足的部分通过在小维度数组的前面添加长度为1的维度补齐;
第二,输出数组的shape是输入数组shape中各个维度上的最大值;
第三,输入数组的某个维度长度为1时,沿着此维度运算时都用该维度上的第一组值
import numpy as np
np.arange(3) + 5 #一维数组与数字的运算,向量与标量的运算
#array([5,6,7])
np.ones((3,3)) + np.arange(3)
#array([[1,2,3.],[1,2,3.],[1,2,3.]])
np.arange(3).reshape((3,1)) + np.arange(3)
#array([[0,1,2],[1,2,3],[2,3,4]])
广播机制将维度或形状比较小的数组扩展到更大的范围,以便两个参与操作的数组维度相同,各维度的长度相同,达到数组形状可兼容,然后实现两个相同形状数组对应元素之间的操作。
ufunc(universal function)函数意为“通用函数”,是一种能够对数组中每个元素进行操作的函数。ufunc函数对输入数组进行基于元素级别的运算,输出结果为numpy数组。numpy中许多ufunc内置函数的底层代码是基于C语言实现的,也因此对一个数组进行重复运算时,使用ufunc函数的计算速度比使用math标准库函数要快很多。但是,在对单个数值进行运算时,python提供的运算要比numpy执行效率高。
常用的ufunc函数:
ceil()函数对数组元素向上取整,返回向上最接近该元素的整数;
floor()函数对数组元素向下取整,返回向下最接近该元素的整数;
rint()函数对数组元素进行四舍五入,返回最接近的整数;
isnan()函数用于判断数组元素是否为NaN(Not a Number)。
import numpy as np
arr = np.random.randn(2,3)
print(arr)
# [[-1.14243468 0.62343218 1.10789425]
# [ 0.14386543 0.90263521 1.13352443]]
print(np.ceil(arr))
print(np.floor(arr))
print(np.rint(arr))
print(np.isnan(arr))
# [[-1. 1. 2.]
# [1. 1. 2. ]]
# [[-2. 0. 1.]
# [0. 0. 1.]]
# [[-1. 1. 1.]
# [0. 1. 1.]]
# [[False False False]
# [False False False]]
muitiply()函数用于元素相乘 ,等同于数组的 “*” 操作,需要注意该操作与数学中的矩阵乘法不同;
divide()函数用于元素相除,等同于数组的 "/" 操作。
import numpy as np
np.multiply(np.arange(3),5)
# array([0, 5, 10])
np.arangr(3) * 5
# array([0, 5, 10])
np.divide(np.arange(3),5)
# array([0. ,0.2, 0.4])
np.arrange(3)/5
# array([0. ,0.2, 0.4])