NumPy入门基础语法学习5

      NumPy 数组的计算:通用函数
到目前为止,我们讨论了 NumPy 的一些基础知识。在接下来的几小节
中,我们将深入了解 NumPy Python 数据科学世界中如此重要的原
因。明确点说, NumPy 提供了一个简单灵活的接口来优化数据数组的
计算。
NumPy 数组的计算有时非常快,有时也非常慢。使 NumPy 变快的关键
是利用向量化操作,通常在 NumPy 的通用函数( ufunc )中实现。本节
将介绍 NumPy 通用函数的重要性 —— 它可以提高数组元素的重复计算
的效率;然后,将会介绍很多 NumPy 包中常用且有用的数学通用函
数。
 
    缓慢的循环
Python 的默认实现(被称作 CPython )处理起某些操作时非常慢,一部
分原因是该语言的动态性和解释性 —— 数据类型灵活的特性决定了序列
操作不能像 C 语言和 Fortran 语言一样被编译成有效的机器码。
          Python 的相对缓慢通常出现在很多小操作需要不断重复的时候,比如对
数组的每个元素做循环操作时。假设有一个数组,我们想计算每个元素
的倒数,一种直接的解决方法是:
 
import numpy as np 
np.random.seed(0)
def compute_reciprocals(values): 
    output = np.empty(len(values)) 
    for i in range(len(values)):
        output[i] = 1.0 / values[i] 
        return output

values = np.random.randint(1, 10, size=5) 
compute_reciprocals(values)

array([1.66666667e-001, 7.12919228e-225, 1.25522403e-311, 1.25522403e-311,
       6.50368792e-172])
这种实现方式可能对于有 C 语言或 Java 背景的人来说非常自然,但是
如果测试一个很大量的输入数据运行上述代码的时间,这一操作将非常
耗时,并且是超出意料的慢!我们将用 IPython %timeit 魔法函数
 
 big_array = np.random.randint(1, 100, size=1000000)
 %timeit compute_reciprocals(big_array) 

 180 µs ± 12.5 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
完成百万次上述操作并存储结果花了几秒钟的时间.
 
通用函数介绍
NumPy 为很多类型的操作提供了非常方便的、静态类型的、可编译程
序的接口,也被称作向量操作。你可以通过简单地对数组执行操作来实
现,这里对数组的操作将会被用于数组中的每一个元素。这种向量方法
被用于将循环推送至 NumPy 之下的编译层,这样会取得更快的执行效
率。比较以下两个结果:
print(compute_reciprocals(values))
print(1.0 / values)

[1.66666667e-001 7.12919228e-225 1.25522403e-311 1.25522403e-311
 6.50368792e-172]
[0.16666667 1.         0.25       0.25       0.125     ]
如果计算一个较大数组的运行时间,可以看到它的完成时间比 Python
循环花费的时间更短:
 %timeit (1.0 / big_array)
6.1 ms ± 448 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

NumPy 中的向量操作是通过通用函数实现的。通用函数的主要目的是
NumPy 数组中的值执行更快的重复操作。它非常灵活,前面我们看
过了标量和数组的运算,但是也可以对两个数组进行运算:
np.arange(5) / np.arange(1, 6)
array([0.        , 0.5       , 0.66666667, 0.75      , 0.8       ])
通用函数并不仅限于一维数组的运算,它们也可以进行多维数组的运
算:
x = np.arange(9).reshape((3, 3))
2 ** x

array([[  1,   2,   4],
       [  8,  16,  32],
       [ 64, 128, 256]], dtype=int32)
     通过通用函数用向量的方式进行计算几乎总比用 Python 循环实现的计
算更加有效,尤其是当数组很大时。只要你看到 Python 脚本中有这样
的循环,就应该考虑能否用向量方式替换这个循环。
 
探索 NumPy 的通用函数
通用函数有两种存在形式:一元通用函数( unary ufunc )对单个输入操
作,二元通用函数( binary ufunc )对两个输入操作。我们将在以下的介
绍中看到这两种类型的例子。
 
