# 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> :::