【Numpy】数组的计算1

Numpy数组的计算:通用函数

Numpy数组的计算有时非常快,有时也非常慢,使Numpy变快的关键是利用向量化的操作,通常在Numpy的通用函数中实现,提高数组元素的重复计算的效率

缓慢的循环

Pythom的默认实现(被称为Cpython)处理某种操作时非常慢,一部分原因是该语言的动态性和解释性-数据类型的灵活特性决定了序列操作不能像C语言和Fortan语言一样被编译成有效的机器码

Python的相对缓慢通常出现在很多小操作需要不断重复的时候,比如对数组的每个元素做循环操作时。

事实上处理的瓶颈并不是运算本身,而是Cpython在每次循环时都必须做数据类型的检查和函数的调度,并没有静态语言运行前编译这样更有效率

通用函数介绍

Numpy为很多类型的操作提供了非常方便的,静态类型的,可编译程序的接口。也被称作向量操作,可以通过简单地对数组进行操作,这样会用于数组的每一个元素

Numpy的向量操作是通过通用函数实现的,通用函数的主要目的是对Numpy数组中的值执行更快的重复操作

1 np.arange(5) / np.arange(1, 6)
2 Out[85]: array([0.        , 0.5       , 0.66666667, 0.75      , 0.8       ])

不仅限于一维数组,可以进行多维数组的计算

1 x = np.arange(9).reshape((3,3))
2 
3 2 ** x
4 Out[87]: 
5 array([[  1,   2,   4],
6        [  8,  16,  32],
7        [ 64, 128, 256]], dtype=int32)

通过通用函数用向量的方式进行计算几乎总比用Python循环实现的计算更有效率,尤其是数组很大时。

Numpy的通用函数

通用函数有两种存在形式:一元通用函数对单个输入操作,二元通用函数对两个输入操作

1.数组的计算

 1 x = np.arange(4)
 2 
 3 print("x  =", x)
 4 x  = [0 1 2 3]
 5 
 6 print("x + 5", x + 5)
 7 x + 5 [5 6 7 8]
 8 
 9 print("x - 5", x - 5)
