注:本文是我在阅读 An introduction to Numpy and Scipy 时,一边实践一边记下的笔记。个人觉得这篇介绍 NumPy 的英文文档写的很好,因此如果可以,请停止阅读本文,转去参考此英文文档。
目录
Numpy 是在 Python 中进行科学计算所依赖的核心库,它提供高性能的多维数组对象,已经大量便于计算的方法。
可以在 Installing packages 找到安装方法,而后在 Python 中采用如下方式引入它:
import numpy as np
Arrays
NumPy 中的核心对象是多维数组 np.ndarray
,它有一个别名 np.array
,这个数组和 Python 中的 array.array
不同,Python 中的 array
只支持一维,而 np.array
支持多维,且提供了更多的方法。
np.array
中只能存放同种类型的数据,如下,使用 np.array
创建数组,第二个参数需指明数组中元素的类型,否则 np.array
会自动推测数据类型:
>>> a = np.array([1, 4, 5, 8], float) >>> a array([ 1., 4., 5., 8.]) >>> type(a) <type 'numpy.ndarray'>
np.ndarray
含下面几个常用的属性:
ndarray.ndim
:数组的维度ndarray.shape
:数组的形状ndarray.size
:数组中所有元素的数量ndarray.dtype
:数组中元素的类型ndarray.itemsize
:每个元素的大小ndarray.data
:元素数据 buffer
创建多维数组:
>>> a = np.array([[1, 2, 3], [4, 5, 6]], float) >>> a[0, 0] 1
数组创建后可以使用 reshape
来调整维度,可以使用 shape
来得到数组的维度:
>>> a = np.array(range(10), float) >>> a array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]) >>> a = a.reshape((5, 2)) >>> a array([[ 0., 1.], [ 2., 3.], [ 4., 5.], [ 6., 7.], [ 8., 9.]]) >>> a.shape (5, 2)
Python中 list
的切片操作,同样适用,对个维度需要使用 ,
隔开:
>>> a = np.array([[1, 2, 3], [4, 5, 6]], float) >>> a[1,:] # 第二行的所有列 array([ 4., 5., 6.]) >>> a[:,2] array([ 3., 6.]) >>> a[-1:,-2:] # 最后一行的后两列 array([[ 5., 6.]])
copy
能够生成数组的一份拷贝:
>>> a = np.array([1, 2, 3], float) >>> b = a >>> c = a.copy() >>> a[0] = 0 >>> a array([0., 2., 3.]) >>> b array([0., 2., 3.]) >>> c array([1., 2., 3.])
fill
方法给数组统一填充某个值:
>>> a = array([1, 2, 3], float) >>> a array([ 1., 2., 3.]) >>> a.fill(0) >>> a array([ 0., 0., 0.])
transpose
方法用来得到二维数组的转置:
>>> a = np.array(range(6), float).reshape((2, 3)) >>> a array([[ 0., 1., 2.], [ 3., 4., 5.]]) >>> a.transpose() array([[ 0., 3.], [ 1., 4.], [ 2., 5.]])
多维数组能够被展平:
>>> a = np.array([[1, 2, 3], [4, 5, 6]], float) >>> a array([[ 1., 2., 3.], [ 4., 5., 6.]]) >>> a.flatten() array([ 1., 2., 3., 4., 5., 6.])
多个数组可以使用 concatenate
拼接起来:
>>> a = np.array([1,2], float) >>> b = np.array([3,4,5,6], float) >>> c = np.array([7,8,9], float) >>> np.concatenate((a, b, c)) array([1., 2., 3., 4., 5., 6., 7., 8., 9.])
如果有多个维度,默认(不指定 axis 时)是按第一个维度拼接的
>>> a = np.array([[1, 2], [3, 4]], float) >>> b = np.array([[5, 6], [7,8]], float) >>> np.concatenate((a,b)) array([[ 1., 2.], [ 3., 4.], [ 5., 6.], [ 7., 8.]]) >>> np.concatenate((a,b), axis=0) array([[ 1., 2.], [ 3., 4.], [ 5., 6.], [ 7., 8.]]) >>> np.concatenate((a,b), axis=1) array([[ 1., 2., 5., 6.], [ 3., 4., 7., 8.]])
一个数组的维度,可以借助 newaxis
来增加:
>>> a = np.array([1, 2, 3], float) >>> a array([1., 2., 3.]) >>> a[:,np.newaxis] array([[ 1.], [ 2.], [ 3.]]) >>> a[:,np.newaxis].shape (3,1) >>> a[np.newaxis,:] array([[ 1., 2., 3.]]) >>> a[np.newaxis,:].shape (1,3)
其他创建数组的方法
np.arange
和 range
类似,只是前者返回一个数组:
>>> np.arange(5, dtype=float) array([ 0., 1., 2., 3., 4.]) >>> np.arange(1, 6, 2, dtype=int) array([1, 3, 5])
zeros
和 ones
用来创建指定维度的数组,并填充 0 和 1:
>>> np.ones((2,3), dtype=float) array([[ 1., 1., 1.], [ 1., 1., 1.]]) >>> np.zeros(7, dtype=int) array([0, 0, 0, 0, 0, 0, 0])
zeros_like
和 ones_like
创建和给定数组维度相同的新数组,并填充 0 和 1:
>>> a = np.array([[1, 2, 3], [4, 5, 6]], float) >>> np.zeros_like(a) array([[ 0., 0., 0.], [ 0., 0., 0.]]) >>> np.ones_like(a) array([[ 1., 1., 1.], [ 1., 1., 1.]])
identity
方法用来一个指定阶数的单位矩阵:
>>> np.identity(4, dtype=float) array([[ 1., 0., 0., 0.], [ 0., 1., 0., 0.], [ 0., 0., 1., 0.], [ 0., 0., 0., 1.]])
eye
方法用来创建一个指定阶数的矩阵,其指定(k)对角线上值为 1:
>>> np.eye(4, k=1, dtype=float) array([[ 0., 1., 0., 0.], [ 0., 0., 1., 0.], [ 0., 0., 0., 1.], [ 0., 0., 0., 0.]])
数组的数学运算
当将标准数学运算作用于数组上时,这样运算会分别在数组的各个元素上进行,这意味着进行运算的两个数组的大小需要一致:
>>> a = np.array([1,2,3], float) >>> b = np.array([5,2,6], float) >>> a + b array([6., 4., 9.]) >>> a – b array([-4., 0., -3.]) >>> a * b array([5., 4., 18.]) >>> b / a array([5., 1., 2.]) >>> a % b array([1., 0., 3.]) >>> b ** a array([5., 4., 216.])
对于二维数组间的乘法,依然是元素与元素相乘,而非矩阵乘法:
>>> a = np.array([[1,2], [3,4]], float) >>> b = np.array([[2,0], [1,3]], float) >>> a * b array([[2., 0.], [3., 12.]])
当数组长度不匹配的时候就会出错:
>>> a = np.array([1,2,3], float) >>> b = np.array([4,5], float) >>> a + b Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: shape mismatch: objects cannot be broadcast to a single shape
但是,数组的维度不匹配时,NumPy 有一种广播机制,能够让运行进行下去,通常是将现有的数组进行重复,以完成运算:
>>> a = np.array([[1, 2], [3, 4], [5, 6]], float) >>> b = np.array([-1, 3], float) >>> a array([[ 1., 2.], [ 3., 4.], [ 5., 6.]]) >>> b array([-1., 3.]) >>> a + b array([[ 0., 5.], [ 2., 7.], [ 4., 9.]])
这里一维数组 b 被扩展为二维,扩展后与数组 a 有相同的 shape,如此以来就可以进行运算。
在基本数学运算符的基础上,NumPy 增加了一些常见的属性数学运算函数:abs
, sign
, sqrt
, log
, log10
, exp
, sin
, cos
, tan
, arcsin
, arccos
, arctan
, sinh
, cosh
, tanh
, arcsinh
, arccosh
, arctanh
。
>>> np.sqrt(a) array([ 1., 2., 3.])
floor
, ceil
, rint
分别对浮点数向下、向上、四舍五入取整。
>>> a = np.array([1.1, 1.5, 1.9], float) >>> np.floor(a) array([ 1., 1., 1.]) >>> np.ceil(a) array([ 2., 2., 2.]) >>> np.rint(a) array([ 1., 2., 2.])
np.pi
为圆周率,np.e
为自然常数:
>>> np.pi 3.1415926535897931 >>> np.e 2.7182818284590451
数组的迭代
可以像迭代 list
一样迭代 np.array
:
>>> a = np.array([1, 4, 5], int) >>> for x in a: ... print x ... <hit return> 1 4 5
对于多维数组,迭代会在第一维上进行:
>>> a = np.array([[1, 2], [3, 4], [5, 6]], float) >>> for x in a: ... print x ... <hit return> [ 1. 2.] [ 3. 4.] [ 5. 6.]
对于多维数组迭代,可以使用解构:
>>> a = np.array([[1, 2], [3, 4], [5, 6]], float) >>> for (x, y) in a: ... print x * y ... <hit return> 2.0 12.0 30.0
基本的数组操作
有些运算需要作用于整个数组上,比如求和、求均值等。
>>> a = np.array([2, 4, 3], float) >>> a.sum() # 求和 9.0 >>> a.prod() # 所有元素连乘 24.0
可以在 array 元素上调用方法,也可以使用在 np 上的函数:
>>> np.sum(a) 9.0 >>> np.prod(a) 24.0
在涉及统计的时候,常常会用到下列函数:
>>> a = np.array([2, 1, 9], float) >>> a.mean() # 求均值 4.0 >>> a.var() # 方差(variance) 12.666666666666666 >>> a.std() # 标准差 3.5590260840104371
可以使用 max
和 min
求最大、最小值:
>>> a = np.array([2, 1, 9], float) >>> a.min() 1.0 >>> a.max() 9.0
argmax
和 argmin
返回数组中,最大和最小元素的下标:
>>> a = np.array([2, 1, 9], float) >>> a.argmin() 1 >>> a.argmax() 2
对于多维数组,上面提到的针对数组的方法,可以接受一个参数 axis
,用来指明这些方法作用的轴。即,对于二维数组而言,是针对行,还是针对列。
>>> a = np.array([[0, 2], [3, -1], [3, 5]], float) >>> a.mean(axis=0) array([ 2., 2.]) >>> a.mean(axis=1) array([ 1., 1., 4.]) >>> a.min(axis=1) array([ 0., -1., 3.]) >>> a.max(axis=0) array([ 3., 5.])
对于多维数组,如果不指定 axis
,那么结果相当于将数组会被展平为一维数组,然后执行该方法。比如:
>>> a = np.array([[0, 2], [3, -1], [3, 5]], float) >>> a.sum() # 对所有元素求和 12.0
像 list
一样,np.array
也可以进行排序:
>>> a = np.array([6, 2, 5, -1, 0], float) >>> sorted(a) [-1.0, 0.0, 2.0, 5.0, 6.0] >>> a.sort() >>> a array([-1., 0., 2., 5., 6.])
使用 clip
将数组中的值,压缩到一个指定范围。
>>> a = np.array([6, 2, 5, -1, 0], float) >>> a.clip(0, 5) # 小于 0 的数被置为 0,大于 5 的被置为 5 array([ 5., 2., 5., 0., 0.])
使用 unique
对数组去重:
>>> a = np.array([1, 1, 4, 5, 5, 5, 7], float) >>> np.unique(a) array([ 1., 4., 5., 7.])
对于二维数组,diagonal
方法能够取得对角线上的元素:
>>> a = np.array([[1, 2], [3, 4]], float) >>> a.diagonal() # 并不要求二维数组为方阵 array([ 1., 4.])
比较操作
比较运算能够作用于数组的各个元素上,得到的结果是由布尔值构成的数组:
>>> a = np.array([1, 3, 0], float) >>> b = np.array([0, 3, 2], float) >>> a > b array([ True, False, False], dtype=bool) >>> a == b array([False, True, False], dtype=bool) >>> a <= b array([False, True, True], dtype=bool) >>> a = np.array([1, 3, 0], float) >>> a > 2 # 可以和一个常数进行比较 array([False, True, False], dtype=bool)
any
和 all
方法能够作用于数组上:
>>> c = np.array([ True, False, False], bool) >>> any(c) # 数组中是否至少有一个 True True >>> all(c) # 数组中是否全为 True False
对于布尔数组,可以利用 logical_and
, logical_or
, logical_not
,在上面进行与或非
等布尔运算:
>>> a = np.array([1, 3, 0], float) >>> np.logical_and(a > 0, a < 3) array([ True, False, False], dtype=bool) >>> b = np.array([True, False, True], bool) >>> np.logical_not(b) array([False, True, False], dtype=bool) >>> c = np.array([False, True, False], bool) >>> np.logical_or(b, c) array([ True, True, False], dtype=bool)
where
可以实现在两个数组中选择元素来构造新数组:
>>> a = np.array([1, 3, 0], float) >>> np.where(a != 0, 1 / a, a) array([ 1. , 0.33333333, 0. ])
这里 a != 0
会得到一个含布尔值的数组 [False, True, False]
, where
根据这个数组中的值,如果为 False
就选第三个数组中对应的值,否则选择第二个数组中对应的值。
当然,也可以用于常数:
>>> np.where(a > 0, 3, 2) array([3, 3, 2])
有时候需要得出数组中符合某种条件的元素的下标,此时可以使用 nonzero
方法:
>>> a = np.array([[1, 0], [0, 3]], float) >>> a.nonzero() (array([0, 1]), array([0, 1]))
nonzero
返回非 0 元素的下标,其结果是一个元组,元组的长度和数组 a
的维度相当,元组中每个元素又是一个数组,其中第一个数组中的值为第一个维度的下标,第二个数组为第二维度,以此类推。上例中结果说明 a[0, 0]
和 a[1, 1]
为非零元素。
对于布尔值构成的数组,nonzero
返回值为 True
的元素的下标,因此可以用下面的方法,找出值大于 2 的元素的下标:
>>> a = np.array([[1, 0], [0, 3]], float) >>> np.nonzero(a > 2) (array([1]), array([1]))
要想找出符合条件的值,而非下标,可以将 nonzero
的结果作为下标来取值:
>>> a = np.array([[1, 0], [0, 3]], float) >>> a[np.nonzero(a > 2)] array([3.])
利用 np.isnan
和 np.isfinite
可以判断元素值是否为 NaN
或 无穷:
>>> a = np.array([1, np.NaN, np.Inf], float) >>> a array([ 1., NaN, Inf]) >>> np.isnan(a) array([False, True, False], dtype=bool) >>> np.isfinite(a) array([ True, False, False], dtype=bool)
数组元素选择和操作
要取得 np.array
中的值,可以在 []
中放入适当的下标:
>>> a = np.array([[1, 0], [0, 3]], float) >>> a[0, 0] # 使用两个维度上的下标来索引 1.0 >>> a[(0, 0)] # 使用元组 1.0 # 两个数组,分别指定两个维度的下标,这样可以一次取出多个值 >>> a[([0, 1], [0, 1])] array([1., 3.]) # 使用数组也能达到同样效果 >>> a[[0, 1], [0, 1]] array([1., 3.])
另外 np.array
还支持使用 np.array
来索引,如使用布尔数组来索引:
>>> a = np.array([[6, 4], [5, 9]], float) >>> a >= 6 array([[True, False], [False, True]], dtype=bool) >>> a[a >= 6] array([ 6., 9.])
这里 a >= 6
和 a
有相同的 shape
,a[a >= 6]
则返回 a >=6
中值为 True
的位置在 a
中所对应的元素。
还可以使用更加复杂的表达式:
>>> a[np.logical_and(a > 5, a < 9)] >>> array([ 6.])
但本质就是通过一个含布尔值的 np.array
来进行索引。
一个 np.array
作为另一个的下标:
>>> a = np.array([2, 4, 6, 8], float) >>> b = np.array([0, 0, 1, 3, 2, 1], int) >>> a[b] array([ 2., 2., 4., 8., 6., 4.])
take
方法,可以帮助取值:
>>> a = np.array([[1, 2], [3, 4]], float) >>> a array([[1., 2.], [3., 4.]]) >>> a.take(3) # 相当于 a[1][1] 4.0 >>> a.take([0, 1]) array([1., 2.]) >>> a.take(0, axis=0) # 相当于 a[0, :] array([1., 2.]) >>> a.take(0, axis=1) # 相当于 a[:, 0] array([1., 3.])
对于多维数组,take
如果不传入 axis
参数,就相当于将多维数组展平为一维数组后,再索引一样。
如果想要给指定下标的位置赋值,可以用到 put
方法:
>>> a = np.array([0, 1, 2, 3, 4, 5], float) >>> b = np.array([9, 8, 7], float) >>> a.put([0, 3], b) >>> a array([ 9., 1., 2., 8., 4., 5.])
put
的第一个参数为索引,第二个参数为要赋的值。这里的下标是数组展平后的索引。注意到上例中中,7
并没有被赋入 a,这是因为索引只有两个。
当索引够长,而值不够是,值能够进行扩展。
>>> a = np.array([[1, 2], [3, 4]], float) >>> a.put([0, 1, 2, 3], [1,2]) >>> a array([[1., 2.], [1., 2.]]) >>> a.put([0, 1, 2, 3], 5) >>> a array([[5., 5.], [5., 5.]])
向量和矩阵的数学运算
完成向量的点乘和矩阵的乘法,需要用到 dot
方法:
>>> a = np.array([1, 2, 3], float) >>> b = np.array([0, 1, 1], float) >>> np.dot(a, b) 5.0
对于向量,inner
, outer
, cross
可用于计算內积、外积、和叉乘:
>>> a = np.array([1, 4, 0], float) >>> b = np.array([2, 2, 1], float) >>> np.outer(a, b) array([[ 2., 2., 1.], [ 8., 8., 4.], [ 0., 0., 0.]]) >>> np.inner(a, b) 10.0 >>> np.cross(a, b) array([ 4., -1., -6.])
在 np.linalg
中有大量涉及线性代数的计算函数,如:
>>> a = np.array([[4, 2, 0], [9, 3, 7], [1, 2, 1]], float) >>> a array([[ 4., 2., 0.], [ 9., 3., 7.], [ 1., 2., 1.]]) >>> np.linalg.det(a) # 得出行列式的值 -53.999999999999993 >>> vals, vecs = np.linalg.eig(a) # 得出特征值和特征向量
随机数
在子模块 np.random
中有若干函数来支持随机数生成。其中用到伪随机数生成算法,需要设置种子:
>>> np.random.seed(293423)
生成一组介于 [0, 1)
的随机数:
>>> np.random.rand(5) array([ 0.40783762, 0.7550402 , 0.00919317, 0.01713451, 0.95299583])
也可以是多维的:
>>> np.random.rand(2,3) array([[0.02258773, 0.45209532, 0.91634883], [0.45311731, 0.23780582, 0.03024893]])
生成单个随机数,介于[0, 1)
:
>>> np.random.random() 0.8573439034930186 >>> np.random.rand() 0.6180841214951669
生成 [min, max)
间的整数:
>>> np.random.randint(5, 10) 8 >>> np.random.randint(5, 10, size=3) array([9, 5, 6])
生成具有特定分布类型的随机数,比如生成具有正态分布的随机数:
>>> np.random.normal(size=5) array([-1.67215088, 0.65813053, -0.70150614, 0.91452499, 0.71440557]) # 可以调整方差和期望, μ = 1.5, δ^2 = 16.0 >>> np.random.normal(1.5, 4.0) 0.83636555041094318
打乱数组中的值:
>>> a = np.arange(10) >>> a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> np.random.shuffle(a) >>> a array([7, 6, 9, 3, 2, 4, 8, 0, 1, 5])
来源:https://www.cnblogs.com/wy-ei/p/numpy.html