前言
本博客主要是記錄一些學習《python 機器學習基礎》的心得 ,通過記錄博客來作爲輸出,希望能夠和大家一起分享知識。代碼編寫環境是直接安裝的Anaconda,在 Jupyter Notebook上實現的,對於小白來說很友好,省事
後面的內容主要是從書中的 1.7 第一個應用:鳶尾花分類
開始記錄,因爲之前都是一些簡單的介紹,比如使用的代碼包和版本,大家可以自己去了解就行。那麼廢話不多說,就開始吧
1.7 第一個應用:鳶尾花分類
這個小節主要是介紹如何去實現一個簡單的模型還有一些核心概念和術語。
問題分析
1.場景
有一名植物學愛好者對她發現的鳶尾花品種很感興趣,她就收集了每朵鳶尾花的一些測量數據:花瓣的長度和寬度以及花萼的長度和寬度,所有測量結果的單位都是釐米。這些花之前已經被植物學專家鑑定爲屬於 setosa、 versicolor 或 virginica 三個品種之一。
2.目標
現在的目標就是構建一個機器學習模型,可以從這些已知的品種的鳶尾花測量數據中進行學習,從而能夠預測新鳶尾花的品種。
3.問題定位
我們有已知品種的鳶尾花的測量數據,所以這是一個監督學習問題,同時在這個場景中我們是要預測出屬於哪一種鳶尾花品種,所以這還是一個分類問題。這其中有兩個基本概念,類別與標籤。
-
類別:鳶尾花的不同品種
-
標籤:單個數據點(一朵鳶尾花)的預期輸出——這朵花屬於哪個品種
1.7.1 初識數據
本例中使用到的數據,是機器學習和統計學中一個經典的數據集,它包含在scikit-learn 的 datasets 模塊中,引入方式如下:
from sklearn.datasets import load_iris
iris_dataset = load_iris()
load_iris 返回的 iris 對象是一個 Bunch 對象,與字典非常相似,裏面包含鍵和值,可以使用iris_dataset.keys()查看
其中有一些關鍵字段需要說明:
DESCR 鍵對應的值是數據集的簡要說明:可以使用如下方式查看
print(iris_dataset['DESCR'][:193] + "\n...")
target_names 鍵對應的值是一個字符串數組,裏面包含我們要預測的花的品種:
print("Target names: {}".format(iris_dataset['target_names']))
feature_names 鍵對應的值是一個字符串列表,對每一個特徵進行了說明:
print("Feature names: \n{}".format(iris_dataset['feature_names']))
target 和 data 字段包含着訓練使用的數據,data裏面是花萼長度、花萼寬度、花瓣長度、花瓣寬
度的測量數據,格式爲 NumPy 數組;data 數組的每一行對應一朵花,列代表每朵花的四個測量數據。
使用如下語法查看數據的情況:
print("Shape of data: {}".format(iris_dataset['data'].shape))
###會輸出 Shape of data: (150, 4)
可以看出,數組中包含 150 朵不同的花的測量數據。這裏補充一些概念,機器學習彙總,個體叫樣本(sample)
,其屬性叫做特徵(feature)
。下面給出前 5 個樣本的特徵數值:
print("First five rows of data:\n{}".format(iris_dataset['data'][:5]))
輸出如下:
First five rows of data:
[[ 5.1 3.5 1.4 0.2]
[ 4.9 3. 1.4 0.2]
[ 4.7 3.2 1.3 0.2]
[ 4.6 3.1 1.5 0.2]
[ 5. 3.6 1.4 0.2]]
target是一維數組,每朵花對應其中一個數據:(品種被轉換成從 0 到 2 的整數)
print("Target:\n{}".format(iris_dataset['target']))
輸出如下:
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 000000000000111111111111111111111111 1
111111111111111111111111122222222222 2
222222222222222222222222222222222222 2 2]
上述數字的代表含義由 iris['target_names'] 數組給出:
0 代表 setosa,1 代表 versicolor, 2 代表 virginica。
1.7.2 衡量模型是否成功:訓練數據與測試數據
當評估一個模型的效果時,我們是不能用構建模型的數據用於評估模型的,因爲我們的模型會一直記住這個數據,他就總是能預測正確,這樣會導致我們無法判斷它的預測結果是否可信。因此我們需要使用新的數據來評估模型性能。
通常的做法通常的做法是將收集好的帶標籤數據(此例中是 150 朵花的測量數據) 分成兩部分。一部分數據用於構建機器學習模型,叫作訓練數據(training data)或訓練 集(training set)。其餘的數據用來評估模型性能,叫作測試數據(test data)、測試集(test set)或留出集(hold-out set)
如何實現數據劃分
scikit-learn 中的 train_test_split 函數可以打亂數據集並進行拆分。這個函數將 75% 的 行數據及對應標籤作爲訓練集,剩下 25% 的數據及其標籤作爲測試集。訓練集與測試集的 分配比例可以是隨意的,但使用 25% 的數據作爲測試集是很好的經驗法則。
基本原則
scikit-learn 中的數據通常用大寫的 X 表示,而標籤用小寫的 y 表示。這是受到了數學 標準公式 f(x)=y 的啓發,其中 x 是函數的輸入,y 是輸出。我們用大寫的 X 是因爲數據是 一個二維數組(矩陣),用小寫的 y 是因爲目標是一個一維數組(向量),這也是數學中 的約定。
代碼樣例
###在對數據進行拆分之前,train_test_split 函數利用僞隨機數生成器將數據集打亂。
###爲了確保多次運行同一函數能夠得到相同的輸出,我們利用 random_state 參數指定了隨機數生成器的種子。
##這樣函數輸出就是固定不變的,所以這行代碼的輸出始終相同。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
iris_dataset['data'], iris_dataset['target'], random_state=0)
train_test_split 函數的輸出爲 X_train、X_test、y_train 和 y_test,它們都是 NumPy 數組。
X_train 包含 75% 的行數據,X_test 包含剩下的 25%
1.7.3 觀察數據
在構建機器學習模型之前,通常最好檢查一下數據,看看如果不用機器學習能不能輕鬆完
成任務,或者需要的信息有沒有包含在數據中。比如數據中是否包含異常值和特殊值。
觀察數據可以繪製散點圖,對於多於 3 個維度的數據集,可以繪製散點矩陣圖
代碼實現
注意:需要先執行以下代碼引入相關包,其中因爲 python3 的版本原因,引入 mglearn 會有警告,scatter_matrix()方法在 pandas.plotting 下。
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import mglearn
# 利用X_train中的數據創建DataFrame
# 利用iris_dataset.feature_names中的字符串對數據列進行標記
iris_dataframe = pd.DataFrame(X_train,columns=iris_dataset.feature_names)
# 利用DataFrame創建散點圖矩陣,按y_train着色
grr = pd.plotting.scatter_matrix(iris_dataframe,c=y_train,figsize=(15,15),marker='o'
,hist_kwds={'bins':20},s=60,alpha=.8,cmap=mglearn.cm3)
Iris 數據集的散點圖矩陣,按類別標籤着色
1.7.4 構建第一個模型:k 近鄰算法
現在開始構建機器學習的模型,對於這個場景我們使用的是 k 近鄰分類器。這是一個很容易理解的算法。構建此模型只需要保存訓練 集即可。要對一個新的數據點做出預測,算法會在訓練集中尋找與這個新數據點距離最近 的數據點,然後將找到的數據點的標籤賦值給這個新數據點。
scikit-learn 中所有的機器學習模型都在各自的類中實現,這些類被稱爲 Estimator 類。k 近鄰分類算法是在 neighbors 模塊的 KNeighborsClassifier 類中實現的。我們需 要將這個類實例化爲一個對象,然後才能使用這個模型。這時我們需要設置模型的參數。 KNeighborsClassifier 最重要的參數就是鄰居的數目,這裏我們設爲 1:
代碼實現
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=1)
想要基於訓練集來構建模型,需要調用 knn 對象的 fit 方法,輸入參數爲 X_train 和 y_ train,二者都是 NumPy 數組,前者包含訓練數據,後者包含相應的訓練標籤
knn.fit(X_train, y_train)
輸出如下:
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
metric_params=None, n_jobs=1, n_neighbors=1, p=2,
weights='uniform')
1.7.5 做出預測
現在我們可以用這個模型對新數據進行預測了,我們可能並不知道這些新數據的正確標籤,先模擬一份數據看看
In[27]:
X_new = np.array([[5, 2.9, 1, 0.2]])
print("X_new.shape: {}".format(X_new.shape))
Out[27]:
X_new.shape: (1, 4)
我們將這朵花的測量數據轉換爲二維 NumPy 數組的一行,這是因爲 scikit-learn
的輸入數據必須是二維數組。
預測
現在調用 knn 對象的 predict 方法來進行預測:
prediction = knn.predict(X_new)
print("Prediction: {}".format(prediction))
print("Predicted target name: {}".format(
iris_dataset['target_names'][prediction]))
輸出如下:
Prediction: [0]
Predicted target name: ['setosa']
1.7.6 評估模型
這裏需要用到之前創建的測試集。這些數據沒有用於構建模型,但我們知道測試集中每朵
鳶尾花的實際品種。
因此,我們可以對測試數據中的每朵鳶尾花進行預測,並將預測結果與標籤(已知的品 種)進行對比。我們可以通過計算精度(accuracy)來衡量模型的優劣,精度就是品種預 測正確的花所佔的比例:
notebook上操作如下
In[29]:
y_pred = knn.predict(X_test)
print("Test set predictions:\n {}".format(y_pred))
Out[29]:
Test set predictions:
[2 1 0 2 0 2 0 1 1 1 2 1 1 1 1 0 1 1 0 0 2 1 0 0 2 0 0 1 1 0 2 1 0 2 2 1 0 2]
In[30]:
print("Test set score: {:.2f}".format(np.mean(y_pred == y_test)))
Out[30]:
Test set score: 0.97
我們還可以使用 knn 對象的 score 方法來計算測試集的精度:
In[31]:
print("Test set score: {:.2f}".format(knn.score(X_test, y_test)))
Out[31]:
Test set score: 0.97
結果
對於這個模型來說,測試集的精度約爲 0.97,也就是說,對於測試集中的鳶尾花,我們的 預測有 97% 是正確的。根據一些數學假設,對於新的鳶尾花,可以認爲我們的模型預測 結果有 97% 都是正確的。對於我們的植物學愛好者應用程序來說,高精度意味着模型足 夠可信,可以使用。
未完待續