機器學習實戰 K-近鄰算法

K-近鄰算法概述

​ 簡單地說,**k-近鄰算法採用測量不同特徵值之間的距離的方法進行分類。他的優點是精度高、對異常值不敏感、無數據輸入設定。缺點是計算複雜度高、空間複雜度高。**使用數據範圍爲:數值型和標稱型。

​ k-近鄰算法(kNN)的工作原理是:存在一個樣本數據集合,也稱作訓練樣本集,並且樣本集合中每個數據都存在標籤,即我們知道樣本集中每一數據與所屬分類的對應關係。輸入沒有標籤的新數據後,**將新數據的每個特徵與樣本集中數據對應的特徵進行比較,然後算法提取樣本集中特徵最相似(最近鄰)的分類標籤。一般來說,我們只選擇樣本數據集中前k個最相似數據的數據,**這就是k-近鄰算法中k的出處,**通常,k是不大於20的整數。**最後,選擇k個最相似的數據中出現的次數最多的分類,作爲新數據的分類。

k-近鄰算法的一般流程

  1. 收集數據: 可以使用任何方法
  2. 準備數據:距離計算所需要的數值,最好是結構化的數據格式
  3. 分析數據:可以使用任何方法
  4. 訓練算法:此步驟不適合k-近鄰算法
  5. 測試算法:計算錯誤率
  6. 使用算法:首先需要輸入樣本數據和結構化的輸出結果。然後運行k-近鄰算法判定輸入數據分別屬於哪個分類,最後應用對計算出的分類執行後續的處理。

k-近鄰算法的實施

對未知類別屬性的數據集中的每個點依次執行以下操作:

  1. 計算已知類別數據集中的點中的每個點與當前點之間的距離
  2. 按照距離遞增次序排序
  3. 選取與當前距離最小的k個點
  4. 確定前k個點所在類別的出現頻率
  5. 返回前k個點出現頻率最高的類別作爲當前點的預測分類

點與點之間的距離的算法有很多,這裏使用了歐氏距離公式:

(xA0xB0)2+(xA1xB1)2\sqrt{(xA_0 - xB_0)^2 + (xA_1 - xB_1)^2}

例如,點(0,0)與(1,2)之間的距離計算爲:(10)2+(20)2\sqrt{(1 - 0)^2 + (2 - 0)^2}

數據的歸一化

​ 對於某些數據,其特徵值之間的數值差異比較大,而差值最大的屬性對結果影響也很大。這會大大提高分類模型的錯誤率。**因此將該類數據歸一化是一個重要的操作。**下面的公式可以將任取值範圍的特徵值轉換爲0到1之間的值:(oldValuemin)/(maxmin)(oldValue - min)/(max - min)。其中,min和max分別是數據集中的最小特徵值和最大特徵值。

如何測試分類器

​ 分類器並不會得到百分百正確的結果,我們可以使用多種方法檢測分類器的正確率。此外分類器的性能也會受到多種因素的影響,如分類器設置和數據集等。不同的算法在不同數據集上的表現可能完全不同。

​ 爲了測試分類器的效果,我們可以使用已知答案的數據,檢驗分類器給出的結果是否符合預期結果。通過大量的測試數據,我們可以得到分類器的錯誤率----分類器給出錯誤結果的次數除以測試執行的總數。錯誤率是常用的評估方法,主要用於評估分類器在某個數據集上的執行效果。完美分類器的錯誤率爲0,最差分類器的錯誤率是1.0。

示例: 使用k-近鄰算法改進約會網站的配對效果

​ 數據集見:datingTestSet.txt(提取碼:80ms)。數據一共分四列,前三列爲三種特徵,第四列爲三種人物類型。我們將通過前三種特徵值,生成一個kNN分類器,來預測不同人對於你的吸引力。

飛行里程數/年 視頻遊戲時間百分比 每週消費冰激凌公升數 吸引力
40920 8.326976 0.953952 largeDoses
14488 7.153469 1.673904 smallDoses
26052 1.441871 0.805124 didntLike

