# Python 進階技術整理
[![](https://img.shields.io/badge/dynamic/json?color=orange&label=總觀看人數&query=%24.viewcount&url=https://hackmd.io/Q9gE7WIhSVCzvjCbqerCgg%2Finfo)]()
> [name=AndyChiang][time=Tue, Feb 2, 2021 5:41 PM][color=#00CDAF]
###### tags: `Python`
> 因為Python筆記寫太長了,所以有關模組的部分內容移來此篇說明XD
## Python pip
之前講得不夠清楚,所以補充一下,[中文安裝教學](https://www.maxlist.xyz/2019/07/13/pip-install-python/)。
下載前先檢查有沒有安裝pip:
```
python -m pip --version
```
如果有出現版本,就代表已經安裝過了!
如果沒安裝過,到[pip官網](https://pip.pypa.io/en/stable/installing/)跟著步驟下載。
如果要用pip安裝套件,留意路徑要對!
```
C:\Users\Your Name\AppData\Local\Programs\Python\Python36-32\Scripts>pip install beautifulsoup4
```
## Python NumPy
是一個Python專門處理數學運算的模組,此模組所定義的陣列(ndarray)比起傳統Python的列表快上50倍!
### 引用 Numpy
如果您已經在系統上安裝了Python和PIP,則安裝NumPy非常容易。
```
# CMD
C:\Users\Your Name>pip install numpy
```
安裝完後就可以引用此模組了。
```
import numpy as np
```
習慣上會將 numpy 簡寫成 np。
### 創立 ndarray
使用 array() 函數,參數可以是任意型態的數組,回傳型態為 ndarray。
```
arr = np.array([1, 2, 3, 4, 5])
```
### 陣列維度
#### 一維陣列
```
arr = np.array([1, 2, 3, 4, 5])
```
#### 二維陣列
```
arr = np.array([[1, 2, 3], [4, 5, 6]])
```
#### 三維陣列
```
arr = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])
```
#### 檢查維度
```
d = arr.ndim
```
### 取得陣列元素
和數組差不多,只有二維以上比較特別。
```
arr1[2] # 一維
arr2[1, 5] # 二維
```
### 陣列切割
#### 一維陣列
```
arr = np.array([1, 2, 3, 4, 5, 6, 7])
print(arr[1:5:2])
```
從1切到4(不包括5),2為間隔。
#### 二維陣列
```
arr = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
print(arr[0:2, 1:4])
```
從二維取出0到1的一維陣列,再從一維陣列切出1到3的值,因此回傳值為兩個長度三的一維陣列。
### NumPy 數據型態
* i:整數
* f:浮點數
* S:字串
* 更多...
#### 檢查數據型態
```
arr.dtype
```
#### 轉換數字類型
```
newarr = arr.astype('i')
```
### 複製與預覽(copy/view)
#### 複製
產生副本,更改副本不會影響原始陣列,更改原始陣列也不會影響副本。
```
arr = np.array([1, 2, 3, 4, 5])
x = arr.copy()
```
#### 預覽
產生預覽,更改預覽會影響原始陣列,更改原始陣列也會影響預覽。
```
arr = np.array([1, 2, 3, 4, 5])
x = arr.view()
```
#### 區分複製與預覽
使用 `.base` 檢查:
* 如果是複製,回傳None
* 如果是預覽,回傳原陣列
### 陣列形狀
```
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
print(arr.shape) # (2, 4)
```
#### 重塑形狀
##### 一維轉二維
```
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
newarr = arr.reshape(4, 3) # 4*3的矩陣
```
產生的陣列為**預覽(view)**
##### 一維轉三維
```
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
newarr = arr.reshape(2, 3, 2) # 2*3*2的矩陣
```
##### 任意維轉一維
```
newarr = arr.reshape(-1)
```
-1 是未知數,電腦會自動幫你補上對的數字。
### 走訪陣列
可以用之前的For迴圈:
```
arr = np.array([[1, 2, 3], [4, 5, 6]])
for x in arr:
for y in x:
print(y)
```
但如果碰上高維度的陣列,相對變得麻煩,因此可以使用 `.nditer()` 函數。
```
arr = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
for x in np.nditer(arr):
print(x)
```
### 列舉陣列
使用 `.ndenumerate()` 列舉出所有元素以及它的索引值。
```
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
for idx, x in np.ndenumerate(arr):
print(idx, x)
```
### 連接陣列
使用 `np.concatenate()` 函數,可決定要連接的軸心。
```
arr = np.concatenate((arr1, arr2), axis=1)
```
使用 `np.stack()` 函數,可決定要連接的軸心。
```
arr = np.stack((arr1, arr2), axis=1)
```
### 拆分陣列
使用 `np.array_split()` 函數,參數為要拆分的陣列以及拆成幾份。
```
newarr = np.array_split(arr, 3)
```
### 搜尋陣列
使用 `np.where(condition)` 函數,傳回符合條件的元素的索引值,型態為組合(tuple)。
```
arr = np.array([1, 2, 3, 4, 5, 4, 4])
x = np.where(arr == 4)
```
使用 `np.searchsorted()` 函數,傳回指定值適合插入在陣列的索引值,插入後不會影響原排序。預設從左邊開始搜尋,可改變 `side='right'` 從右邊開始搜尋。
```
arr = np.array([6, 7, 8, 9])
x = np.searchsorted(arr, 7, side='right')
```
### 排序陣列
使用 `np.sort()` 函數,回傳值為排序好的陣列副本。
```
arr = np.array([3, 2, 0, 1])
print(np.sort(arr))
```
### 篩選陣列
在NumPy中,會使用 **布林值陣列** 進行篩選:
```
arr = np.array([41, 42, 43, 44])
x = [True, False, True, False]
newarr = arr[x]
print(newarr) # [41, 43]
```
* 相同索引值對應到 **True** 會留下。
* 對應對 **False** 則會捨棄。
#### 產生布林值陣列
NumPy提供了一個方便的功能,只要 `布林值陣列 = 原陣列condition` ,模組會依照條件自動產生一組布林值陣列。
```
arr = np.array([41, 42, 43, 44])
filter_arr = arr > 42 # [False False True True]
newarr = arr[filter_arr]
```
### NumPy 隨機
從 numpy 中引用 random 模組:
```
from numpy import random
```
#### 產生隨機整數
```
x = random.randint(100) # 產生0到100的隨機整數
```
#### 產生隨機整數陣列
size 參數可決定陣列大小。
```
x=random.randint(100, size=(3, 5)) # 產生3*5隨機整數陣列
```
#### 產生隨機浮點數
```
x = random.rand() # 產生0到1之間的隨機浮點數
```
#### 產生隨機浮點數陣列
```
x = random.rand(3, 5) # 產生3*5隨機浮點數陣列
```
#### 隨機抽取
```
x = random.choice([3, 5, 7, 9]) # 從3、5、7、9中隨機擇一
```
#### 產生隨機抽取陣列
size 參數可決定陣列大小。
```
x = random.choice([3, 5, 7, 9], size=(3, 5)) # 由3、5、7、9隨機組成的3*5陣列
```
#### 機率分配
p 陣列代表機率,機率值從0~1,0是完全不會出現,1是一定會出現,機率總和記得要為1。
```
x = random.choice([3, 5, 7, 9], p=[0.1, 0.3, 0.6, 0.0], size=(100))
```
#### 隨機打散陣列
使用 `shuffle()` 隨機打散陣列,原陣列會改變。
```
arr = np.array([1, 2, 3, 4, 5])
random.shuffle(arr)
print(arr)
```
使用 `permutation()` 隨機打散陣列,原陣列不會改變。
```
arr = np.array([1, 2, 3, 4, 5])
print(random.permutation(arr))
```
#### 機率分布圖
有太多分布了,而且不是那麼重要,有需要可以查底下連結:[更多分布](https://www.w3schools.com/python/numpy_random_normal.asp)
可以搭配 Matplotlib 印出分布圖,那部分之後再說明。
### NumPy ufuncs
NumPy ufuncs 實作出像量化,因此會比正常的運算還要更快。
#### 自定義 ufuncs
使用 `frompyfunc(<函數名稱>, <輸入參數(數組)的數量>, <輸出數組的數量>)`,如下:
```
def myadd(x, y):
return x+y
myadd = np.frompyfunc(myadd, 2, 1)
print(myadd([1, 2, 3, 4], [5, 6, 7, 8]))
```
#### 基礎運算
當然原先Python提供的加減乘除也可以用,但用 ufuncs 會跑得更快!
##### 加法
```
newarr = np.add(arr1, arr2)
```
##### 減法
```
newarr = np.subtract(arr1, arr2)
```
##### 乘法
```
newarr = np.multiply(arr1, arr2)
```
##### 除法
```
newarr = np.divide(arr1, arr2)
```
ps. 無法整除的會返回浮點數。
##### 次方
```
newarr = np.power(arr1, arr2)
```
##### 餘數
```
newarr = np.mod(arr1, arr2)
```
```
newarr = np.remainder(arr1, arr2)
```
##### 絕對值
```
newarr = np.absolute(arr)
```
#### 捨入小數
##### Truncation
直接刪除小數後的整數部分。
```
arr = np.trunc([-3.1666, 3.6667])
```
##### 四捨五入
第二個參數可指定要四捨五入到第幾位。
```
arr = np.around(3.1666, 2)
```
##### 無條件捨去
```
arr = np.floor([-3.1666, 3.6667])
```
##### 無條件進位
```
arr = np.ceil([-3.1666, 3.6667])
```
#### 對數
##### 取log2
```
np.log2(arr)
```
##### 取log10
```
np.log10(arr)
```
##### 取log,以e(自然對數)為基底
```
np.log(arr)
```
#### 取總和(sum)
```
arr1 = np.array([1, 2, 3])
arr2 = np.array([1, 2, 3])
newarr = np.sum([arr1, arr2])
print(newarr) # (1+2+3)+(1+2+3)=12
```
#### 取總乘積(product)
```
arr = np.array([1, 2, 3, 4])
x = np.prod(arr)
print(x) # 1*2*3*4=24
```
#### 取項目差(difference)
```
arr = np.array([10, 15, 25, 5])
newarr = np.diff(arr)
print(newarr) # [15-10, 25-15, 5-25] = [5, 10, -20]
```
#### 取最小公倍數(LCM)
##### 數字
```
num1 = 4
num2 = 6
x = np.lcm(num1, num2) # 12
```
##### 陣列
```
arr = np.array([3, 6, 9])
x = np.lcm.reduce(arr) # 18
```
#### 取最大公因數
##### 數字
```
num1 = 6
num2 = 9
x = np.gcd(num1, num2) # 3
```
##### 陣列
```
arr = np.array([20, 8, 32, 36, 16])
x = np.gcd.reduce(arr) # 4
```
#### 三角函數
```
x = np.sin(np.pi/2)
x = np.cos(np.pi/2)
x = np.tan(np.pi/2)
```
注意到三角函數的參數都是弧度,因此必須先把角度(degree)換成弧度(radian):
```
x = np.deg2rad(90)
```
反過來也可以:
```
x = np.rad2deg(np.pi/2)
```
給sin、cos、tan值反求角度:
```
x = np.arcsin(1.0)
x = np.arccos(1.0)
x = np.arctan(1.0)
```
#### 集合(set)
使用 `unique()` 將任意陣列轉為集合,重複項將刪除。
```
arr = np.array([1, 1, 1, 2, 3, 4, 5, 5, 6, 7])
x = np.unique(arr) # [1 2 3 4 5 6 7]
```
關於集合的操作前面講過了,這邊只放指令
* `newarr = np.union1d(arr1, arr2)`:聯集(union)
* `newarr = np.intersect1d(arr1, arr2, assume_unique=True)`:交集(intersection)
* `newarr = np.setdiff1d(set1, set2, assume_unique=True)`:差(difference)
* `newarr = np.setxor1d(set1, set2, assume_unique=True)`:對稱差(symmetric difference)
* `assume_unique=True`:此屬性可以加速運算,寫就對了!
## Python Matplotlib
是專門用來繪製數據圖的Python模組。
### 引用 Matplotlib
如果您已經在系統上安裝了 Python 和 PIP,則 Matplotlib 的安裝非常簡單。
```
# CMD
C:\Users\Your Name>pip install matplotlib
```
大多數 Matplotlib 實用程序位於 pyplot 子模組下,並且通常以 plt 別名導入:
```
import matplotlib.pyplot as plt
```
### 印出圖表
```
plt.show()
```
### 繪製座標圖
使用 `plot()` 函數在xy座標上繪製點或線。
```
xpoints = np.array([1, 8])
ypoints = np.array([3, 10])
plt.plot(xpoints, ypoints)
```
plot() 第一個參數代表x軸上的座標,第二個參數代表y軸上的座標。
如果只給一組參數,函數會預設x軸座標為 [0,1,2,3...]
#### 只有點
參數多加上 "o"
```
plt.plot(xpoints, ypoints, 'o')
```
#### 格式化樣式(fmt)
`marker|line|color` 依序為 `端點形狀|線樣式|點和線的顏色`
```
plt.plot(ypoints, 'o:r') # 原點|點狀虛線|紅色
```
樣式有很多,可以去以下連結找:[Matplotlib 標記格式](https://www.w3schools.com/python/matplotlib_markers.asp)
### 端點格式
#### 端點大小
可修改參數 markersize(或ms) 設定端點大小。
```
plt.plot(ypoints, marker = 'o', ms = 20)
```
#### 端點顏色
可修改參數 markeredgecolor(或mec) 設定端點邊緣顏色。
```
plt.plot(ypoints, marker = 'o', ms = 20, mec = 'r')
```
可修改參數 markerfacecolor(或mfc) 設定端點邊緣內顏色。
```
plt.plot(ypoints, marker = 'o', ms = 20, mfc = 'r')
```
顏色可使用十六進位制色碼或指定顏色名稱。
### 線格式
#### 線樣式
可修改參數 linestyle(或ls) 設定線的樣式。
```
plt.plot(ypoints, linestyle = 'dotted')
```
#### 線顏色
可修改參數 color(或c) 設定線的顏色。
```
plt.plot(ypoints, color = 'r')
```
顏色可使用十六進位制色碼或指定顏色名稱。
#### 線寬
可修改參數 linewidth(或lw) 設定線的寬度。
```
plt.plot(ypoints, linewidth = '20.5')
```
### 標籤與標題
#### 設定標籤
```
plt.xlabel("This is X axis")
plt.ylabel("This is Y axis")
```
#### 設定標題
```
plt.title("This is title")
```
可使用 `loc` 參數來修改標題位置:
```
plt.title("This is title", loc = 'left')
```
* center:置中(預設值)
* left:靠左
* right:靠右
#### 更改標籤樣式
```
font1 = {'family':'serif','color':'blue','size':20}
font2 = {'family':'serif','color':'red','size':15}
plt.title("This is title", fontdict = font1)
plt.xlabel("This is X axis", fontdict = font2)
plt.ylabel("This is Y axis", fontdict = font2)
```
### 網格線(grid line)
可修改參數 `axis` 設定網格線類型:
```
plt.grid(axis = 'x')
```
* x
* y
* both(預設值)
網格線也可以更改格式,方法和線一樣。
### 多圖
#### 顯示多個圖
使用 `subplots()` ,一口氣顯示多個圖。
```
#plot 1:
x = np.array([0, 1, 2, 3])
y = np.array([3, 8, 1, 10])
plt.subplot(1, 2, 1)
plt.plot(x,y)
#plot 2:
x = np.array([0, 1, 2, 3])
y = np.array([10, 20, 30, 40])
plt.subplot(1, 2, 2)
plt.plot(x,y)
```
參數代表:`subplot(多圖有幾列, 有幾行, 這是第幾張圖)`
#### 主標籤
使用 `suptitle()` 顯示整張多圖的主標籤。
```
plt.suptitle("MY SHOP")
```
### 散點圖
#### 建立散點圖
使用 `scatter()` 必須有兩個長度相同的陣列,第一個當x軸座標,第二個當y軸座標。
```
x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6])
y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86])
plt.scatter(x, y)
plt.show()
```
#### 設定散點圖顏色
可修改參數 color(或c) 設定散點圖的顏色。
```
plt.scatter(x, y, color = '#88c999')
plt.scatter(x, y, color = 'hotpink')
```
#### 色卡(ColorMap)
使用 cmap 參數設定色卡,另外必須有 color 陣列標記色卡百分比(0~100),長度必須與散點圖一致,參數限定使用 `c`。
```
x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6])
y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86])
colors = np.array([0, 10, 20, 30, 40, 45, 50, 55, 60, 70, 80, 90, 100])
plt.scatter(x, y, c=colors, cmap='viridis')
```
使用 `plt.colorbar()` 更可以將色卡印在散點圖旁邊。
[更多色卡](https://www.w3schools.com/python/matplotlib_scatter.asp)
#### 設定散點圖大小
可修改參數 s 設定散點圖的大小,如果想讓每個點的大小都不一樣,請給定一個長度和散點圖一樣的陣列,陣列內的值為點的大小。
```
x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6])
y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86])
sizes = np.array([20,50,100,200,500,1000,60,90,10,300,600,800,75])
plt.scatter(x, y, s=sizes)
```
#### 設定散點圖透明度
可修改參數 alpha 設定散點的透明度,值為(0~1),數字越小越透明。
```
plt.scatter(x, y, alpha=0.5)
```
### 直條圖
#### 建立直條圖
使用 `bar()` 函數建立直條圖。
```
x = np.array(["A", "B", "C", "D"])
y = np.array([3, 8, 1, 10])
plt.bar(x,y)
```
使用 `barh()` 函數建立直條圖(橫式)。
```
x = np.array(["A", "B", "C", "D"])
y = np.array([3, 8, 1, 10])
plt.barh(x,y)
```
#### 設定直條圖顏色
改顏色方法和散點圖一樣。
#### 設定直條寬度(或高度?)
使用 width 參數設定直條寬度(預設為0.8),但如果是橫式則使用 height 參數(預設也為0.8)。
### 直方圖
使用 `hist()` 函數建立直方圖,常用來表示高斯分布。
```
x = np.random.normal(170, 10, 250) # 產生高斯分布
plt.hist(x)
```
### 圓餅圖
使用 `pie()` 函數建立圓餅圖,值加起來必須為100。
```
y = np.array([35, 25, 25, 15])
plt.pie(y)
```
#### 加入標籤
使用 labels 參數設定圓餅區塊標籤,通常指向一個標籤陣列。
```
y = np.array([35, 25, 25, 15])
mylabels = ["Apples", "Bananas", "Cherries", "Dates"]
plt.pie(y, labels = mylabels)
```
#### 起始角度
使用 startangle 參數設定圓餅圖起始角度,預設為0。
![](https://i.imgur.com/HOHF8ru.png =60%x)
```
y = np.array([35, 25, 25, 15])
mylabels = ["Apples", "Bananas", "Cherries", "Dates"]
plt.pie(y, labels = mylabels, startangle = 90)
```
#### 凸顯效果(爆炸效果!?)
使用 explode 參數設定圓餅圖區塊的凸顯效果,數值代表離圓心的距離,預設為0。
```
y = np.array([35, 25, 25, 15])
mylabels = ["Apples", "Bananas", "Cherries", "Dates"]
myexplode = [0.2, 0, 0, 0]
plt.pie(y, labels = mylabels, explode = myexplode)
```
#### 陰影
使用 shadows 參數設定圓餅圖是否有陰影,預設為False。
```
plt.pie(y, labels = mylabels, explode = myexplode, shadow = True)
```
#### 設定顏色
改顏色方法和散點圖一樣。
#### 圖示說明
使用 `legend()` 函數,加入圖示說明在圖上。
另外,使用 title 屬性設定圖示說明的標題。
```
y = np.array([35, 25, 25, 15])
mylabels = ["Apples", "Bananas", "Cherries", "Dates"]
plt.pie(y, labels = mylabels)
plt.legend(title = "Four Fruits:")
```
## Python SciPy
在 Python 中專門處理科學記號或運算的模組。
### 引用 SciPy
如果您已經在系統上安裝了 Python 和 PIP,則 SciPy 的安裝非常簡單。
```
# CMD
pip install scipy
```
安裝完即可直接引用。
```
import scipy
```
可以印出 `scipy.__version__` 檢查是否安裝成功。
### SciPy 常數
常數位於 scipy 底下的 constants 子模組中
```
from scipy import constants
```
常數有非常多,大致分類成這樣:
* Metric,公制,單位為公尺(meter),例如:kilo
* Binary,二進位,單位為bytes
* Mass,重量,單位為公斤(kg)
* Angle,角度,單位為弧度(radians)
* Time,時間,單位為秒(seconds)
* Length,長度,單位為公尺(meter)
* Pressure,壓力,單位為帕斯卡(pascals)
* Area,面積,單位為平方公尺(m^2^)
* Volume,體積,單位為立方公尺(m^3^)
* Speed,速度,單位為每秒幾公尺(meters per second)
* Temperature,溫度,單位為凱式溫標(K)
* Energy,能量,單位為焦耳(J)
* Power,功率,單位為瓦特(W)
* Force,力,單位為牛頓(newton)
* [更多常數...](https://www.w3schools.com/python/scipy_constants.asp)
### SciPy 優化
#### 求方程式的解
使用 `scipy.optimze.root` 可求得該方程式的解,第一個參數為方程式,第二個參數為解的猜測值。
```
from scipy.optimize import root
from math import cos
def eqn(x):
return x + cos(x)
myroot = root(eqn, 0)
print(myroot.x) # -0.73908513
```
#### 簡化方程式
使用 `scipy.optimize.minimize()` 可簡化方程式,第一個參數為方程式,第二個參數為解的猜測值,第三個參數為簡化方法。
```
from scipy.optimize import minimize
def eqn(x):
return x**2 + x + 2
mymin = minimize(eqn, 0, method='BFGS')
print(mymin)
```
### SciPy 稀疏陣列(sparse data)
有 CSC 和 CSR 兩種處理方式,範例都使用 CSR。
#### 建立 CSR 陣列
必須引用 `scipy.sparse.csr_matrix()` 函數,將一般陣列轉為 CSR 陣列。
```
arr = np.array([0, 0, 0, 0, 0, 1, 1, 0, 2])
print(csr_matrix(arr))
# (0, 5) 1
# (0, 6) 1
# (0, 8) 2
```
#### 非零值
```
arr = np.array([[0, 0, 0], [0, 0, 1], [1, 0, 2]])
print(csr_matrix(arr).data)
```
#### 非零值數量
```
arr = np.array([[0, 0, 0], [0, 0, 1], [1, 0, 2]])
print(csr_matrix(arr).count_nonzero())
```
### Scipy 圖(Graphs)
使用前必須引用 `scipy.sparse.csgraph` 模組。
#### 鄰接矩陣(Adjacency Matrix)
就是資料結構的 Adjacency Matrix,通常是 CSR 陣列。
#### 連接組件(Connected Components)
Connected Components 指的是有連接的最大子圖(Subgragh)。
```
import numpy as np
from scipy.sparse.csgraph import connected_components
from scipy.sparse import csr_matrix
arr = np.array([
[0, 1, 2],
[1, 0, 0],
[2, 0, 0]
])
newarr = csr_matrix(arr)
print(connected_components(newarr))
```
#### 走訪圖的演算法
##### Dijkstra 演算法
```
import numpy as np
from scipy.sparse.csgraph import dijkstra
from scipy.sparse import csr_matrix
arr = np.array([
[0, 1, 2],
[1, 0, 0],
[2, 0, 0]
])
newarr = csr_matrix(arr)
print(dijkstra(newarr, return_predecessors=True, indices=0))
```
##### Floyd Warshall 演算法
```
import numpy as np
from scipy.sparse.csgraph import floyd_warshall
from scipy.sparse import csr_matrix
arr = np.array([
[0, 1, 2],
[1, 0, 0],
[2, 0, 0]
])
newarr = csr_matrix(arr)
print(floyd_warshall(newarr, return_predecessors=True))
```
##### Bellman Ford 演算法
一樣是走訪圖,但此演算法可以應付邊權重為負的情況:
```
import numpy as np
from scipy.sparse.csgraph import bellman_ford
from scipy.sparse import csr_matrix
arr = np.array([
[0, -1, 2],
[1, 0, 0],
[2, 0, 0]
])
newarr = csr_matrix(arr)
print(bellman_ford(newarr, return_predecessors=True, indices=0))
```
##### 深度優先演算法(DFS)
第一個參數為圖,第二個參數為起始點。
```
import numpy as np
from scipy.sparse.csgraph import depth_first_order
from scipy.sparse import csr_matrix
arr = np.array([
[0, 1, 0, 1],
[1, 1, 1, 1],
[2, 1, 1, 0],
[0, 1, 0, 1]
])
newarr = csr_matrix(arr)
print(depth_first_order(newarr, 1))
```
##### 廣度優先演算法(BFS)
```
import numpy as np
from scipy.sparse.csgraph import breadth_first_order
from scipy.sparse import csr_matrix
arr = np.array([
[0, 1, 0, 1],
[1, 1, 1, 1],
[2, 1, 1, 0],
[0, 1, 0, 1]
])
newarr = csr_matrix(arr)
print(breadth_first_order(newarr, 1))
```
### SciPy Matlab
必須引用 `scipy.io` 模組。
#### 匯出 Matlab 格式
有三個參數:第一個參數是檔名,第二個參數是包含數組的字典,第三個參數是布林值,是否要壓縮(預設為False)。
```
from scipy import io
import numpy as np
arr = np.arange(10)
io.savemat('arr.mat', {"vec": arr})
```
#### 引入 Matlab 格式
```
mydata = io.loadmat('arr.mat')
```
> SciPy 之後的東西太難了,看不懂QQ~,就只寫到這裡。以後學會了再補寫(?)
> [連結](https://www.w3schools.com/python/scipy_interpolation.asp)
## Python Pandas
### 引用Pandas
使用pip安裝用以下指令:
```
pip install pandas
```
在Python程式中引用:
```
import pandas as pd
```
### 建立Series
在`Series()`中放入列表型態,轉為Series型態。
```python=
s1 = pd.Series([2, 1, 7, 4])
print(s1)
```
執行結果:
```
0 2
1 1
2 7
3 4
dtype: int64
```
索引值預設為0, 1, 2...,也可以用`index=`設定索引值。
```python=
s2 = pd.Series([20, 10, 70, 40], index=["小明", "小美", "小王", "小智"])
print(s2)
```
執行結果:
```
小明 20
小美 10
小王 70
小智 40
dtype: int64
```
### 建立DataFrame
```python=
data = {
'name': ['王小郭', '張小華', '廖丁丁', '丁小光'],
'email': ['min@gmail.com', 'hchang@gmail.com', 'laioding@gmail.com', 'hsulight@gmail.com'],
'grades': [60, 77, 92, 43]
}
df = pd.DataFrame(data, index=["A", "B", "C", "D"])
```
字典中key是column欄位的名稱,value則是一個iterable,值為欄位的數值。
index預設為0, 1, 2,...,可使用index=list改變index內容。
### 印出DataFrame資料
#### 印出全部資料
```
print(df)
```
#### 印出前n筆資料
```
print(df.head(n))
```
#### 印出後n筆資料
```
print(df.tail(n))
```
#### 印出資料型態等資訊
```
print(df.info())
```
#### 印出統計資訊
```
print(df.describe())
```
#### 印出index資訊
```
print(df.index)
```
#### 印出欄位資訊
```
print(df.columns)
```
### 篩選資料
#### `df["屬性名稱"]`
```
print(df["num"])
```
#### df."屬性名稱"
```
print(df.num)
```
#### `df.iloc[row, col]`
iloc參數為索引值(整數)
```
print(df.iloc[0, 1]) # 第1列/第2行
print(df.iloc[3, :]) # 第3列全部
print(df.iloc[:, 1]) # 第1行全部
```
#### `df.loc[row, col]`
loc參數為欄位名稱(字串)
```
print(df.iloc["num"])
```
#### loc/iloc + boolean array
篩選num介於11到19間的列。
```
out_df = df.iloc[[(x > 10 and x < 20) for x in df["num"]]]
print(out_df)
```
### 排序資料
#### 依照index排序
* axis = 0,以列排序;axis = 1,以欄排序。
* ascending = True,升冪;ascending = False,降冪。
```
print(df.sort_index())
```
#### 依照欄位數值排序
* by = "col",根據col欄位排序。
```
print(df.sort_values(by="num"))
```
### 重新命名欄位
```
rename_dic = {"col 1": "x", "col 2": "10x"}
df = df.rename(rename_dic, axis=1)
```
輸入dict為要更改的名稱,axis=0是row,axis=1才是column。
### 刪除欄位
第一個參數為刪除之欄位名稱。
```
df.drop(['grades'], axis=1)
```
### 處理 NA/NaN 值
當讀進的資料有遺漏項時就會出會NaN值。
#### 填補空值
```
fill_df1 = df.fillna(0) # 全部NaN填補0
print(fill_df1)
print("-----")
fill_df2 = df.fillna({"shop name": "None", "market size": 0}) # 依照欄位填補None或0
print(fill_df2)
print("-----")
```
執行結果:
```
shop id shop name maket size
0 1 Wal mart 3000000.0
1 2 Costco 2000000.0
2 3 0 1500000.0
3 4 Pchome 300000.0
4 5 Yahoo 0.0
-----
shop id shop name maket size
0 1 Wal mart 3000000.0
1 2 Costco 2000000.0
2 3 None 1500000.0
3 4 Pchome 300000.0
4 5 Yahoo NaN
-----
```
#### 刪除空值
```
drop_df = df.dropna() # 刪除空值的整行
print(drop_df)
print("-----")
```
執行結果:
```
shop id shop name maket size
0 1 Wal mart 3000000.0
1 2 Costco 2000000.0
3 4 Pchome 300000.0
-----
```
### 列合併和行合併
#### concat(列合併)
```python=
data_1 = {
'name': ['王小郭', '張小華', '廖丁丁', '丁小光'],
'email': ['min@gmail.com', 'hchang@gmail.com', 'laioding@gmail.com', 'hsulight@gmail.com'],
'grades': [60, 77, 92, 43]
}
data_2 = {
'name': ['黃明明', '汪新新', '鮑呱呱', '江組組'],
'email': ['ww@gmail.com', 'cc@gmail.com', 'bb@gmail.com', 'ee@gmail.com'],
'grades': [70, 17, 32, 43]
}
df_1 = pd.DataFrame(data_1)
df_2 = pd.DataFrame(data_2)
df_3 = pd.concat([df_1, df_2])
print(df_3)
```
執行結果:
```
name email grades
0 王小郭 min@gmail.com 60
1 張小華 hchang@gmail.com 77
2 廖丁丁 laioding@gmail.com 92
3 丁小光 hsulight@gmail.com 43
0 黃明明 ww@gmail.com 70
1 汪新新 cc@gmail.com 17
2 鮑呱呱 bb@gmail.com 32
3 江組組 ee@gmail.com 43
```
如果是 `pd.concat([df_1, df_2], ignore_index=True)`,則index會合併後重新排列。
執行結果:
```
name email grades
0 王小郭 min@gmail.com 60
1 張小華 hchang@gmail.com 77
2 廖丁丁 laioding@gmail.com 92
3 丁小光 hsulight@gmail.com 43
4 黃明明 ww@gmail.com 70
5 汪新新 cc@gmail.com 17
6 鮑呱呱 bb@gmail.com 32
7 江組組 ee@gmail.com 43
```
#### merge(行合併)
```python=
data_1 = {
'name': ['王小郭', '張小華', '廖丁丁', '丁小光'],
'email': ['min@gmail.com', 'hchang@gmail.com', 'laioding@gmail.com', 'hsulight@gmail.com'],
'grades': [60, 77, 92, 43]
}
data_2 = {
'name': ['王小郭', '張小華', '廖丁丁', '丁小光'],
'age': [19, 20, 32, 10]
}
df_1 = pd.DataFrame(data_1)
df_2 = pd.DataFrame(data_2)
df_3 = pd.merge(df_1, df_2)
print(df_3)
```
執行結果:
```
name email grades age
0 王小郭 min@gmail.com 60 19
1 張小華 hchang@gmail.com 77 20
2 廖丁丁 laioding@gmail.com 92 32
3 丁小光 hsulight@gmail.com 43 10
```
### 匯出資料
Pandas要匯出資料非常簡單,常見的檔案支援格式有這些,參數輸入檔案名稱即可。
```python=
data = {
'name': ['王小郭', '張小華', '廖丁丁', '丁小光'],
'email': ['min@gmail.com', 'hchang@gmail.com', 'laioding@gmail.com', 'hsulight@gmail.com'],
'grades': [60, 77, 92, 43]
}
df = pd.DataFrame(data)
df.to_csv("data.csv")
df.to_excel("data.xlsx")
df.to_json("data.json")
df.to_html("data.html")
```
### 匯入檔案
參數一樣輸入檔案名稱即可,如果資料有中文字要特別注意編碼問題,加上`encoding="utf-8"`,否則會出現亂碼。
```python=
df1 = pd.read_csv("data.csv")
df2 = pd.read_excel("data.xlsx")
df3 = pd.read_json("data.json")
df4 = pd.read_html("data.html")
print(df1)
print(df2)
print(df3)
print(df4)
```
### 測試用DataFrame
#### 隨機產生
```
pd.util.testing.makeDataFrame()
```
#### 不同型態
```
pd.util.testing.makeMixedDataFrame()
```
### 參考
* [簡明 Python Pandas 入門教學](https://blog.techbridge.cc/2020/09/21/python-pandas-zen-tutorial/)
* [[Python] Pandas 基礎教學](https://oranwind.org/python-pandas-ji-chu-jiao-xue/)
* [資料科學家的 pandas 實戰手冊:掌握 40 個實用數據技巧](https://leemeng.tw/practical-pandas-tutorial-for-aspiring-data-scientists.html)
### 實用工具
* [tqdm:了解你的數據處理進度](https://github.com/tqdm/tqdm)
* [swifter:加速你的數據處理](https://github.com/jmcarpenter2/swifter)
* [qgrid:即時排序、篩選及編輯你的 DataFrame](https://github.com/quantopian/qgrid)
* [pandas-profiling:你的一鍵 EDA 神器](https://github.com/pandas-profiling/pandas-profiling)
## 相關文章
[Python 基礎技術整理](/3L8iXhnVR2uFC_4iJs-n3g)
## 參考網站
* [W3School Python教學](https://www.w3schools.com/python/default.asp)
* [Python 官方document](https://docs.python.org/zh-tw/3/tutorial/index.html)