数组的运算
NumPy 通用函数的使用方式非常自然,因为它用到了 Python 原生
的算术运算符,标准的加、减、乘、除都可以使用:
x = np.arange(4) 
print("x =", x)  
print("x - 5 =", x - 5) 
print("x * 2 =", x * 2) 
print("x / 2 =", x / 2)
print("x // 2 =", x // 2) #地板除法运算

x = [0 1 2 3]
x - 5 = [-5 -4 -3 -2]
x * 2 = [0 2 4 6]
x / 2 = [0.  0.5 1.  1.5]
x // 2 = [0 0 1 1]
还有逻辑非、 ** 表示的指数运算符和 % 表示的模运算符的一元通
用函数:
print("-x = ", -x) 
print("x ** 2 = ", x ** 2) 
print("x % 2 = ", x % 2)

-x =  [ 0 -1 -2 -3]
x ** 2 =  [0 1 4 9]
x % 2 =  [0 1 0 1]
你可以任意将这些算术运算符组合使用。当然,你得考虑这些运算
符的优先级:
 
 
-(0.5*x + 1) ** 2

array([-1.  , -2.25, -4.  , -6.25])

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

np.add(x, 2)

array([2, 3, 4, 5])
2-2 列出了所有 NumPy 实现的算术运算符。
2-2 NumPy 实现的算术运算符
 
另外, NumPy 中还有布尔 / 位运算符,这些运算符将在 2.6 节中进
一步介绍。
绝对值
正如 NumPy 能理解 Python 内置的运算操作, NumPy 也可以理解
Python 内置的绝对值函数:
x = np.array([-2, -1, 0, 1, 2]) 
abs(x)

array([2, 1, 0, 1, 2])
对应的 NumPy 通用函数是 np.absolute ,该函数也可以用别名
np.abs 来访问:
np.absolute(x)

array([2, 1, 0, 1, 2])
np.abs(x)

array([2, 1, 0, 1, 2])
这个通用函数也可以处理复数。当处理复数时,绝对值返回的是该
复数的幅度:
x = np.array([3 - 4j, 4 - 3j, 2 + 0j, 0 + 1j]) 
np.abs(x)

array([5., 5., 2., 1.])
三角函数
NumPy 提供了大量好用的通用函数,其中对于数据科学家最有用
的就是三角函数。首先定义一个角度数组:
theta = np.linspace(0, np.pi, 3)
#现在可以对这些值进行一些三角函数计算:
print("theta = ", theta) 
print("sin(theta) = ", np.sin(theta)) 
print("cos(theta) = ", np.cos(theta)) 
print("tan(theta) = ", np.tan(theta))


theta =  [0.         1.57079633 3.14159265]
sin(theta) =  [0.0000000e+00 1.0000000e+00 1.2246468e-16]
cos(theta) =  [ 1.000000e+00  6.123234e-17 -1.000000e+00]
tan(theta) =  [ 0.00000000e+00  1.63312394e+16 -1.22464680e-16]
这些值是在机器精度内计算的,所以有些应该是 0 的值并没有精确 0 。逆三角函数同样可以使用:
 x = [-1, 0, 1] 
 print("x = ", x)
 print("arcsin(x) = ", np.arcsin(x))
 print("arccos(x) = ", np.arccos(x))
 print("arctan(x) = ", np.arctan(x))


x =  [-1, 0, 1]
arcsin(x) =  [-1.57079633  0.          1.57079633]
arccos(x) =  [3.14159265 1.57079633 0.        ]
arctan(x) =  [-0.78539816  0.          0.78539816]
指数和对数
NumPy 中另一个常用的运算通用函数是指数运算:
 x = [1, 2, 3]
 print("x =", x) 
 print("e^x =", np.exp(x))
 print("2^x =", np.exp2(x))
 print("3^x =", np.power(3, x))


x = [1, 2, 3]
e^x = [ 2.71828183  7.3890561  20.08553692]
2^x = [2. 4. 8.]
3^x = [ 3  9 27]
指数运算的逆运算,即对数运算也是可用的。最基本的 np.log
出的是以自然数为底数的对数。如果你希望计算以 2 为底数或者以
10 为底数的对数,可以按照如下示例处理:
 
x = [1, 2, 4, 10] 
print("x =", x) 
print("ln(x) =", np.log(x)) 
print("log2(x) =", np.log2(x)) 
print("log10(x) =", np.log10(x))

x = [1, 2, 4, 10]
ln(x) = [0.         0.69314718 1.38629436 2.30258509]
log2(x) = [0.         1.         2.         3.32192809]
log10(x) = [0.         0.30103    0.60205999 1.        ]
还有一些特殊的版本,对于非常小的输入值可以保持较好的精度:
x = [0, 0.001, 0.01, 0.1] 
print("exp(x) - 1 =", np.expm1(x)) 
print("log(1 + x) =", np.log1p(x))

exp(x) - 1 = [0.         0.0010005  0.01005017 0.10517092]
log(1 + x) = [0.         0.0009995  0.00995033 0.09531018]
x 的值很小时,以上函数给出的值比 np.log np.exp 的计算
更精确。
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值