参考: https://gitbook.cn/gitchat/column/undefined/topic/5e3bceadec8d9033cf924665
打开 IPython
,创建 Python
的列表 a 对象。然后,使用列表生成式,创建一个元素都为原来两倍的新列表 a2,并统计这一行的用时为 921 ms。
In [95]: a =list(range(10000000))
In [96]: %time b = [i*2 for i in a]
Wall time: 921 ms
使用 NumPy
,创建同样大小和取值的数组 na。然后,对每个元素乘以 2,返回一个新数组 na2,用时为 31 ms。
In [90]: import numpy as np
In [93]: na = np.array(range(10000000))
In [94]: %time na = na*2
Wall time: 31.3 ms
可以看到,完成同样的都对元素乘以 2 的操作, NumPy
比 Python
快了 30 倍之多。
NumPy
计算为什么这么快呢?
Python
的list
是一个通用结构。它能包括任意类型的对象,并且是动态类型。NumPy
的ndarray
是静态、同质的类型,当ndarray
对象被创建时,元素的类型就确定。
由于是静态类型,所以 ndarray
间的加、减、乘、除用 C
和 Fortran
实现才成为可能,所以运行起来就会更快。根据官网介绍,底层代码用 C
语言和 Fortran
语言实现,实现性能无限接近 C
的处理效率。
1. 创建 Numpy 数组
1.1 一维数组 array
In [99]: import numpy as np
In [101]: np.array([1,2,3,4])
Out[101]: array([1, 2, 3, 4])
1.2 二维数组 array
In [102]: np.array([[1,2], [3,4]])
Out[102]:
array([[1, 2],
[3, 4]])
一维数组和二维数组的类型都为 numpy.ndarray
In [103]: a = np.array([1,2,3,4])
In [104]: b = np.array([[1,2], [3,4]])
In [105]: type(a)
Out[105]: numpy.ndarray
In [106]: type(b)
Out[106]: numpy.ndarray
1.3 arange 数组
In [22]: r = np.arange(1, 10, 1)
In [23]: r
Out[23]: array([1, 2, 3, 4, 5, 6, 7, 8, 9])
arange()
的第一个值代表开始值,第二个值代表终值(不包括这个值),最后一个值代表步长(间隔),如 arange(1,10,1)
代表一个从 0-9,步长为 1 的数组。
1.4 linspace 数组
返回 1 和 10 之间的 8 个元素。
In [110]: np.linspace(1, 10, 8)
Out[110]:
array([ 1. , 2.28571429, 3.57142857, 4.85714286, 6.14285714,
7.42857143, 8.71428571, 10. ])
In [111]: np.linspace(1, 10, 8)
Out[111]:
array([ 1. , 2.28571429, 3.57142857, 4.85714286, 6.14285714,
7.42857143, 8.71428571, 10. ])
In [112]:
对于 linspace()
,它的前两个值和 arange()
一样,代表开始值和终值,但有个区别是 linspace()
默认包括终值,如果你不想包括终值,加上 endpoint = False
即可,对于第三个值它是指元素的个数,这个和 arange
不一样,一定不要混淆。
1.5 组合 ndarray 对象
如下创建一个 ndarray
对象 a
:
In [112]: a = np.arange(10).reshape(2, -1)
In [113]: a
Out[113]:
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
找出 a 中大于 4 的元素索引,使用 where
方法,返回一个元组,带有 2 个 ndarray
对象,分别表示大于 4 的元素第一维、第二维度中的位置:
In [114]: np.where(a>4)
Out[114]: (array([1, 1, 1, 1, 1], dtype=int64), array([0, 1, 2, 3, 4], dtype=int64))
我们把它拼接为一个 ndarray
对象:
In [115]: np.array(np.where(a>4))
Out[115]:
array([[1, 1, 1, 1, 1],
[0, 1, 2, 3, 4]], dtype=int64)
然后,再转置,使用 np.transpose
方法:
In [117]: np.transpose(x)
Out[117]:
array([[1, 0],
[1, 1],
[1, 2],
[1, 3],
[1, 4]], dtype=int64)
In [118]:
可以很明显的看出 [1, 0] 表示大于 4 的元素在原 ndarray 对象的索引。
2. Numpy 数组属性
2.1 shape 属性
shape
属性返回数组的形状信息,是一个元组对象。
In [118]: a = np.zeros(5)
In [120]: b = np.ones((2, 3))
In [121]: a
Out[121]: array([0., 0., 0., 0., 0.])
In [122]: b
Out[122]:
array([[1., 1., 1.],
[1., 1., 1.]])
可以看到 a 是一维的,而 b 是一个 2*3 的数组,打印它们的 shape 信息,可以看到:
In [124]: a.shape
Out[124]: (5,)
In [125]: b.shape
Out[125]: (2, 3)
In [126]:
2.2 size 属性
size
属性获取数组内元素个数:
In [126]: a.size
Out[126]: 5
In [127]: b.size
Out[127]: 6
In [128]:
2.3 dtype 属性
dtype
属性获取数组内元素的类型:
In [128]: a.dtype
Out[128]: dtype('float64')
In [129]: b.dtype
Out[129]: dtype('float64')
创建数组时,还可以通过为 dtype
赋值,指定元素类型:
In [134]: m = np.array([1,2,3])
In [135]: m.dtype
Out[135]: dtype('int32')
In [136]: m = np.array([1,2,3], dtype='float')
In [137]: m.dtype
Out[137]: dtype('float64')
dtype
更多取值: int
、 complex
、 bool
、 object
,还可以显示的定义数据位数的类型,如: int64
、 int16
、 float128
、 complex128
。
3. 数组函数
3.1 arange 函数
起始点,终点,步长;不包括终点。
In [138]: np.arange(1, 10, 2)
Out[138]: array([1, 3, 5, 7, 9])
In [139]:
3.2 linspace 函数
起始点,终点,分割份数;包括终点。
In [139]: np.linspace(1, 10, 7)
Out[139]: array([ 1. , 2.5, 4. , 5.5, 7. , 8.5, 10. ])
In [140]:
3.3 logspace 函数
创建以 e 为底,指数为 1,2,…,10 的数组:
In [140]: np.logspace(1, 10, 3)
Out[140]: array([1.00000000e+01, 3.16227766e+05, 1.00000000e+10])
In [141]:
3.4 diag 对角函数
创建对角数组:
In [141]: np.diag([1,2,3,4])
Out[141]:
array([[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]])
主对角线偏移 1 的数组:
In [142]: np.diag([1,2,3,4],k=1)
Out[142]:
array([[0, 1, 0, 0, 0],
[0, 0, 2, 0, 0],
[0, 0, 0, 3, 0],
[0, 0, 0, 0, 4],
[0, 0, 0, 0, 0]])
In [143]:
3.5 zeros 函数
创建一个全零的数组,接受参数为数组的维度
In [143]: np.zeros(3)
Out[143]: array([0., 0., 0.])
In [145]: np.zeros((3,4))
Out[145]:
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
In [146]: np.zeros((2,3,4))
Out[146]:
array([[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]])
In [147]:
3.6 ones 函数
创建一个全 1 的数组
In [147]: np.ones(3)
Out[147]: array([1., 1., 1.])
In [148]: np.ones((2,3))
Out[148]:
array([[1., 1., 1.],
[1., 1., 1.]])
In [149]: np.ones((2,3,1))
Out[149]:
array([[[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.]]])
In [150]:
3.7 random 随机数组
生成 0~1、shape 为 (2,3) 的随机数数组:
In [151]: np.random.rand(2,3)
Out[151]:
array([[0.50761977, 0.73557945, 0.84018083],
[0.1117079 , 0.02225728, 0.51466307]])
In [152]:
4. 多维索引和筛选
4.1 二维数组
In [37]: a = np.arange(25).reshape(5,5)
In [38]: a
Out[38]:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
In [39]: a[0]
Out[39]: array([0, 1, 2, 3, 4])
In [40]: a[1]
Out[40]: array([5, 6, 7, 8, 9])
In [43]: a[0:2]
Out[43]:
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
In [47]: a[1:3]
Out[47]:
array([[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
In [48]: a[0][0]
Out[48]: 0
In [53]: a[0,0]
Out[53]: 0
In [51]:
a[0][0]
和 a[0,0]
是等价的。
4.2 三维数组
NumPy
索引,功能强大,不仅支持切片操作,还支持布尔型按条件筛选操作。
In [152]: m = np.arange(18).reshape(2,3,3)
In [153]: n = np.arange(18)
In [154]: m
Out[154]:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]]])
:
表示此维度的所有元素全部获取:
In [155]: m[:,1:2,:]
Out[155]:
array([[[ 3, 4, 5]],
[[12, 13, 14]]])
In [156]: m[:,1:2,:1]
Out[156]:
array([[[ 3]],
[[12]]])
In [157]:
按照维度赋值:
In [157]: m[:,0,:] = -2
In [158]: m
Out[158]:
array([[[-2, -2, -2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[-2, -2, -2],
[12, 13, 14],
[15, 16, 17]]])
In [159]: m[:,:,1]
Out[159]:
array([[-2, 4, 7],
[-2, 13, 16]])
In [160]:
判断上面切片 m[:,:,0]
中大于 5 的元素,写法简洁,无需写 for
循环。
In [160]: m
Out[160]:
array([[[-2, -2, -2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[-2, -2, -2],
[12, 13, 14],
[15, 16, 17]]])
In [161]: m[m>5]
Out[161]: array([ 6, 7, 8, 12, 13, 14, 15, 16, 17])
In [162]: