# Numpy
###### tags: `Python` `Numpy`
#### 2022/03/17 by JohnAxer
## 基本觀念
- Numpy 是一個多維陣列的運算套件,可以用來進行矩陣相關運算。
- 在數學中的「矩陣」(Matrix),如果要丟到程式當中運算,我們通常會利用「陣列」(array) 來儲存。Numpy 提供一個可以高效的陣列和許多陣列計算函式,非常適合用來儲存科學或工程計算所需的資料,並作相關的計算。<span style="color: red;">但是請注意:陣列並不等於矩陣,所以有些計算方式是數學上的矩陣所沒有的。</span>
- 在 Numpy 中,陣列透過 ndarray 物件來實現。
## 認識陣列(矩陣)
- 假設陣列 A 如下:
$$
A = \begin{bmatrix}
11 & 12 \\
21 & 22 \\
31 & 32
\end{bmatrix}
$$
- 陣列 A 為「3列(row) 2行(column)」,其中列為橫的,行為直的。
- 在 numpy 中,利用元組(tuple) 紀錄陣列的形狀(shape),A 為 (3, 2) 的矩陣。
- 陣列大小(size) 其實就是陣列中的元素個數,所以,陣列 A 的大小為 6。
- 陣列 A 是一個 2維矩陣,所以,陣列 A 的維度(ndim) 為 2。
- 可以利用 A[2, 1] 或 A[2][1] 存取到最右下角的元素,其值為「32」。注意:如同串列(list)一樣,列索引值和行索引值都是從 0 開始。
- 一個 n 維陣列,會有 n 個軸(axis)。以陣列 A 為例,陣列 A 有兩個軸,那誰是axis 0呢?很簡單,看下圖就明白了。

