第八天
Numpy数组通用函数
Numpy数组的计算有时非常快,有时也非常慢。使Numpy数组变快的关键是利用向量化操作,通常是在Numpy的通用函数(ufunc)中实现。
一、一般通用函数:
通用函数有两种存在形式:一元通用函数(unary ufunc)对单个输入操作,二元通用函数(binary ufunc)对两个输入操作。
1.数组的运算
Numpy通用函数得到使用方式非常自然,因为它用到了Python原生的算术运算符。
import numpy as np
x = np.arange(4)
print("x = ", x)
print("x + 5 = ", x + 5)
print("x - 5 = ", x - 5)
print("x * 2 = ", x * 2)
print("x / 2 = ", x / 2)
还有逻辑非、**表示大的指数运算符合%表示的模运算符的一元通用函数。
所有的这些算术运算符都是Numpy内置函数的简单封装器,例如+运算符就是一个add函数的封装器:
np.add(x, 2) # array([2, 3, 4, 5])
下表示Numpy实现的算术运算符。
运算符 | 对应的通用函数 | 描述 |
---|---|---|
+ | np.add | 加法运算(1+1=2) |
- | np.subtract | 减法运算(3-2=1) |
* | np.multiply | 乘法运算(2*3=6) |
/ | np.divide | 除法运算(3/2=1.5) |
// | np.floor_divide | 地板除法(3/2=1) |
** | np.power | 指数运算(2**3=8) |
% | np.mod | 模/余数(9%4=1) |
2.绝对值
正如Numpy能理解Python内置的运算符操作,Numpy也可以理解Python内置的绝对值函数:
x = np.array([-2, -1, 0, 1, 2])
abs(x) # ([2, 1, 0, 1, 2])
对应的Numpy通用函数就是np.absolute
该函数也可以用别名np.abs
来访问。
np.absolute(x)
np.abs(x) # ([2, 1, 0, 1, 2])
3.三角函数
Numpy提供了大量好用的通函函数,其中对于数据科学家最有用的就是三角函数。首先定义一个角度数组:
theta = np.linespace(0, np.pi, 3)
# 创建一个大小为3的角度数组,其值分布在0~pi
现在可以对这些值进行一些三角函数计算:
print("theta = ", theta)
print("sin(theta) = ", np.sin(theta))
print("cos(theta) = ", np.cos(theta))
print("tan(theta) = ", np.tan(theta))
4.指数和对数
Numpy中另一个常用的运算通用函数式指数运算:
x = [1, 2, 3]
print("e ^ x = ", np.exp(x))
print("2 ^ x = ", np.exp2(x))
print("3 ^ x = ", np.power(3, x))
指数运算的逆运算,即对数运算也时刻用的。最基本的np.log
给出的是以自然数为底数的对数。如果你希望计算以2为底数或者以10为底数的对数,可以按照如下示例处理:
x = [1, 2, 4, 10]
print("ln(x) = ", np.log(x))
print("log2(x) = ", np.log2(x))
print("log10(x) = ", np.log10(x))
二、高级通用函数
很多Numpy用户在没有完全了解通用函数的特性时就开始使用它们,这里介绍一些高级通用函数的。
1.指定输出
在进行大量运算时,有时候指定一个用于存放运算结果的数组是非常有用的。不同于创建临时数组,你可以用这个特性将计算结果指定写入到你期望的存储位置。所有的通用函数都可以通过out
参数来指定计算结果的存放位置:
x = np.arange(5) # 0 1 2 3 4
y = np.empty(5)
np.multiply(x, 10, out = y) # 将计算结果保存到y
print(y)
这个特性也可以被用作数组视图,例如可以将计算结果写入指定数组的每隔一个元素的位置:
y = np.zeros(10)
np.power(2, x, out = y[::2])
print(y)
如果这里写的是y[::2]=2 ** x
那么结果将是创建一个临时数组,该数组存放的是2 ** x
的结果,并且接下来会将这些值复制到y数组中。对于上述例子中比较小的运算量来说,这两种方式的差别并不大。但是对于较大的数组,通过慎重使用out参数将能够有效节约内存。
2.聚合
二元通用函数有些非常有趣的聚合功能,这些聚合可以直接在对象上计算。例如,如果我们希望用一个特定的运算reduce一个数组,那么可以用任何通用函数的reduce方法。一个reduce方法会对给定的元素和操作重复执行,直至得到单个的结果。
例如,对add通用函数调用reduce方法会返回数组中所有元素的和:
x = np.arange(1, 6)
np.add.reduce(x)
# 15
同样,对于multiply
通用函数调用reduce方法会返回数组中所有元素的乘积:
np.multiply.reduce(x)
# 120
如果需要存储每次计算的中间结果,可以使用accumulate:
np.add.accumulate(x) # [1, 3, 6, 10, 15]
np.multiply.accumulate(x) # [1, 2, 6, 24, 120]
3.外积
最后,任何通用函数都可以用outer
方法获得两个不同输入数组所有元素对的函数运算结果。这意味着你可以用一行代码实现一个乘法表:
x = np.arange(1, 6)
np.multiply.outer(x, x)
有关通用函数的更多信息(包括通用函数的完整列表)可以在Numpy(http://www.numpy.org)和SciPy(http://www.scipy.org)文档的网站找到。