---
# System prepended metadata

title: 巨匠Python - 機器學習
tags: [Data]

---

# 巨匠Python - 機器學習
###### tags: `資料分析`

# 第一章、機器學習主要概念

![](https://i.imgur.com/SIzbCFA.png)

[Scikit Learn - 機器學習概念地圖](https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html)



## （一） 常用資料型態轉換工具
```
import  pandas as pd
import  numpy as np

# 【建立二維】 ndarray => ndarray
numpy_2d = np.arange(15).reshape(3,5)

# 【建立二維】 ndarray => DataFrame
df = pd.DataFrame(
    numpy_2d,
    index=['name1','name2','name3'],
    columns=['y','m','d','earn','cost'])

# 【取出一維資料】 DataFrame => Series

# 取column
print(df.earn)
print(df['earn'])

# 取row
print(df.loc['name1',:]) # 以label取值
print(df.iloc[0,:]) # 以index取值


# 【建立二維】 Series => DataFrame
df2 = pd.DataFrame({'earn':df.earn,'cost':df.cost})

# 【取出一維資料】 ndarray => ndarray
numpy_1d = numpy_2d[:,3]
```
## （二）機器學習 Q&A
**Q1. 資料適合哪一種機器學習方式?**
* 樣本數大於50才進行機器學習
* 預測類別
	* 已貼標籤 => 監督式學習：分類
	* 未貼標籤 => 非監督式學習：分群
* 預測數量
	* 監督式學習：迴歸

**Q2. 機器學習的三種類型與各自目標**
* 監督式學習(迴歸/分類)： 標記資料、直接回饋、預測未來
* 非監督式學習(分群)：沒有標記沒有回饋、找到隱藏的結構
* 強化式學習：決策過程、獎勵系統、學習一系列的行動

**Q3. 迴歸與分類差異**
* 迴歸: 預測連續輸出的結果，預估數值
* 分類: 預測離散輸出的結果，預估分類結果

## （三） joblib 迴歸模型儲存與讀取

`!pip install joblib`

```
# 01. 儲存模型
import joblib
joblib.dump(model,'drink_sales.pkl')
# 會儲存在暫存資料夾中

# 02. 連結google drive
from google.colab import drive
drive.mount('/content/drive',force_remount=True)

# 03. 載入模型
import joblib
model=joblib.load('/content/drive/MyDrive/%path%')
```


# 第一章、資料預處理 Data Processing

:::danger
**安裝 [Scikit-learn 機器學習工具包](https://scikit-learn.org/stable/)**
`!pip install scikit-learn`
:::
:::warning

* **[訓練組、受試組拆分模型](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html)**
`from sklearn.model_selection import train_test_split`
:::
```
# ----- 定義變量 (接受二維資料)----- #

# Explanatory Variable(s) or Feature(s) (自變量/獨立變數/特徵)
X = pd.DataFrame(new_films, columns=['USD_Production_Budget'])

# Response Variable or Target (應變量/控制變數/目標)
y = pd.DataFrame(new_films, columns=['USD_Worldwide_Gross']) 


# ----- 拆解訓練組、受試組 ----- #

features = data.iloc[:, :-1]
target = data.PRICE

X_train, X_test, y_train, y_test = train_test_split(
    features, # 自變數
    target, # 應變數
    test_size=0.2, # test數組的大小 
    random_state=10) # 隨機因子
```
    
# 第二章、迴歸 Regression
## 一、簡單線性迴歸 Simple Linear Regression

:::warning

* **[線性回歸模型](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html)**
`from sklearn.linear_model import LinearRegression`

* **誤差值分析**
```
from sklearn.metrics import r2_score
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import median_absolute_error
from sklearn.metrics import mean_squared_error
```
:::

**線性回歸**
![](https://i.imgur.com/nN51sTq.png)

```
# ----- 00. 建立模型 ----- #

regression = LinearRegression()


# ----- 01. 模型訓練 ----- #

# Find the best-fit line (需使用二維資料)
regression.fit(X, y)

# 截距 Θ(0) intercept
print(regression.intercept_)

# 斜率 Θ(1) coefficient
print(regression.coef_)


# ----- 02. 模型預測 ----- #

predicted_values = regression.predict(X_train)
```

**模型效度判斷**

```
# ----- Method1: R平方 (R-Squared) ----- #

# 又稱為判定係數(coefficient of determination)
# 衡量回歸模型的表現 (可以解釋的變數比例)
# 若 R-Squared > 0.5 即表示回歸模型具參考價值

regression.score(X, y)


# ----- Method2: 誤差值分析 ----- #

predicted_values = regression.predict(X_train)
residuals = (y_train - predicted_values)

# 求誤差值平均、偏態係數，越趨近於0，效度越高

resid_mean = round(residuals.mean(), 2)
resid_skew = round(residuals.skew(), 2)

sns.displot(residuals, 
            aspect=2,
            kde=True, 
            color='#00796b')

plt.title(f'Residuals Skew ({resid_skew}) Mean ({resid_mean})')
plt.show()


# ----- Method3:其他誤差值計算 ----- #

from sklearn.metrics import r2_score
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import median_absolute_error
from sklearn.metrics import mean_squared_error

# 測試組 y_test vs. 預測組 y_pred 

mean_squared_error(y_test,y_pred)  # 平均平方誤差/均方誤差 MSE
np.sqrt(mean_squared_error(y_test,y_pred))  # 根號平均平方誤差/均方根誤差 RMSE
mean_absolute_error(y_test,y_pred)  # 平均絕對值誤差 MAE
median_absolute_error(y_test,y_pred)  # 中位絕對值誤差
r2_score(y_test,y_pred)  # r2_score

```
![](https://i.imgur.com/M45BJqV.png)


:::spoiler
**Q&A：sklearn vs. numpy.polyfit()之差異**


* 相同部分
sklearn經訓練之後會產生模型，這個模型可以拿來進行預測。
numpy部分亦可以將數值資料帶入方程式中，可以產生結果。
* 不同部分
sklearn經訓練之後的模型，可以儲存模型，以供之後使用。
numpy只能儲存數值，不能儲存方程式。
sklearn經訓練之後的模型，可以進行驗證，評估模型好壞。
numpy只有方程式，若要驗證得自己手動方式寫語法處理。

:::


# 第三章、分類 Classification

:::warning

* **sklearn 內建資料集**
`from sklearn import datasets`
* **[感知器學習 Perceptron Learning Algorithm(PLA)](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Perceptron.html)**
`from sklearn.linear_model import Perceptron`
    * 模型函數：
        * n_iter：訓練次數，整數
        * eta：學習率，為浮點數，介於0到1之間
    * 模型範例：`model = Perceptron(max_iter=40, eta0=0.1)`
* **[羅吉斯迴歸 Logistic Regression](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html)**
`from sklearn.linear_model import LogisticRegression`
    * 模型函數：
        * solver：Algorithm to use in the optimization problem.
            * `liblinear`：線性－線性分類
            * `newton-cg`：平面/二階－牛頓方法，最嚴謹，但速度慢
            * `lbfgs`：平面/二階－線性分類，有更動才會載入，速度較牛頓快
            * `sag`：平面/一階－梯度下降(依前個數值)
            * `saga`：平面/一階－梯度下降的擴展，加入L1正規化，避免過度擬合
    * 模型範例：`model = LogisticRegression(solver='liblinear')`
* **[最近鄰分類 K-Nearest Neighbors(K-NN)](https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html)**
`from sklearn.neighbors import KNeighborsClassifier`
    * 模型函數：
        * n_neighbors：最近鄰數量，預設為5
    * 模型範例：`model = KNeighborsClassifier(n_neighbors=3)
* **[支援向量機 Support Vector Machine (SVM)](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html)**
`from sklearn.svm import SVC`
    * 模型函數：
        * kernel：Specifies the kernel type to be used in the algorithm. 
            * `linear`：線性
            * `poly`：非線性，另可加入degree參數增加模型複雜度，規劃n次方的計算
            * `rdf`：非線性，代表高斯轉換
        * C：控制分類錯誤的懲罰，控制模型複雜度
        * gamma：投射範圍/作用範圍的倒數
* **評估：準確值/分類報告/混淆矩陣**
```
from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
```
:::


## 一、線性－感知器學習 Perceptron Learning Algorithm(PLA)
![](https://i.imgur.com/qDPkcXW.png)

1. 最早的神經網路模型，由突觸接收(input)，若加權(w)後大於閥值(threshold)，則判斷為(A)，否則為(B)
2. 只能判斷資料為A/B
3. 成立前提為：資料具線性可分性(Linear separability)，否則演算法不會停止
4. 因條件嚴苛，故改良為：pocket-PLA
    * 選出誤差最低的分類線即停止
    * 因額外需儲存與比較，運作速度較慢


**Sklearn - Iris資料集**
```
# ----- 00. 載入鳶嘴花資料集 ----- #

import pandas as pd
from sklearn import datasets

iris = datasets.load_iris()


# ----- 01. 資料探索 ----- #

# 資料集屬性
print(iris.keys())
# 資料集詳細描述
print(iris.DESCR)

# 資料型態
print(iris.__class__)
# 資料筆數 (共150筆樣本)
print(len(iris.data))

# 特徵名稱 (花萼長度、寬度；花瓣長度、寬度)
print(iris.feature_names)
# 目標名稱 (3個品種)
print(iris.target_names)
# 分類的目標
print(iris.target)

'''
資料型態
<class 'sklearn.utils.Bunch'>

資料特徵名稱
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

資料目標名稱 iris.target_names
['setosa' 'versicolor' 'virginica']

資料目標 iris.target
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]
'''


# ----- 02. 以DataFrame方式呈現 ----- #

# 比對轉換，表示iris.target的意義
species = [iris.target_names[x] for x in iris.target]

# 將資料轉換為DataFrame
data = pd.DataFrame(iris.data,columns=['sepal length', 'sepal width', 'petal length', 'petal width'])
data['species'] = species
data['level'] = iris.target


# ----- 03. 拆解訓練組與測試組 ----- #

from sklearn.model_selection import train_test_split

features = data.iloc[:, 1:5]
target = data.iloc[:, -1]

X_train, X_test, y_train, y_test = train_test_split(
    features, # 自變數
    target, # 應變數
    test_size=0.3, # test數組的大小 
    # random_state=10  # 隨機因子
    )
```


**感知器分類**
* 注意若train的資料過多，可能導致過度擬合
```
from sklearn.linear_model import Perceptron


# ----- 00. 訓練分類模型 ----- #
# n_iter：訓練次數，整數
# eta :學習率，為浮點數，介於0到1之間

model = Perceptron(max_iter=40, eta0=0.1)
model.fit(X_train, y_train)


# ----- 01. 進行預測 ----- #

predict = model.predict(X_test)
print("預測結果: ", predict)
print("實際結果: ", np.array(y_test))


# ----- 02. 模型分數評估 ----- #

from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix

print("===== 準確率 accuracy score =====")
print(accuracy_score(y_test,predict))
'''分數 > 0.75 極為表現良好'''

print("\n===== 混淆矩陣 confussion matrix =====")
print("縱軸: 真實數量, 橫軸: 猜測數量\n")
print(confusion_matrix(y_test,predict))

print("\n===== 分類報告 classification report =====")
print("3種品項的精確率(預測為真), 召回率(事實為真), 兩者平均值, 實際出現次數\n")
print("精確度: 從預測正確的角度(橫軸)計算(O, O(猜12=>精確12), X(猜8=>其實7))\n")
print("召回率: 從真實正確的角度(橫軸)計算(O, X(正確13=>猜12), O(正確7=>召回7))\n")
print(classification_report(y_test,predict))
```
![](https://i.imgur.com/b1FpR9a.png)



## 二、線性－羅吉斯迴歸 Logistic Regression
![](https://i.imgur.com/VaZtYFc.png)
![](https://i.imgur.com/h7xoZwC.png)

1. 由PLA延伸，判斷資料可能是A/B的機率

**羅吉斯迴歸**
```
from sklearn.linear_model import LogisticRegression


# ----- 00. 訓練分類模型 ----- #

model = LogisticRegression(solver='liblinear')
model.fit(X_train, y_train)


# ----- 01. 進行預測 ----- #

predict = model.predict(X_test)
print("預測結果: ", predict)
print("實際結果: ", np.array(y_test))

# ===== Logistic Regression 額外可針對機率做計算 =====
pd.options.display.float_format = '{:,.2f}'.format
predict_probability = model.predict_proba(X_test)

print("\n===== Logistic Regression可預測機率 =====\n")
print(predict_probability)

'''
===== Logistic Regression可預測機率 =====

[[2.00841669e-02 6.43838219e-01 3.36077614e-01]
 [2.61997627e-03 3.40084040e-01 6.57295984e-01]
 [1.58477364e-02 7.44523453e-01 2.39628811e-01]
 [1.27083409e-03 3.46926469e-01 6.51802697e-01]
'''


# ----- 02. 模型分數評估 ----- #

print("===== 準確率 accuracy score =====")
print(accuracy_score(y_test,predict))
'''分數 > 0.75 極為表現良好'''

print("\n===== 混淆矩陣 confussion matrix =====")
print("縱軸: 真實數量, 橫軸: 猜測數量\n")
print(confusion_matrix(y_test,predict))

print("\n===== 分類報告 classification report =====")
print("3種品項的精確率(預測為真), 召回率(事實為真), 兩者平均值, 實際出現次數\n")
print("精確度: 從預測正確的角度(橫軸)計算(O, O(猜12=>精確12), X(猜8=>其實7))\n")
print("召回率: 從真實正確的角度(橫軸)計算(O, X(正確13=>猜12), O(正確7=>召回7))\n")
print(classification_report(y_test,predict))
```
## 三、線性－最近鄰分類 K-Nearest Neighbors(K-NN)
```
from sklearn.neighbors import KNeighborsClassifier
import numpy as np


# ----- 00. 訓練分類模型 ----- #

model = KNeighborsClassifier(n_neighbors=3)
model.fit(X_train, y_train)


# ----- 01. 進行預測 ----- #

predict = model.predict(X_test)
print("預測結果: ", predict)
print("實際結果: ", np.array(y_test))


# ----- 02. 模型分數評估 ----- #

print("===== 準確率 accuracy score =====")
print(accuracy_score(y_test,predict))
'''分數 > 0.75 極為表現良好'''

print("\n===== 混淆矩陣 confussion matrix =====")
print("縱軸: 真實數量, 橫軸: 猜測數量\n")
print(confusion_matrix(y_test,predict))

print("\n===== 分類報告 classification report =====")
print("3種品項的精確率(預測為真), 召回率(事實為真), 兩者平均值, 實際出現次數\n")
print("精確度: 從預測正確的角度(橫軸)計算(O, O(猜12=>精確12), X(猜8=>其實7))\n")
print("召回率: 從真實正確的角度(橫軸)計算(O, X(正確13=>猜12), O(正確7=>召回7))\n")
print(classification_report(y_test,predict))
```
![](https://i.imgur.com/bHaV1B9.png)

## 四、平面－支援向量機 Support Vector Machine(SVM)
[資料來源](https://medium.com/jameslearningnote/%E8%B3%87%E6%96%99%E5%88%86%E6%9E%90-%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E7%AC%AC3-4%E8%AC%9B-%E6%94%AF%E6%8F%B4%E5%90%91%E9%87%8F%E6%A9%9F-support-vector-machine-%E4%BB%8B%E7%B4%B9-9c6c6925856b)

1. 適用非線性、高維度資料(特徵欄位>3)







