# 巨匠Python - 機器學習
###### tags: `資料分析`
# 第一章、機器學習主要概念

[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
```
:::
**線性回歸**

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

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

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))
```

## 二、線性-羅吉斯迴歸 Logistic Regression


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))
```

## 四、平面-支援向量機 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)