> ✊不积跬步,无以至千里;不积小流,无以成江海。 |
|
> NumPy是Python中的一个运算速度非常快的一个数学库,它主要侧重数组的相关操作。它允许你在Python中进行向量和矩阵计算,并且由于许多底层函数实际上是用C编写的,因此在原生Python中它的计算执行速度是非常快的. |
|
# 一些数学知识 |
|
> 🔔 向量 : 理论数学中 , 同时满足具有大小和方向两个性质的几何对象即可认为是向量 . 一般的,它们通常用于表示速度,加速度和动量等事物。向量可以用多种方式编写,在numpy中最有用的是它们被写为n元组的形式,如(1,4,6,9)。这就是我们在NumPy中表示他们的方式。 |
|
|
|
> 🔔 矩阵 : 是一个按照长方阵列排列的复数或实数集合 ,最早来自于方程组的系数及常数所构成的方阵。矩阵类似于矢量,除了它由行和列组成; 很像一个网格。可以通过给出它所在的行和列来引用矩阵中的值。 这一概念由19世纪英国数学家凯利首先提出。 矩阵是高等代数学中的常见工具,也常见于统计分析等应用数学学科中。 |
|
--- |
|
# 数组基础 |
|
### 🔎 创建一个数组(4种方式) |
|
```python |
import numpy as np |
a = np.array([0, 1, 2, 3, 4]) |
b = np.array((0, 1, 2, 3, 4)) |
c = np.arange(5) |
d = np.linspace(0, 2*np.pi, 5) |
|
print(a) |
print(a[2]) |
print(b) |
print(c) |
print(d) |
|
''' |
[0 1 2 3 4] |
2 |
[0 1 2 3 4] |
[0 1 2 3 4] |
[0. 1.57079633 3.14159265 4.71238898 6.28318531] |
''' |
🎈 当我们打印具有不同长度数字的数组时,它会自动将它们填充出来。这对于查看矩阵很有用 |
``` |
|
### 🔎 使用多维数组表示矩阵 |
|
```python |
🎈 2维(2D)数组的创建,传递的是列表的列表,(或者是一个序列的序列)给array()函数。如果我们想要一个3D(三维)数组,我们就要传递一个列表的列表的列表,如果是一个4D(四维)数组,那就是列表的列表的列表的列表,以此类推 |
|
📌取1行,2列的元素 12 |
|
a = np.array([[11, 12, 13, 14, 15], |
[16, 17, 18, 19, 20], |
[21, 22, 23, 24, 25], |
[26, 27, 28 ,29, 30], |
[31, 32, 33, 34, 35]]) |
print(a[0,1]) #12 |
``` |
|
### 🔎 多维数组切片 |
|
```python |
a = np.array([[11, 12, 13, 14, 15], |
[16, 17, 18, 19, 20], |
[21, 22, 23, 24, 25], |
[26, 27, 28, 29, 30], |
[31, 32, 33, 34, 35]]) |
print(a[0, 0:3]) # [11 12 13] 取1行,头3列元素,顾头不顾尾 |
print(a[2:5, 2]) # [23 28 33] |
print(a[::2, ::2]) #支持步长 |
''' |
[[11 13 15] |
[21 23 25] |
[31 33 35]] |
''' |
print(a[:, 1]) # [12 17 22 27 32] |
``` |
|
|
|
### 🔎 数组属性 |
|
```python |
a = np.array([[11, 12, 13, 14, 15], |
[16, 17, 18, 19, 20], |
[21, 22, 23, 24, 25], |
[26, 27, 28, 29, 30], |
[31, 32, 33, 34, 35]]) |
|
print(type(a)) # <class 'numpy.ndarray'> 用ndarray表示一个n维的数组,这是一个ndarray对象 |
|
print(a.dtype) # int32 #查看数组的数据类型,为 int32 |
|
print(a.size) # 25 # 查看数组的大小 |
|
print(a.shape) # (5, 5) 表示数组的形状,比如这个是5行5列的矩阵,表示为(5,5) |
|
print(a.itemsize) # 4 #每个项占用的字节数。这个数组的数据类型是int 32,一个int 32中有32位,一个字节中有8位,除以32除以8,你就可以得到它占用了多少字节,在本例中是4。 |
|
print(a.ndim) # 2 数组的维度 |
|
print(a.nbytes) # 100 数组中的所有数据消耗掉的字节数。这并不表示数组的开销,因此数组占用的实际空间将稍微大一点 |
|
``` |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
# 使用数组 |
|
### |
基本操作符 |
只是能够从数组中创建和检索元素和属性是不够的,有时也需要对它们进行数学运算。 可以使用四则运算符 **+、- 、/ **来完成运算操作 |
|
```python |
🎈除了 dot() 之外,这些操作符都是对数组进行逐元素运算。比如 (a, b, c) + (d, e, f) 的结果就是 (a+d, b+e, c+f)。它将分别对每一个元素进行配对,然后对它们进行运算。它返回的结果是一个数组。注意,当使用逻辑运算符比如 “<” 和 “>” 的时候,返回的将是一个布尔型数组 |
|
a = np.arange(25) # 生成一个数组 1D 0到24 |
a = a.reshape((5, 5)) # 变形 2D 数组 |
b = np.array([10, 62, 1, 14, 2, 56, 79, 2, 1, 45, |
4, 92, 5, 55, 63, 43, 35, 6, 53, 24, |
56, 3, 56, 44, 78]) |
b = b.reshape((5, 5)) |
print(a) |
''' |
[[ 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]] |
''' |
print(b) |
''' |
[[10 62 1 14 2] |
[56 79 2 1 45] |
[ 4 92 5 55 63] |
[43 35 6 53 24] |
[56 3 56 44 78]] |
''' |
print(a+b) |
''' |
[[ 10 63 3 17 6] |
[ 61 85 9 9 54] |
[ 14 103 17 68 77] |
[ 58 51 23 71 43] |
[ 76 24 78 67 102]] |
''' |
print(a-b) |
''' |
[[-10 -61 1 -11 2] |
[-51 -73 5 7 -36] |
[ 6 -81 7 -42 -49] |
[-28 -19 11 -35 -5] |
[-36 18 -34 -21 -54]] |
''' |
print(a * b) |
''' |
[[ 0 62 2 42 8] |
[ 280 474 14 8 405] |
[ 40 1012 60 715 882] |
[ 645 560 102 954 456] |
[1120 63 1232 1012 1872]] |
''' |
print(a / b) |
''' |
[[0. 0.01612903 2. 0.21428571 2. ] |
[0.08928571 0.07594937 3.5 8. 0.2 ] |
[2.5 0.11956522 2.4 0.23636364 0.22222222] |
[0.34883721 0.45714286 2.83333333 0.33962264 0.79166667] |
[0.35714286 7. 0.39285714 0.52272727 0.30769231]] |
''' |
print(a**2) |
''' |
[[ 0 1 4 9 16] |
[ 25 36 49 64 81] |
[100 121 144 169 196] |
[225 256 289 324 361] |
[400 441 484 529 576]] |
''' |
print(a < b) |
''' |
[[ True True False True False] |
[ True True False False True] |
[False True False True True] |
[ True True False True True] |
[ True False True True True]] |
''' |
print(a > b) |
''' |
[[False False True False True] |
[False False True True False] |
[ True False True False False] |
[False False True False False] |
[False True False False False]] |
''' |
``` |
|
```python |
🎈 dot() 函数计算两个数组的点积。它返回的是一个标量(只有大小没有方向的一个值)而不是数组。 |
🎈 numpy中多维数组的点积就是高数中的矩阵乘法 |
|
a = np.arange(25) # 生成一个数组 1D 0到24 |
a = a.reshape((5, 5)) # 变形 2D 数组 |
b = np.array([10, 62, 1, 14, 2, 56, 79, 2, 1, 45, |
4, 92, 5, 55, 63, 43, 35, 6, 53, 24, |
56, 3, 56, 44, 78]) |
b = b.reshape((5, 5)) |
print(a) |
''' |
[[ 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]] |
''' |
print(b) |
''' |
[[10 62 1 14 2] |
[56 79 2 1 45] |
[ 4 92 5 55 63] |
[43 35 6 53 24] |
[56 3 56 44 78]] |
''' |
print(a.dot(b)) # 即把 a 数组每一行的元素与 b 数组每一列的元素相乘之后的结果的和,为最终结果。且两个数组需要满足第一个的列数等于第二个数组的行数,即a = MN ,b = NP |
''' |
[[ 417 380 254 446 555] |
[1262 1735 604 1281 1615] |
[2107 3090 954 2116 2675] |
[2952 4445 1304 2951 3735] |
[3797 5800 1654 3786 4795]] |
''' |
``` |
|
|
|
|
### 背后的一点数学知识 |
|
矩阵相乘最重要的方法是一般矩阵乘积。它只有在第一个矩阵的列数和第二个矩阵的行数相同时才有意义 。一般单指矩阵乘积时,指的便是一般矩阵乘积。一个m×n的矩阵就是m×n个数排成m行n列的一个数阵。由于它把许多数据紧凑地集中到了一起,所以有时候可以简便地表示一些复杂的模型,如电力系统网络模型 |
|
|
|
🎯注意事项 |
|
- 当矩阵A的列数(column)等于矩阵B的行数(row)时,A与B可以相乘。 |
- 矩阵C的行数等于矩阵A的行数,C的列数等于B的列数。 |
- 乘积C的第m行第n列的元素等于矩阵A的第m行的元素与矩阵B的第n列对应元素乘积之和。 |
|
|
|
### 特殊运算符 |
|
```python |
🎨 # sum, min, max, cumsum |
|
a = np.arange(10) #[0 1 2 3 4 5 6 7 8 9] |
print(a) |
print(a.sum()) #45 |
print(a.min()) #0 |
print(a.max()) #9 |
print(a.cumsum()) # [ 0 1 3 6 10 15 21 28 36 45] |
|
🍄 cumsum()函数,它的结果是数组中第 n 和 n+1 个元素相加的结果存到一个新的列表中,再将这个累加的结果与原数组中的下一个元素相加得到的结果存到下一个列表中,依次类推 |
``` |
|
--- |
|
# 索引进阶 |
|
### 花式索引 |
|
> 花式索引指的是利用整数数组进行索引 |
> 花式索引跟切片不一样,它总是将数据复制到新数组中,产生一个新数组 |
|
```python |
🎈 一维数组 |
a = np.arange(0, 100, 10) |
indices = [1, 5, -1] |
b = a[indices] |
print(a) # >>>[ 0 10 20 30 40 50 60 70 80 90] |
print(b) # >>>[10 50 90] 取索引为1,-5,-1的元素组成新的数组 |
|
🎈 二维数组 |
arr=np.arange(32).reshape((4,8)) |
print(arr) |
''' |
[[ 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 25 26 27 28 29 30 31]] |
''' |
print(arr[:,[1,3]]) # : 取所有行,第1,3列的交集元素,组成一个新的数组 |
''' |
[[ 1 3] |
[ 9 11] |
[17 19] |
[25 27]] |
''' |
print(arr[[1,3,2],3]) # 取第1,3,2行,第3列的交集元素,组成一个新的数组 |
|
''' |
[11 27 19] |
''' |
🔔 补充:特别注意,使用花式索引时,如果两边都是花式索引,会出问题,或者报错 |
如下: |
arr=np.arange(32).reshape((4,8)) |
print(arr[[1,3,2],[1,3]]) |
|
''' |
File "C:/Users/blingabc/PycharmProjects/pythonProject/科学计算/NumPy学习", line 72, in |
print(arr[[1,3,2],[1,3]]) |
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (3,) (2,) |
|
''' |
|
|
两边都为花式索引时,就会换一种解析的方式,会取出,按照类似了坐标的取法,取出 [1,2]和[3,4]这么两个数,而不是二维数组的形式,因为取法类似于坐标,所以两边使用花式索引时,要保证两边的个数时一样的。 |
那我们就想这么取,而且还能达到我们想要的结果,怎么办? |
|
🎯🎯🎯 思路:分两步, 先切行,再切列 |
|
a = np.arange(5,35).reshape(5,6) |
print(a) |
''' |
[[ 5 6 7 8 9 10] |
[11 12 13 14 15 16] |
[17 18 19 20 21 22] |
[23 24 25 26 27 28] |
[29 30 31 32 33 34]] |
''' |
print(a[[1,3],:][:,[2,4]]) |
''' |
[[13 15] |
[25 27]] |
''' |
|
``` |
|
### 布尔屏蔽(布尔索引) |
|
> 🎈 根据我们指定的条件检索数组中的元素 |
|
```python |
🎨 eg1 : |
|
arr = np.arange(10) |
print(arr[arr > 5]) |
''' |
[6 7 8 9] |
''' |
|
📌📌📌 布尔索引取值的原理: |
arr = np.arange(10) |
print(arr[arr > 5]) |
''' |
[6 7 8 9] |
''' |
print(arr > 5) |
''' |
[False, False, False, False ,False, False, True, True , True , True] |
''' |
print(arr[[False, False, False, False ,False, False, True, True , True , True]]) |
''' |
[6 7 8 9] |
''' |
🔔 解释:将同样大小的布尔数组传进索引,会返回一个由所有True对应位置上元素的数组 |
``` |
|
### 缺省索引(不完全索引) |
|
> 🎈 不完全索引是从多维数组的第一个维度获取索引或切片的一种方便方法。例如,如果数组a=[1,2,3,4,5],[6,7,8,9,10],那么[3]将在数组的第一个维度中给出索引为3的元素,这里是值4。 |
|
```python |
a = np.arange(0, 100, 10) |
print(a) |
b = a[:5] |
c = a[a >= 50] |
print(b) # >>>[ 0 10 20 30 40] |
print(c) # >>>[50 60 70 80 90] |
``` |
|
### Where 函数 |
|
> 🎈 where() 函数是另外一个根据条件返回数组中的值的有效方法。只需要把条件传递给它,它就会返回一个使得条件为真的元素的列表。 |
|
```python |
a = np.arange(0, 100, 10) |
print(a) # [ 0 10 20 30 40 50 60 70 80 90] |
b = np.where(a < 50) |
c = np.where(a >= 50)[0] |
print(b) # >>>(array([0, 1, 2, 3, 4]),dtype=int64),) # 返回满足条件元素所对应的索引列表.第二个是表示该数据给int64的数据类型 |
print(c) # >>>[5 6 7 8 9] # 只拿满足条件为真的元素索引 |
``` |