約會網站K-近鄰分類器生成步驟:

  1. 收集數據:提供文本文件
  2. 準備數據:使用python解析文本文件
  3. 測試算法:使用部分數據作爲測試樣本。計算分類器的錯誤率
  4. 使用算法:產生簡單的命令行程序,然後可以輸入一些特徵數據以判斷對方是否爲自己喜歡的類型。

python3代碼實現

#!/usr/bin/env python3
# coding: utf-8
# Author:Shen Yi
# Date :2020/2/13 21:19

"""機器學習實戰 第二章 k-近鄰算法

k-近鄰算法的完整實現,包含了k-近鄰算法的距離計算,錯誤率統計,數據集矩陣標準化以及一個戀愛網站的demo.

"""

from collections import Counter
from numpy import *


def knn_classify(in_x, data_set, labels, k_num):
    """ implementation of algorithm of knn

    calculation of distance between prediction and training, then sorted and extract the most common labels in top k_num
    closer data

    :param in_x: the vector to predict
    :param data_set: training data
    :param labels:  label of training data
    :param k_num:  number of k
    :return:  label of predict
    """

    # calculation of distance
    data_set_size = data_set.shape[0]
    diff_mat = tile(in_x, (data_set_size, 1)) - data_set
    distances = ((diff_mat ** 2).sum(axis=1)) ** 0.5
    sort_distances_index = distances.argsort()

    # extract the most common label
    vote_labels = [labels[index] for index in sort_distances_index[0: k_num]]
    most_label = Counter(vote_labels).most_common(1)[0][0]
    return most_label


def auto_norm(data_set):
    """data normalization"""

    min_vals = data_set.min(0)
    max_vals = data_set.max(0)
    ranges = max_vals - min_vals
    m = data_set.shape[0]
    norm_data_set = data_set - tile(min_vals, (m, 1))
    norm_data_set = norm_data_set / tile(ranges, (m, 1))
    return norm_data_set, ranges, min_vals


def dating_class_test(data_mat, labels, ho_ratio, k_num):
    """calculate the accuracy of the model"""

    m = data_mat.shape[0]
    error_count = 0
    number_test_vecs = int(m * ho_ratio)
    for i in range(number_test_vecs):
        classifier_rslt = knn_classify(data_mat[i, :], data_mat[number_test_vecs: m, :], labels[number_test_vecs: m], k_num)
        if classifier_rslt != labels[i]:
            error_count += 1
    print(f"the total error rate is: {error_count / number_test_vecs}")
    return error_count / number_test_vecs


def demo_date():
    """demo: used knn algorithm model to predict the matching effect of dating websites"""

    file_name = "data\\Ch02\\datingTestSet.txt"
    lines = open(file_name).readlines()
    lines_number = len(lines)
    data_mat = zeros((lines_number, 3))
    labels = []
    index = 0
    for line in lines:
        line = line.strip().split('\t')
        data_mat[index, :] = line[0: 3]
        labels.append(line[-1])
        index += 1

    norm_data_set, ranges, min_vals = auto_norm(data_mat)
    dating_class_test(norm_data_set, labels, 0.1, 3)

    percent_tas = float(input("percentage of time spent playing video games: "))
    ffmiles = float(input("frequent flier miles earned per year: "))
    ice_cream = float(input("liters of ice cream consumed per year:"))
    in_array = (array([ffmiles, percent_tas, ice_cream]) - min_vals) / ranges
    classifier_result = knn_classify(in_array, norm_data_set, labels, 3)
    print(f"you will probably like this person: {classifier_result}")


if __name__ == '__main__':
    demo_date()

運行結果:

the total error rate is: 0.05
percentage of time spent playing video games: 10
frequent flier miles earned per year: 10000
liters of ice cream consumed per year:0.5
you will probably like this person: smallDoses

從結果可以看出,該分類器的錯誤率爲5%,在輸出一組特徵值後,得到了預期的分類標籤。

發佈了16 篇原創文章 · 獲贊 4 · 訪問量 7552
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章