1. 程式人生 > >機器學習實戰——1.1K近鄰演算法

機器學習實戰——1.1K近鄰演算法

宣告:參考書目《機器學習實戰》作者: Peter Harrington 出版社: 人民郵電出版社 譯者: 李銳 / 李鵬 / 曲亞東 / 王斌 

參考部落格 Jack-Cui  作者個人網站:http://cuijiahua.com/

公式:d=\sqrt{(xA_{0}-xB_{0})^{2}+(xA_{1}-xB_{1})^{2}}

K近鄰演算法的一般步驟

  • 收集資料:可以使用任何方法
  • 準備資料:使用Python解析、預處理資料。
  • 分析資料:可以使用很多方法對資料進行分析,例如使用Matplotlib將資料視覺化。
  • 測試演算法:計算錯誤率。
  • 使用演算法:錯誤率在可接受範圍內,就可以執行k-近鄰演算法進行分類。

海倫女士一直使用線上約會網站尋找適合自己的約會物件。儘管約會網站會推薦不同的任選,但她並不是喜歡每一個人。經過一番總結,她發現自己交往過的人可以進行如下分類:

  1. 不喜歡的人
  2. 魅力一般的人
  3. 極具魅力的人

海倫收集約會資料已經有了一段時間,她把這些資料存放在文字檔案datingTestSet.txt中,每個樣本資料佔據一行,總共有1000行。資料地址:DataSet

資料主要包括四行,三種特徵以及一個標籤:其中第一組資料數量級遠大於其他兩組資料,如果直接將原始資料放入公式d=\sqrt{(xA_{0}-xB_{0})^{2}+(xA_{1}-xB_{1})^{2}} 會導致第一組資料其決定性的作用,從而導致其他兩組資料失效。因此我們需要將原始資料進行歸一化處理,將所有資料都處理到0-1的區間內。公式: newLine=\frac{oleLine-min}{max-min}

 

所以我們的目的這次就很清楚了,

  1. 首先將資料從文字匯入,進行預處理,將其放置到矩陣中
  2. 將矩陣中的資料進行歸一化處理
  3. 將需要進行判斷的資料輸入,並與DataSet中所有資料進行歐式距離計算
  4. 選取歐氏距離最小的前 k 個數據,將其中距離最小的資料你的類別作為本次輸入資料的類別
#-*-cording:UTF-8-*-
import numpy as np

#將資料從文字讀入矩陣中 filename 為檔案所在的地址
def ReadFile(filename):
    #開啟文字並讀取文字中的內容
    fr = open(filename)
    ReadLines = fr.readlines()
    #記錄文字行數是為了建立一個可以正好放入所有資料的矩陣
    Len_File = len(ReadLines)
    #建立一個全零矩陣大小為 Len_File * 3
    Array_return = np.zeros((Len_File,3))
    #建立一個列表,用於存放標籤
    ClassLables = []
    #index用於記錄存放在數組裡面數據的位置的
    index = 0
    #逐行讀取文字內容
    for line in ReadLines:
        #去除空格跟換行符
        line = line.strip()
        line = line.split('\t')
        #將每行資料的前三個賦值給矩陣對應的行。資料第四個為標籤
        Array_return[index, : ] = line[0:3]
        #按標籤將資料進行分類,1代表不喜歡,2第還行,3表示還不錯
        if line[-1] == 'didntLike':
            ClassLables.append(1)
        elif line[-1] == 'smallDoses':
            ClassLables.append(2)
        elif line[-1] == 'largeDoses':
            ClassLables.append(3)
        index += 1
    return Array_return, ClassLables

#歸一化處理 DataSet為輸入的資料集
#公式為  newValue= (oleValue - min)/(max - min)
def AutoNorm(DataSet):
    #shape[0]返回的是Dataset的行數,shape[1]返回的是列數
    array_len = DataSet.shape[0]
    #輸出DataSet行裡面的最大最小值
    min_value = DataSet.min(axis=0)
    max_value = DataSet.max(axis=0)
    value_range = max_value - min_value
    #newArray = np.zeros(np.shape(DataSet))
    #np.tile 是將min_value在行方向上覆制 array_len 次,在列方向上覆制1 次
    newArray = DataSet - np.tile(min_value,(array_len,1))
    newArray = newArray / np.tile(value_range,(array_len,1))
    return newArray,value_range, min_value

#K近鄰處理演算法
#公式為 diatance ={ (x1-x2)^2 - (y1-y2)^2 }^0.5
#Data為你給的資料,DataSet為資料集,Labes為標籤,K為你選擇的樣本數
def Classify(Data, DataSet, Lables, k):
    #獲取DataSet的行數,用以建立矩陣
    LenData = DataSet.shape[0]
    #建立一個矩陣,這個矩陣是由你給的 1*3矩陣複製成 LenData*3的矩陣減去DataSet矩陣得到的
    ArryMat = np.tile(Data, (LenData, 1)) - DataSet
    #將矩陣開方,其實是將矩陣內每個元素進行開方處理
    SqlMat = ArryMat ** 2
    #將矩陣按照列方向進行相加,變成一個LenData*1的矩陣
    SumMat = SqlMat.sum(axis=1)
    #將矩陣開根號處理
    DistanceMat = SumMat ** 0.5
    #將矩陣元素按從小到大排序,即數值越小說明距離越短,也就是越接近這個類別
    SortDistance = DistanceMat.argsort()
    #建立一個字典用來存放對應類別的個數
    ClassCount = {}
    for i in range(k):
        #返回Lables
        votoLables = Lables[SortDistance[i]]
        #字典的get函式dict.get(key, default=None)如果沒有找到對應的值,那麼就會返回你設定的值,或者預設值。這裡我們設定為 0
        ClassCount[votoLables] = ClassCount.get(votoLables,0) + 1
    #將字典裡按照從大到小排序
    SortClassCount = sorted(ClassCount.items(), reverse=True)
    #返回最大值
    return SortClassCount[0][0]




if __name__ == "__main__":
    filename = "C:/Users/lpp/Desktop/datingTestSet.txt"
    DataSet, Lables = ReadFile(filename)
    Array, value_range, min_value = AutoNorm(DataSet)
    precentTats = float(input("玩視訊遊戲所耗時間百分比:"))
    ffMiles = float(input("每年獲得的飛行常客里程數:"))
    iceCream = float(input("每週消費的冰激淋公升數:"))
    data = np.array([precentTats, ffMiles, iceCream])
    ClassCount = Classify(data, Array, Lables, 1)
    if ClassCount == 1:
        print("不喜歡")
    elif ClassCount == 2:
        print("感興趣")
    elif ClassCount == 3:
        print("非常喜歡")