10 x - 5 [-5 -4 -3 -2]
11 
12 print("x * 2", x * 2)
13 x * 2 [0 2 4 6]
14 
15 print("x / 2", x / 2)
16 x / 2 [0.  0.5 1.  1.5]
17 
18 print("x // 2", x // 2)
19 x // 2 [0 0 1 1]
20 
21 print("-x =", -x)
22 -x = [ 0 -1 -2 -3]
23 
24 print("x **2", x ** 2)
25 x **2 [0 1 4 9]
26 
27 print("x % x", x % 2)
28 x % x [0 1 0 1]

可以任意将这些运算符组合使用,当然需要考虑优先级

1 - (0.5 * x + 1) ** 2
2 Out[98]: array([-1.  , -2.25, -4.  , -6.25])

所有这些算数运算符都是Numpy内置函数的简单封装器,例如+运算符就是add函数的封装器:

1 np.add(x, 2)
2 Out[99]: array([2, 3, 4, 5])

Numpy实现的算术运算符

1 运算符       对应的通用函数  
2 +             np.add
3 -             no.subtract
4 -             np.negative
5 /             np.divide
6 //            np.floor_divide
7 **            np.power
8 %             np.mod

2.绝对值

1 x = np.array([-2, -1, 0, 1, 2])
2 
3 abs(x)
4 Out[101]: array([2, 1, 0, 1, 2])
5 
6 x
7 Out[102]: array([-2, -1,  0,  1,  2])

对应的Numpy通用函数是np.absolute,该函数也可以用别名np.abs来访问:

1 np.absolute(x)
2 Out[103]: array([2, 1, 0, 1, 2])
3 
4 np.abs(x)
5 Out[104]: array([2, 1, 0, 1, 2])

这个通用函数也可以处理复数,当处理复数时,绝对值返回的是该复数的模

1 x = np.array([3 - 4j, 4 - 3j, 2 + 0j, 0 + 1j])
2 
3 np.abs(x)
4 Out[106]: array([5., 5., 2., 1.])

3.三角函数

首先定义一个角度数组:

1 theta = np.linspace(0, np.pi, 3)

对这些值进行三角函数运算:

 1 print("theta  =", theta)
 2 theta  = [0.         1.57079633 3.14159265]
 3 
 4 print("sin(theta) =", np.sin(theta))
 5 sin(theta) = [0.0000000e+00 1.0000000e+00 1.2246468e-16]
 6 
 7 print("cos(theta) =", np.cos(theta))
 8 cos(theta) = [ 1.000000e+00  6.123234e-17 -1.000000e+00]
 9 
10 print("tan(theta) =", np.tan(theta))
11 tan(theta) = [ 0.00000000e+00  1.63312394e+16 -1.22464680e-16]

逆三角函数同样可以使用:

 1 x = [-1, 0, 1]
 2 
 3 print("x  =", x)
 4 x  = [-1, 0, 1]
 5 
 6 print("arcsin(x) =", np.arcsin(x))
 7 arcsin(x) = [-1.57079633  0.          1.57079633]
 8 
 9 print("arccos(x) =", np.arccos(x))
10 arccos(x) = [3.14159265 1.57079633 0.        ]
11 
12 print("arctan(x) =", np.arctan(x))
13 arctan(x) = [-0.78539816  0.          0.78539816]

4.指数和对数

Numpy中另一个常用的运算通用函数是指数运算

 1 x = [1, 2, 3]
 2 
 3 print("x  =", x)
 4 x  = [1, 2, 3]
 5 
 6 print("e^2 =", np.exp(x))
 7 e^2 = [ 2.71828183  7.3890561  20.08553692]
 8 
 9 print("2^x =", np.exp2(x))
10 2^x = [2. 4. 8.]
11 
12 print("3^x =", np.power(3, x))
13 3^x = [ 3  9 27]

指数运算的逆运算,即取对数也是可用的

最基本的np.log给出的是以自然常数(e)为底数的对数

 1 x = [1, 2, 4, 10]
 2 
 3 print("x   =", x)
 4 x   = [1, 2, 4, 10]
 5 
 6 print("ln(x) =", np.log(x))
 7 ln(x) = [0.         0.69314718 1.38629436 2.30258509]
 8 
 9 print("log2(x) =", np.log2(x))
10 log2(x) = [0.         1.         2.         3.32192809]
11 
12 print("log10(x) =", np.log10(x))
13 log10(x) = [0.         0.30103    0.60205999 1.        ]

还有一些特殊版本,对非常小的输入值可以保持较好的精度:

1 x = [0, 0.001, 0.01, 0.1]
2 
3 print("exp(x) - 1 =", np.expm1(x))
4 exp(x) - 1 = [0.         0.0010005  0.01005017 0.10517092]
5 
6 print("log(1 + x) =", np.log1p(x))
7 log(1 + x) = [0.         0.0009995  0.00995033 0.09531018]

当x的值很小时,以上函数给出的值比np.log和np.exp的计算更精确

5.专用的通用函数

介绍一个更加专用,也更加晦涩的通用函数优异来源是子模块scipy.special,scipy.special中包含了很多的计算函数(包含统计学用到的函数)

可以在官网看到,搜索"gamma function python"

高级的通用函数特性

1. 指定输出

在进行大量运算时,有时候需要指定一个用于存放运算结果的数组是有用的,不同于创建临时数组,可以使用这个特性将计算结果直接写入期望的存储位置

所有的通用函数都可以通过out参数来指定计算结果的存放位置

1 x = np.arange(5)
2 
3 y = np.empty(5)
4 
5 np.multiply(x, 10, out=y)
6 Out[138]: array([ 0., 10., 20., 30., 40.])
7 
8 print(y)
9 [ 0. 10. 20. 30. 40.]

这个特性也可以被用作数组视图,例如将计算结果写入指定数组的每隔一个元素位置:

1 y = np.zeros(10)
2 
3 np.power(2, x, out=y[::2])
4 Out[141]: array([ 1.,  2.,  4.,  8., 16.])
5 
6 print(y)
7 [ 1.  0.  2.  0.  4.  0.  8.  0. 16.  0.]

如果这里写的是y[::2] = 2  ** x,那么结果将是创建一个临时数组,该数组存放的是 2 ** x的结果,并且接下来会将这些值复制到y数组中,对于比较小的计算量来说,两种方式差别不大,对于较大数组,通过慎重使用out参数将能够有效节约内存

2.聚合

二元通用函数存在聚合功能,这些聚合可以直接在对象上计算。

例如,使用reduce方法作用一个数组,一个reduce方法会对给定的元素和操作重复执行,直到得到单个结果

举例:

对add通用函数调用reduce方法会返回数组中所有元素的和

1 x = np.arange(1, 6)
2 
3 np.add.reduce(x)
4 Out[145]: 15

对multiply通用函数调用reduce方法会返回数组中所有元素的乘积

1 np.multiply.reduce(x)
2 Out[146]: 120

需要存储每次计算的中间结果,可以使用accumulate

1 np.add.accumulate(x)
2 Out[147]: array([ 1,  3,  6, 10, 15], dtype=int32)
3 
4 np.multiply.accumulate(x)
5 Out[148]: array([  1,   2,   6,  24, 120], dtype=int32)

还有其他专用函数(np.sum,np.prod,np.cumsum....),也可以实现以上的reduce功能

3.外积

任何通用函数都可以使用outer方法获得两个不同输入数组所有元素对的函数计算结果

意味着可以使用一行代码实现乘法表:

1 x = np.arange(1, 6)
2 
3 np.multiply.outer(x, x)
4 Out[150]: 
5 array([[ 1,  2,  3,  4,  5],
6        [ 2,  4,  6,  8, 10],
7        [ 3,  6,  9, 12, 15],
8        [ 4,  8, 12, 16, 20],
9        [ 5, 10, 15, 20, 25]])

通用函数另一个非常有用的特性是它能操作不同大小和形状的数组,一组这样的操作被称为广播 

posted @ 2019-08-24 21:18  木屐呀  阅读(278)  评论(0编辑  收藏  举报
//增加一段JS脚本,为目录生成使用