- 程式碼
```python=
import numpy as np
a = np.array([[11, 12], [21, 22], [31, 32]])
print(type(a)) #顯示變數a的資料型態,結果為 ndarray
print(a.shape) #(3, 2)
print(a.size) #6
print(a.ndim) #2
print(a[2, 1]) #32
```
## 陣列建立
- **透過 List 轉換**
- 一維陣列
```python=
import numpy as np
a1 = np.array([10, 20, 30, 40])
```
這個會得到一個 1 維陣列如下:
$$
a1 = \begin{bmatrix}
10 & 20 & 30 & 40
\end{bmatrix}
$$
- 二維陣列
```python=
import numpy as np
a2 = np.array([[11, 12, 13], [21, 22, 23]])
```
這個程式得到一個 2 維陣列如下:
$$
a2 = \begin{bmatrix}
11 & 12 & 13 \\
21 & 22 & 23
\end{bmatrix}
$$
- 陣列形狀轉換
有時候,我們可以先輸入一個串列後,再改變形狀,例如:
```python=
import numpy as np
a3 = np.array([11, 12, 21, 22, 31, 32])
a3 = a3.reshape(3, 2)
```
執行後,會得到一個 3*2 的陣列如下:
$$
a3 =\begin{bmatrix}
11 & 12 \\
21 & 22 \\
31 & 32
\end{bmatrix}
$$
那麼下面這個程式,產生的陣列應該為何?
```python=
import numpy as np
a3 = np.array([11, 12, 21, 22, 31, 32])
a3 = a3.reshape(2, 3)
```
- **利用 arange 函數產生**
- arange 函數的用法基本上和 range 一樣,唯一的差別是 arange 可以產生浮點數的數列。
```python=
import numpy as np
a4 = np.arange(1, 5, 0.5)
print(a4)
```
結果如下:(注意: 1. 表示為 1 的浮點數)
$$
a4 = \begin{bmatrix}
1. & 1.5 & 2. & 2.5 & 3. & 3.5 & 4. & 4.5
\end{bmatrix}
$$
- **利用 linspace 函數產生**
- linspace 函數可以將指定區間平均分為 n-1 等分。其形式如下:
linspace(start, end, n)
- 注意到 linspace 函數預設是有包括 start 和 end 兩點。
- 考慮以下程式,其執行結果為何?
```python=
import numpy as np
s1 = np.linspace(0, 5, 5)
s2 = np.linspace(0, 5, 6)
```
$$
s1 = \begin{bmatrix}
0. & 1.25 & 2.5 & 3.75 & 5.
\end{bmatrix}
$$
$$
s2 = \begin{bmatrix}
0. & 1. & 2. & 3. & 4. & 5.
\end{bmatrix}
$$
- **利用隨機亂數產生**
- 除了 python 內建的 random 模組可以產生隨機亂數外,Numpy 也提供更強大的 random 模組,包括有:
- numpy.random.rand(): 產生 [0~1) 之間的隨機亂數(浮點數)
- numpy.random.normal(): 產生常態分配的隨機亂數(浮點數)
-
- **特殊的陣列**
- **元素都是 0 的陣列**
```python=
import numpy as np
a5 = np.zeros(5)
a6 = np.zeros((2,3))
a7 = np.zeros((2,3), dtype=int)
```
其中 a5、a6 陣列內的元素值均為 0 且為浮點數;a7 陣列內的元素值為整數 0。結果如下:
$$
a5 = \begin{bmatrix}
0. & 0. & 0. & 0. & 0.
\end{bmatrix}
$$
$$
a6 = \begin{bmatrix}
0. & 0. & 0. \\
0. & 0. & 0.
\end{bmatrix}
$$
$$
a7 = \begin{bmatrix}
0 & 0 & 0 \\
0 & 0 & 0
\end{bmatrix}
$$
- **元素都是 1 的陣列**
```python=
import numpy as np
a8 = np.ones(5)
a9 = np.ones((2,3))
a10 = np.ones((2,3), dtype=int)
```
其中 a8、a9 陣列內的元素值均為 1 且為浮點數;a10 陣列內的元素值為整數 1。結果如下:
$$
a8 = \begin{bmatrix}
1. & 1. & 1. & 1. & 1.
\end{bmatrix}
$$
$$
a9 = \begin{bmatrix}
1. & 1. & 1. \\
1. & 1. & 1.
\end{bmatrix}
$$
$$
a10 = \begin{bmatrix}
1 & 1 & 1 \\
1 & 1 & 1
\end{bmatrix}
$$
- **單位元素陣列**
```python=
import numpy as np
e1 = np.eye(3)
e2 = np.eye(2,3)
e3 = np.eye(3, dtype=int)
```
## 陣列的運算
- 假設有兩個陣列
$$
a = \begin{bmatrix}
1 & 2 \\
3 & 4 \\
5 & 6 \\
\end{bmatrix}\ \ \ \ \ \ \ \ \ \
b = \begin{bmatrix}
1 & 3 \\
2 & 2 \\
3 & 1 \\
\end{bmatrix}
$$
- 純量與陣列運算
- 純量會進行廣播(boardcast)運算。
- 例如:c = 5 + a,則
$$
c = \begin{bmatrix}
6 & 7 \\
8 & 9 \\
10 & 11 \\
\end{bmatrix}
$$
- python 的運算子(符號)均可以用,包括:+、-、*、/、//、%、**
```python=
import numpy as np
a = np.array([1, 2, 3, 4, 5, 6])
a = a.reshape(3, 2)
c = 5 + a
print(c)
```
- 陣列與陣列運算
- 陣列間運算的條件:
- 兩個陣列的形狀(shape)相同。
- 兩個陣列形狀(shape)不相同,但是其中一個陣列可以廣播成另一個形狀。
- python 的運算子(符號)均可以用,包括:+、-、*、/、//、%、**
- 例如: d = a + b
$$
d = \begin{bmatrix}
1 & 2 \\
3 & 4 \\
5 & 6 \\
\end{bmatrix}+
\begin{bmatrix}
1 & 3 \\
2 & 2 \\
3 & 1 \\
\end{bmatrix}=
\begin{bmatrix}
2 & 5 \\
5 & 6 \\
8 & 7 \\
\end{bmatrix}
$$
```python=
import numpy as np
a = np.array([1, 2, 3, 4, 5, 6])
b = np.array([1, 3, 2, 2, 3, 1])
a = a.reshape(3, 2)
b = e.resahpe(3, 2)
d = a + b
print(d)
```
- 數學矩陣運算
- 設有一個矩陣 e 如下
$$
e = \begin{bmatrix}
1 & 2 \\
2 & 1 \\
\end{bmatrix}
$$
- 矩陣 a 與 e 做矩陣乘法,可用運算符號「@」,則 f = a @ e 結果如下:
$$
f = \begin{bmatrix}
1 & 2 \\
3 & 4 \\
5 & 6 \\
\end{bmatrix}\times
\begin{bmatrix}
1 & 2 \\
2 & 1 \\
\end{bmatrix} =
\begin{bmatrix}
5 & 4 \\
11 & 10 \\
17 & 16 \\
\end{bmatrix}
$$
```python=
import numpy as np
a = np.array([1, 2, 3, 4, 5, 6])
e = np.array([1, 2, 2, 1])
a = a.reshape(3, 2)
e = e.resahpe(2, 2)
f = a @ e
print(f)
```