---
# System prepended metadata

title: 2024.5.12 上課講義
tags: [雄資, 資研]

---

# 2024.5.12 上課講義

## 模組 Module & 套件 Package

[**Python函式庫**](https://docs.python.org/zh-tw/3/library/index.html)

### 模組 Module

一個`Python`檔案就類似於一個模組，當一次需要撰寫大量內容或長時間維護時，有時會將部分定義程式碼分檔案撰寫，而在主模組（main）中就可以透過`import`來引入模組。

>別名可以按照自己的習慣去命名，目的是撰寫程式碼時方便輸入

```python=
import datetime
import datetime as dt
from random import randint
```

:::warning
**檢視模組是否引入成功**

```python=
print( datetime.__file__ )
```

>file 前後為雙底線

:::

### 套件 Package

若一個模組形似一個檔案，則套件就類似於一個資料夾，包含許多模組，在主模組（main）中可以透過`from`來引入套件中的模組。

```python=
from matplotlib import pyplot
from matplotlib import pyplot as plt
```

:::warning
**import all 的寫法**

可以一次性引入所有在該套件下的模組

```
from 套件名稱 import *
```
:::

---

## Dates 模組

模組可以自行定義但`Python`也有很多已經撰寫好的模組可以引用，但在一般電腦內的直譯器內模組需另外下載，不過Colab不需要另外下載，需要注意的是在正規測驗、競賽中（如APCS）是無法適用的

### 引入模組

```python=
import datetime
```

### 顯示現在時間

```python=
x = datetime.datetime.now()
y = datetime.datetime.today()
```

1. 顯示的是**GMT標準時間**也就是英國倫敦格林威治天文臺當下的時間，並非主機所位在地點之當地時間
2. 回傳的資料包含年份 year、月份 month、日期 day、小時 hour、分鐘 minute、秒 second、微秒 microsecond
3. 可以透過`.+需要的資料`來進一步取得時間

>對應的英文：年份 year、月份 month、日期 day、小時 hour、分鐘 minute、秒 second、微秒 microsecond

```python=
print(x.year)
```

:::warning
**屬性 attributes vs. 函式 methods**

<Font color="#CE0000">**屬性**</Font>是一個**物件本身的特性**
而<Font color="#CE0000">**函式**</Font>則是**作用在該物件的動作**
:::

### 建立時間點

```python=
x = datetime.datetime(2024, 4, 12)
```

回傳：2024-04-12 00\:00\:00

>沒有給定的會預設為0

### 轉換當地時間

```python=
time_del = datetime.timedelta(hours = -8)
now = datetime.datetime.now()
loc = now - time_del 
now_datetime_format = now.strftime("%Y/%m/%d %H:%M:%S")
loc_datetime_format = loc.strftime("%Y/%m/%d %H:%M:%S")
print(now_datetime_format, loc_datetime_format, sep='\n')
```

:::spoiler 符號

| 符號 |              意義               |            範例            |
|:----:|:-------------------------------:|:--------------------------:|
|  %a  |          星期幾的簡稱           |        Mon, Tue...         |
|  %A  |             星期幾              |     Monday, Tuesday...     |
|  %w  |       星期幾（0->星期日）       |       0, 1, 2..., 6        |
|  %d  |              日期               |     01, 02, 03..., 31      |
|  %b  |            月份縮寫             |        Jan, Feb...         |
|  %B  |              月份               |    January, February...    |
|  %m  |              月份               |       01, 02..., 12        |
|  %y  |          年份（後2位）          |         00, 01...          |
|  %Y  |              年份               |   0001, 0002..., 2024...   |
|  %H  |        小時（24小時制）         |       00, 01..., 23        |
|  %I  |        小時（12小時制）         |       00, 01..., 12        |
|  %M  |              分鐘               |       00, 01..., 59        |
|  %S  |               秒                |       00, 01..., 59        |
|  %f  |              微秒               | 000000, 000001..., 999999  |
|  %U  | 周序號（從0開始, 以周日為開始） |       00, 01..., 53        |
|  %W  | 周序號（從0開始, 以周一為開始） |       00, 01..., 53        |
|  %c  |            日期+時間            | Tue Apr 16 14\:00\:00 2024 |
|  %x  |              日期               |          04/16/24          |
|  %X  |              時間               |         14\:00\:00         |

[**其他符號**](https://docs.python.org/zh-tw/3/library/datetime.html#strftime-and-strptime-behavior)

:::

---

## Math 模組

`Python`本身就有內建的數學函式，`Math`模組算是一個擴充，有更多跟數學相關的函式

```python=
import math
```

### 取最近整數

>類似於[**高斯符號**](https://zh.wikipedia.org/zh-tw/%E5%8F%96%E6%95%B4%E5%87%BD%E6%95%B0) []

```python=
print(math.ceil(13.873096))
print(math.floor(13.873096))
```

1. ceil是取大於該數且最相近之整數
2. floor是取小於該數且最相近之整數

### π

```python=
print(math.pi)
```

[**其他函式**](https://www.w3schools.com/python/module_math.asp)

---

## 矩陣

### 定義

當一個 $m*n$ 的矩陣，有 $m$ 列、 $n$ 行

>直行橫列

### 零矩陣

可記為 $O_{m*n}$ ，且全部的數字皆為 $0$

$e.g.\ O_{1*3} = \left[ 
\begin{array}{ccc}
0 &&0 &&0 \\
\end{array}\right]$ 

$e.g.\ O_{2*4} = \left[ 
\begin{array}{cccc}
0 &&0 &&0 &&0 \\
0 &&0 &&0 &&0 \\
\end{array}\right]$ 

### 單位方陣

可記為 $I_n$ ，必為方陣且所有主對角線數字為 $1$ 其餘為 $0$

:::warning
任何矩陣乘以單位方陣皆不會改變原來的值
:::

$e.g.\ I_{2} = \left[ 
\begin{array}{cc}
1 &&0 \\
0 &&1 \\
\end{array}\right]$ 

$e.g.\ I_{3} = \left[ 
\begin{array}{ccc}
1 &&0 &&0 \\
0 &&1 &&0 \\
0 &&0 &&1 \\
\end{array}\right]$ 

### 矩陣加法、減法

同階矩陣才可相加減，運算時，相對應位置數字進行運算

$e.g.\ A = \left[
\begin{array}{ccc}
1 &&0 &&3 \\
5 &&6 &&0 \\
10 &&0 &&1 \\
\end{array}\right]，
B = \left[ 
\begin{array}{ccc}
1 &&6 &&4 \\
0 &&1 &&-1 \\
7 &&2 &&1 \\
\end{array}\right]$

$A + B = \left[ 
\begin{array}{ccc}
1+1 &&0+6 &&3+4 \\
5+0 &&6+1 &&0-1 \\
10+7 &&0+2 &&1+1 \\
\end{array}\right]
=\left[ 
\begin{array}{ccc}
2 &&6 &&7 \\
5 &&7 &&-1 \\
17 &&2 &&2 \\
\end{array}\right]$

### 係數積

若將一個矩陣乘以k倍，則將該矩陣內每一個元素都乘以k倍

$e.g.\ A = \left[ 
\begin{array}{ccc}
a_{11} &&a_{12} &&a_{13} \\
a_{21} &&a_{22} &&a_{23} \\
a_{31} &&a_{32} &&a_{33} \\
\end{array}\right]$

$A * k = \left[ 
\begin{array}{ccc}
a_{11}*k &&a_{12}*k &&a_{13}*k \\
a_{21}*k &&a_{22}*k &&a_{23}*k \\
a_{31}*k &&a_{32}*k &&a_{33}*k \\
\end{array}\right]$

### 轉置矩陣

若將一個矩陣轉置，則將該矩陣內的所有行列互換

$e.g.\ A = \left[ 
\begin{array}{ccc}
1 &&0 &&3 \\
5 &&6 &&0 \\
\end{array}\right]$

$\ A^T = \left[ 
\begin{array}{cc}
1 &&5 \\
0 &&6 \\
3 &&0 \\
\end{array}\right]$

### 矩陣乘法

必須 **前一個矩陣的行數** 和 **後一個矩陣的列數** 相同才可進行乘法

>$A_{x*y} * B_{y*z} = C_{x*z}$

$e.g.\ A = \left[
\begin{array}{ccc}
a_{11} &&a_{12} &&a_{13} \\
a_{21} &&a_{22} &&a_{23} \\
\end{array}\right]，
B = \left[ 
\begin{array}{cc}
b_{11} &&b_{12} \\
b_{21} &&b_{22} \\
b_{31} &&b_{32} \\
\end{array}\right]$

$A * B = \left[ 
\begin{array}{ccc}
a_{11}*b_{11}+a_{12}*b_{21}+a_{13}*b_{31} &&a_{11}*b_{12}+a_{12}*b_{22}+a_{13}*b_{32}\\
a_{21}*b_{11}+a_{22}*b_{21}+a_{23}*b_{31} &&a_{21}*b_{12}+a_{22}*b_{22}+a_{23}*b_{32} \\
\end{array}\right]$

### 反矩陣

A的反矩陣可記為 $A^{-1}$ ，2者相乘為 $1$

假設 $A = \left[ 
\begin{array}{cc}
a &&b \\
c &&d \\
\end{array}\right]，det(A) = \begin{vmatrix}
a & b \\
c & d
\end{vmatrix}$

則$A^{-1} = 
\cfrac{1}{det(A)} *\left[ 
\begin{array}{cc}
d &&-b \\
-c &&a \\
\end{array}\right]$

### 解方程式

$3x + 2y = 7$
$4x - 3y = -2$

A為係數矩陣、B為常數矩陣、X為未知數

$A = \left[ 
\begin{array}{cc}
3 &&2 \\
4 &&-3 \\
\end{array}\right]，
B = \left[ 
\begin{array}{c}
7\\
-2\\
\end{array}\right]，
X = \left[ 
\begin{array}{c}
x\\
y\\
\end{array}\right]$

原式

$A*X = B$
$\Rightarrow A*A^{-1}*X = B*A^{-1}$
$\Rightarrow X = B*A^{-1}$

---

## Numpy 官網

[**Numpy 官網**](https://numpy.org/)

### 為什麼需要 Numpy

Numpy 的架構中，有`ndarray`可以使用，在用法上跟`List`很像，但方便性、執行速度都比`List`快上許多

>ndarray 全名為 n-dimensional array 是一種多維陣列，為 Numpy 獨有的資料型態

### 建立 array

```python=
import numpy as np
```

- 利用`List`、`Tuple`轉換成`array`

```python=
A = np.array([1, 2, 3, 4, 5])
B = np.array((1, 2, 3, 4, 5))
```

:::warning
**ndarray**

其中的`nd`代表這個陣列的維度，可以使用`arr.ndim`來回傳該資料的維度

>其中不能有數字和列表同地位的狀況

ex. 0d

```python=
A = np.array(42)
print(A, type(A), A.ndim)
```

ex. 1d

```python=
A = np.array([42])
print(A, type(A), A.ndim)
```

ex. 2d

```python=
A = np.array([[1, 2, 3], [4, 5, 6]])
print(A, type(A), A.ndim)
```

ex. 3d

```python=
A = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])
print(A, type(A), A.ndim)
```

- `.size`回傳所有元素數量
- `.shape`以`Tuple`的形式返回每個axis的長度

```python=
A = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])

print(A.size)
print(A.shape)
```

:::

- 建立初始化矩陣，利用`Tuple`來包裝想要的矩陣大小
    - 利用`np.ones()`來創造全為 $1$ 的矩陣
    - 利用`np.zeros()`來創造全為 $0$ 的矩陣

>記得有2個`()`

```python=
A = np.ones((2, 3))
B = np.zeros((1, 4))

print(A)
print(B)
```

- 建立單位矩陣

利用`.eye(n)`，來建立$n*n$的單位矩陣

```python=
A = np.eye(4)

print(A)
```

### indexing

有2種方式，1種和之前一樣，另1種和之前的`List`，有些許不同，利用`[]`依序輸入各維度index，並用`,`隔開

```
[[1, 2, 3], 
[4, 5, 6]]
```

以取出第一列第二個數字來示範，

**List**

```python=
A = [[1, 2, 3], [4, 5, 6]]

print(A[0][1])
```

**Array**

```python=
nd_A = np.array(A)

print(nd_A[0, 1])
print(nd_A[0][1])
```

### slicing

和之前的`List`相同，利用`[]`依序輸入開頭及結尾的index並用`:`隔開

```
[start:end:step]
```

>end一樣不包含

```python=
A = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])

print(A[0, 1:3])
```

### 加減法

相同大小的2矩陣可利用`+`、`-`來進行各位置的加減法

```python=
A = np.array([[1, 2, 3], [4, 5, 6]])
B = np.array([[8, 9, 1], [-1, 6, 10]])

print(A+B)
print(A-B)
```

### 重塑 reshape

使用`arr.reshape(a, b, c...)`將原本的矩陣重新組合成指定大小的多維矩陣

>a, b, c ... 為各維度中指定個數

:::warning
注意矩陣內的元素**總數**需相同，否則會報錯

>使用 -1 可以讓電腦自行運算

:::

```python=
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])
arr = arr.reshape(2, 4)
print(arr)
print(arr.shape)
```

### 疊加 stacking

分別利用`np.vstack((arr1, arr2))`、`np.hstack((arr1, arr2))`將兩 <font color="#CE0000">**Tuple、List、ndarray**</font> 依 **鉛直軸vertical axis 、 水平軸horizontal axis** 疊加，並一律用ndarray回傳值

:::warning
若使用`np.vstack`，則兩陣列**行數**需相同
若使用`np.hstack`，則兩陣列**列數**需相同

**arr1和arr2在傳入時需事先包裝成一個Tuple**
:::

```python=
# vstack 行數相同
arr1 = [[1, 2], 
        [3, 4], 
        [5, 6]]

arr2 = [[-1, 2], 
        [3, 4]]

np.vstack((arr1, arr2))
```
```python=
# hstack 列數相同
arr1 = [[1, 2], 
        [3, 4], 
        [5, 6]]

arr2 = [[-1, 2, 4], 
        [3, 4, 2], 
        [6, 8, 9]]

np.hstack((arr1, arr2))
```

### 轉置 transpose

$A$ 轉置後的矩陣記做 $A^T$，在程式中利用`arr.T`回傳轉置後的陣列

```python=
arr = np.array([[2, 3, 10], [4, -1, 3]])

print(arr)
print(arr.T)
```

### 迭代函數 arange

利用`np.arange(a, b, c)`可以直接創造出一個符合迭代函數的List

>a 是起點，b 是終點（不包含），c 是間隔

```python=
a = np.arange(10)

print(a)
```

### 線性間距向量 linspace

利用`np.linspace(a, b, c)`，在 a 和 b 之間取出平均的 c 個點

>範圍包含 a、b

```python=
a = np.linspace(1, 7, 3)

print(a)
```

### 矩陣乘法

程式上利用`np.dot(arr1, arr2)`或是`arr1.dot(arr2)`回傳相乘過後的矩陣

>`np.dot(arr1, arr2)`也適用於List

```python=
arr1 = np.array([[1, 2], [3, 4]])

arr2 = np.array([[-1, 2], [6, 10]])

print(arr1.dot(arr2))
print(np.dot(arr1, arr2))
```

### 解方程式

:::info
**練習** [**網站**](https://numpy.org/doc/stable/reference/routines.linalg.html)
提示：`linalg`、不利用反矩陣

寫出一個能解出這個二元一次方程式的程式

> $3x+6y=-9$
> $-x-7y=13$

```python=
A = np.array([[3, 6], [-1, -7]])
B = np.array([-9, 13])

print(np.linalg.solve(A, B))
```

提示：`linalg`、利用反矩陣

> $3x+6y=-9$
> $-x-7y=13$

$A*X = B$
$\Rightarrow A*A^{-1}*X = B*A^{-1}$
$\Rightarrow X = B*A^{-1}$

寫出一個能解出這個二元一次方程式的程式

```python=
A = np.array([[3, 6], [-1, -7]])
B = np.array([-9, 13])

# inverse
A_inv = np.linalg.inv(A)

print(np.dot(A_inv, B))
```
:::

## Random

[**Random 官網**](https://docs.python.org/zh-tw/3/library/random.html)

```python=
import random
```

### randint

利用`random.randint(a, b)`隨機產生一個 a ~ b 間的整數

>有包含 b

```python=
random.randint(1, 10)
```

### random

利用`random.random()`隨機產生一個 0 ~ 1 間的實數

>有包含 0 不包含 1

```python=
random.random()
```

### randrange

利用`random.randrange(a, b, c)`以 c 為間隔，隨機產生一個 a ~ b 間的整數

>相當於在`np.arange(a, b, c)`中，隨機取一個數字

```python=
random.randrange(1, 100, 10)
```

### choice

從 A 中隨機抽取一個元素

>A 可以是 String、List、Tuple

```python=
L = [1, 23, 3, 4, 2, 7, 18, 29, 8, 72]
random.choice(L)
```

從 A 中隨機抽取 n 個元素（可能重複）

```python=
L = [1, 23, 3, 4, 2, 7, 18, 29, 8, 72]
random.choices(L, k=3)
```

### sample

從 A 中隨機抽取 n 個元素（不重複）

```python=
L = [1, 23, 3, 4, 2, 7, 18, 29, 8, 72]
random.sample(L, k=6)
```

### shuffle

將 A 中原本的元素順序打亂

```python=
L = [1, 23, 3, 4, 2, 7, 18, 29, 8, 72]
random.shuffle(L)
print(L)
```

:::info
**練習**
請試著用`random`寫出一個終極密碼（1~100）的程式

```python=
import random

seed = random.randint(1, 100)

game = True
ceil = 100
floor = 1
c = 0

while game:
  ans = int(input(f"請在{floor}~{ceil}之間猜一個數字"))
  if ans > seed:
    print("太大囉\n")
    ceil = ans
    c += 1
    continue
  elif ans < seed:
    print("太小囉\n")
    floor = ans
    c += 1
    continue
  else: # ans = seed
    c += 1
    break

print(f"恭喜遊戲結束，您猜對的正確答案為{seed}，一共猜了{c}次")
```
:::

## Matplotlib

[**官方資料**](https://matplotlib.org/stable/index.html)

> `Matplotlib` 為套件，這次我們會教的是裡面的 `pyplot` 這個模組

```python=
import numpy as np
import matplotlib.pyplot as plt
```

:::warning
**補充**

一般在 `Matplotlib.pyplot` 中，所顯示的字型皆為英文，如果要顯示中文需要加上一些步驟
>大部分時候用英文比較保險

1. 取得字型

    [**Mac的下載方式**](https://support.apple.com/zh-tw/guide/font-book/fntbk1000/mac)
    
    檔案總管>本機>Windows>Fonts
    然後右鍵複製，貼到其他地方（像是桌面），上傳到自己的雲端硬碟

2. 掛接雲端硬碟
    
    方法一：
    
    ![image](https://hackmd.io/_uploads/HJ27lVbz0.png)
    
    點左手邊，有一個檔案的符號
    ![image](https://hackmd.io/_uploads/BJaKlVWMR.png)

    點下去之後，按上方列表的第三項 — 掛接雲端硬碟 mount drive
    ![image](https://hackmd.io/_uploads/HyxUZ-V-MC.png)

    跳出頁面，按藍色的—同意
    ![image](https://hackmd.io/_uploads/HyAmZ4bfC.png)
    
    多出現一個 Drive 資料夾就是掛接成功
    ![image](https://hackmd.io/_uploads/Bkj6fVWMC.png)

    >*如果沒有出現可以點第二個的重整 refresh*
    >![image](https://hackmd.io/_uploads/HJ17QEZMR.png)

    
    方法二：
    
    直接執行下方程式
    ```python=
    from google.colab import drive
    drive.mount('/content/drive')
    ```
    
    執行成功即為掛接成功
    ![image](https://hackmd.io/_uploads/HyHO74WMR.png)
    
3. 取得路徑

    ![image](https://hackmd.io/_uploads/HJ27lVbz0.png)
    
    一樣點左手邊，有一個檔案的符號
    ![image](https://hackmd.io/_uploads/BJaKlVWMR.png)
    
    點開 Drive > MyDrive 資料夾
    ![image](https://hackmd.io/_uploads/SJFomNWfC.png)
    
    找到自己的字型檔案，右鍵複製檔案路徑 coby path
    ![image](https://hackmd.io/_uploads/r1rGNVWGR.png)

    檔案路徑就會自動處存到你的剪貼簿
    
4. 載入字型

    ```python=
    # 繪圖處理套件
    import matplotlib.font_manager as plt_font
    # 設定中文字體物件和字型檔案路徑
    twfont1 = plt_font.FontProperties(fname = 'file path')
    ```
    <font color="#CE0000">**file path的地方要記得填入自己的檔案路徑**</font>
:::
