Python 常用模块系列:
- [Python] 常用模块(1):内建模块 – random & datetime
- [Python] 常用模块(2):内建模块 – re 以及正则表达式
- [Python] 常用模块(3):内建模块 – math & itertools
- [Python] 常用模块(4):NumPy 上
- [Python] 常用模块(4):NumPy 中(本文)
- [Python] 常用模块(4):NumPy 下
- [Python] 常用模块(5):pandas 1
- [Python] 常用模块(5):pandas 2
- [Python] 常用模块(5):pandas 3
- [Python] 常用模块(5):pandas 4
- [Python] 常用模块(5):pandas 5
- [Python] 常用模块(5):pandas 6
- [Python] 常用模块(5):pandas 7
- [Python] 常用模块(5):pandas 8
- [Python] 常用模块(5):pandas 9
数组的切片和索引
一维数组
一维数组的切片和索引与列表相同,可以以列表的切片和索引方式进行切片和索引。
- 切片:除了使用列表的切片方法进行切片以外,也可以用内置函数
slice
进行切片,语法与列表的切片相同。
>>> a = np.arange(10)
>>> a[2:7:2] # 列表的切片方法
array([2, 4, 6])
>>> s = slice(2, 9, 2) # slice 函数。注意标点的变化
>>> a[s]
array([2, 4, 6, 8])
- 索引:数组的索引与列表的索引相同。
>>> a[5]
5
多维数组
与一维数组不同的是,多维数组的切片和索引需要指定维度。若某一个维度没有指定,则默认切片该维度下的所有元素。
>>> b = np.arange(24).reshape([2, 3, 4])
>>> b
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]]])
>>> b # 没有指定维度,相当于选择全部元素
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]]])
>>> b[1] # 只选择了第一个维度中的第二个元素
array([[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])
>>> b[1, 1] # 选择了第一个维度里的第二个元素在下一个维度里的第二个元素
array([16, 17, 18, 19])
>>> b[1, 1, 1] # 选择了第一个维度里的第二个元素在下一个维度里的第二个元素在下一个维度里的第二个元素
17
使用 ‘:’ 和 ‘…’ 切片
与列表一样,:
的作用是选择索引前面或后面的所有元素。
>>> a[5:] # 以前面创建的数组 a 为例
array([5, 6, 7, 8, 9])
...
选择与数组维度相同的元素。
>>> b[...,1:,:1]
array([[[ 4],
[ 8]],
[[16],
[20]]])
请思考一下,为什么会是这样的结果?答案在文末。
运算的广播机制
还记得列表相加和相乘吗?咱们来复习一下:
>>> c = [2, 3, 4]
>>> d = [5, 6, 7]
>>> c + d
[2, 3, 4, 5, 6, 7]
>>> c * 2
[2, 3, 4, 2, 3, 4,]
>>> c * d
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-101-9f681d1a24d9> in <module>
----> 1 c*d
TypeError: can't multiply sequence by non-int of type 'list'
基本上,列表与列表相加相当于合并了两个列表;列表与数字相乘相当于把列表复制后合并;而 Python 不知道如何将两个列表相乘。NumPy 数组则不一样。
>>> e = np.arange(7, 10) # array([7, 8, 9])
>>> f = np.arange(10, 13) # array([10, 11, 12])
>>> e + f
array([17, 19, 21])
>>> e + 5
array([12, 13, 14])
>>> e * 2
array([14, 16, 18])
>>> e * f
array([ 70, 88, 108])
如果两个数组的维度相同,则运算结果为元素对应位置运算的结果;若维度不同,则自动触发广播机制。简单来说,
- 数组拥有相同形状。
- 当前维度的值相等。
- 当前维度的值有一个是 1。
则可以继续运算。若第二个数组是一个数字,则该数字看成一个长度为 1 的一元数组。若条件不满足,则返回错误。
>>> g = np.array([19, 20])
>>> e + g
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-111-f7b8d2d62fd1> in <module>
1 g = np.array([19, 20])
----> 2 e + g
ValueError: operands could not be broadcast together with shapes (3,) (2,)
数组的运算
元素运算
- 加、减、乘、除的部分非常直观,直接在示例里演示相加。
>>> h = np.arange(20, 26).reshape([2, 3]) # array([[20, 21, 22],
# [23, 24, 25]])
>>> i = np.ones([2, 3], dtype = int) + 4 # array([[5, 5, 5],
# [5, 5, 5]])
>>> h + i # 相加,减、乘、除相似,略
array([[25, 26, 27],
[28, 29, 30]])
- 倒数、平方
>>> 1 / h # 倒数
array([[0.05 , 0.04761905, 0.04545455],
[0.04347826, 0.04166667, 0.04 ]])
>>> h ** 2 # 平方
array([[400, 441, 484],
[529, 576, 625]])
- 指数
使用np.exp()
进行运算。
>>> np.exp(h)
array([[4.85165195e+08, 1.31881573e+09, 3.58491285e+09],
[9.74480345e+09, 2.64891221e+10, 7.20048993e+10]])
- 对数
使用np.log()
进行运算。
>>> np.log(h)
array([[2.99573227, 3.04452244, 3.09104245],
[3.13549422, 3.17805383, 3.21887582]])
- 比较
>>> h > i
array([[ True, True, True],
[ True, True, True]])
>>> h > 24
array([[False, False, False],
[False, False, True]])
元素整合运算
- 求和
求和使用ndarray.sum()
。这里有两种情况:求整个数组的元素和和某个维度的元素和。对于第二种情况,需要在括号内指定轴。
>>> b.sum() # 使用本文前边定义的数组 b,求整个数组的和
276
>>> b.sum(axis = 0)
array([[12, 14, 16, 18],
[20, 22, 24, 26],
[28, 30, 32, 34]])
>>> b.sum(axis = 1)
array([[12, 15, 18, 21],
[48, 51, 54, 57]])
>>> b.sum(axis = 2)
array([[ 6, 22, 38],
[54, 70, 86]])
一个数组有几个维度就有几个轴。
- 统计运算:求最小值、最大值、平均值、标准差和累加
分别可以用 ndarray.min(),ndarray.max(),ndarray.mean(),ndarray.std() 和 ndarray.cumsum() 运算,既可以对整个数组进行运算,也可以在每个轴上进行运算,规则与求和是一样的。
>>> print(h.sum(axis = 1))
[63 72]
>>> print(h.mean(axis = 0))
[21.5 22.5 23.5]
>>> print(h.cumsum())
[20 41 63 86 110 135]
二维数组的行和列
NumPy 规定, 二维数组的第 0 轴沿着行的垂直往下,第 1 轴沿着列的方向水平延伸。这么说非常抽象,老宅会专门写一篇文章讨论轴的问题。