機器學習筆記2 – sklearn之iris數據集

前言

本篇我會使用scikit-learn這個開源機器學習庫來對iris數據集進行分類練習。python

我將分別使用兩種不一樣的scikit-learn內置算法——Decision Tree(決策樹)kNN(鄰近算法),隨後我也會嘗試本身實現kNN算法。目前爲止,我仍是在機器學習的入門階段,文章中暫不詳細解釋算法原理,若是想了解細節信息可自行搜索。git


代碼分解

讀取數據集

scikit-learn中預製了不少經典數據集,很是方便咱們本身練習用。使用方式也很容易:github

# 引入datasets
from sklearn import datasets
# 獲取所需數據集
iris = datasets.load_iris()

load_iris返回的結果有以下屬性:算法

  • feature_names - 分別爲:sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)
  • data - 每行的數據,一共四列,每一列映射爲feature_names中對應的值
  • target - 每行數據對應的分類結果值(也就是每行數據的label值),其值爲[0,1,2]
  • target_names - target的值對應的名稱,其值爲['setosa' 'versicolor' 'virginica']


分離數據

監督學習能夠用一個簡單的數學公式來表明:數組

y = f(X)app

按上一篇中的相關術語描述就是已知X(features),經過方法f(classifier)y(label)機器學習

按照這個思路,我將iris數據分離爲:ide

# X = features
X = iris.data
# y = label
y = iris.target

那如何來使用數據呢?由於只有150行數據,因此爲了驗證算法的正確性,須要將數據分紅兩部分:訓練數據測試數據,很幸運的是scikit-learn也提供了方便分離數據的方法train_test_split,我將數據分離成60%(即90條數據)用於訓練,40%(即60條數據)用於測試,代碼以下:函數

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.6)


內置算法——Decision Tree(決策樹)

上一篇中已經用過決策樹,使用決策樹的代碼簡單以下:性能

# Decision tree classifier
# 生成決策樹
my_classification = tree.DecisionTreeClassifier()
# 訓練
my_classification.fit(X_train, y_train)
# 預測
predictions = my_classification.predict(X_test)

經過決策樹算法,最終獲得的模型的準確率有多少呢?這個時候可使用scikit-learnaccuracy_score方法:

# 得到預測準確率
print(accuracy_score(y_test, predictions))

因爲train_test_split是隨機切分數據,所以最終跑出來的準確率不是一個固定值


內置算法——kNN(鄰近算法)

kNN算法就是選取k個最近鄰居來歸類樣本值的方法,這是最簡單的一種分類算法,固然缺點也很明顯,必須循環計算測試樣本值和全部的樣本之間的距離,運行效率比較低。

在選用kNN算法的時候,k值最好是奇數,偶數值會形成沒法歸到惟一類的狀況(屬於不一樣分類的機率正好相等)。

只需在上述分離數據以後,將決策樹算法的代碼替換爲:

# N neighbors classifier
# 生成kNN
my_classification2 = KNeighborsClassifier(n_neighbors=5)
# 訓練
my_classification2.fit(X_train, y_train)
# 預測
predictions2 = my_classification2.predict(X_test)
# 得到預測準確率
print(accuracy_score(y_test, predictions2))

因爲train_test_split是隨機切分數據,所以最終跑出來的準確率不是一個固定值。並且因爲算法不一樣,即使是相同的數據,跑出來的準確率也和決策樹跑出來的不一樣。


本身實現kNN

基本思路是沿用上述內置kNN算法的代碼,從新實現KNeighborsClassifier,稱之爲MyKNN好了。除了初始化函數以外,還須要fitpredict這兩個方法,而且方法簽名和原先的保持一致,因此MyKNN類的基本結構以下:

class MyKNN:
    def __init__(self, n_neighbors=5):
        pass
    
    def fit(self, X_train, y_train):
        pass
        
    def predict(self, X_test):
        pass


實現__init__

初始化方法僅需初始化幾個參數以便後續使用:

def __init__(self, n_neighbors=5):
        self.n_neighbors = n_neighbors
        self.X_train = None
        self.y_train = None


實現fit

在這裏我簡單處理該方法,因爲原先fit方法包含了X和y兩個參數,所以沿用該方法簽名,這樣就不須要改動其餘代碼了:

def fit(self, X_train, y_train):
        self.X_train = X_train
        self.y_train = y_train


實現predict

我須要在該方法中遍歷計算測試數據和訓練數據之間的距離,兩點之間的距離可使用歐幾里得公式,所以須要先定義一個外部方法my_euclidean

def my_euclidean(a, b):
    return distance.euclidean(a, b)

我須要計算當前測試數據與K個最近距離的訓練數據之間的值,而後看一下這K個數據中,最多的分類是哪一種,則可認爲測試數據也屬於該種分類(機率最高)。所以先定義一個私有方法__closest

def __closest(self, row):
        all_labels = []
        for i in range(0, len(self.X_train)):
            dist = my_euclidean(row, self.X_train[i])
            # 獲取k個最近距離的鄰居,格式爲(distance, index)的tuple集合
            all_labels = self.__append_neighbors(all_labels, (dist, i))

        # 將k個距離最近的鄰居,映射爲label的集合
        nearest_ones = np.array([self.y_train[idx] for val, idx in all_labels])
        # 使用numpy的unique方法,分組計算label的惟一值及其對應的值第一次出現的index和值的計數
        # 例: elements = [1, 2],  elements_index = [3,0], elements_count = [1, 4] 這個結合表示:
        #   elements = [1, 2] : 出現了1和2兩種類型的數據
        #   elements_index = [3,0] : 1第一次出現的index是3, 2第一次出現的index是0
        #   elements_count = [1, 4] : 1共出現了1次, 2共出現了4次
        elements, elements_index, elements_count = np.unique(nearest_ones, return_counts=True, return_index=True)
        # 返回最大可能性的那種類型的label值
        return elements[list(elements_count).index(max(elements_count))]

爲了提高性能,我定義了__append_neighbors方法,該方法將當前距離-序號的tuple加入到數組中並按升序排序,最終只截取前k個值,能夠用python的特性很容易實現該邏輯:

def __append_neighbors(self, arr, item):
        if len(arr) <= self.n_neighbors:
            arr.append(item)
        return sorted(arr, key=lambda tup: tup[0])[:self.n_neighbors]


後記

短短几行代碼就實現了本身的kNN算法,我本地跑下來的準確率在95%以上。
須要完整代碼能夠在個人GitHub上找到。



本文在個人博客園個人我的博客上同步發佈,做者保留版權,轉載請註明來源。

相關文章
相關標籤/搜索