機器學習之K-近鄰算法

1. 橙子仍是柚子

  該例子來自於《算法圖解》,看下圖中的水果是橙子仍是柚子?git

  

  個人思惟過程相似於這樣:我腦子裏面有個圖表github

  

  圖中左下的表示橙子,右上的表示柚子,取橙子和柚子的兩個特徵(大和紅),通常而言,柚子更大、更紅,上圖的水果又大又紅,所以多是柚子,那下面的水果呢?算法

  

  一種辦法是看它的鄰居,離它最近的鄰居的三個鄰居中有兩個橙子一個柚子,所以這個水果極可能是橙子app

  上面剛使用的方法就是KNN(K-近鄰算法),感受是否是很簡單測試

2. K-近鄰算法步驟

  對未知類別屬性的數據集中的每一個點依次執行如下操做:spa

(1)計算已知類別數據集中的點與當前點之間的距離code

(2)按照距離遞增順序排序orm

(3)選取與當前點距離最小的K個點對象

(4)肯定前k個點所在類別的出現頻率blog

(5)返回前k個點出現頻率最高的類別做爲當前點的預測分類

3. K-近鄰算法實現

  使用Python按照上面的步驟實現算法

import numpy as np

def knn(labels, dataset, in_data,k):

    """
    labels:list
    dataset:ndarray
    in_data:ndarray
    k:int
    """
    row = dataset.shape[0]
    sub_set = dataset - np.tile(in_data,(row,1))
    sqrt_set = sub_set ** 2
    distance = sqrt_set.sum(axis=1) ** 0.5
    dic = {}
    sortedIndex_list = distance.argsort()
    # 算出鄰居中對應的label次數
    result = {}
    for i in range(k):
        key = sortedIndex_list[i]
        result[labels[key]] = result.get(labels[key],0)+1
        
    result_list=sorted(result.items(), key=lambda x: x[1],reverse=True)
    return result_list[0][0]

4. 示例1:約會匹配

需求:

  根據數據特徵值(玩遊戲所耗時間百分比、每一年得到的飛行里程數、每週消費的冰淇淋公升數),判斷對該約會對象的喜愛程度,絕對是否要去約會

準備工做:

(1)數據集:dataset\datingTestSet2.txt

(2)數據集特徵:

  a. 玩遊戲所耗時間百分比  ---->數據集中的第一列

  b. 每一年得到的飛行里程數  ---->數據集中的第二列

  c. 每週消費的冰淇淋公升數 ---->數據集中的第三列

(3)樣本分類標籤:---->數據集中的第四列

(4)測試數據集:dataset\datingTestSet.txt

實現:

(1)從文件提取數據集和標籤

def file2matrix(filename):

    """將文件數據轉換爲numpy.ndarray"""
    
    list_lines = []
    with open(filename,'r') as pf:
        lines = pf.readlines()
        for line in lines:
            list_lines.append([float(i) for i in line.strip().split('\t')])
            
    matrix = np.array(list_lines)
    data_set = matrix[:,0:-1]
    class_labels = matrix[:,-1:]
    class_labels = class_labels.reshape(1,1000).tolist()[0]
    return data_set,class_labels

(2)對數據集中的特徵值數據進行歸一化處理

def auto_norm(dataset):
    """
    爲了防止各特徵值之間的數值差距太大而影響計算結果,
    對矩陣數據進行歸一化處理,將每一個特徵值都轉換爲[0,1]
    """
    min = dataset.min(0)
    max = dataset.max(0)
    sub = max - min
    norm_dataset = np.zeros(dataset.shape)
    row = dataset.shape[0]
    norm_dataset = dataset - np.tile(min,(row,1))
    norm_dataset = norm_dataset / np.tile(sub,(row,1))
    return norm_dataset,sub,min

(3)使用測試數據集對算法進行測試

def test_datingTestSet():
    data_set,date_labels = file2matrix('dataset\\datingTestSet2.txt')
    norm_dataset,sub,min = auto_norm(data_set)

    #根據數據集測試KNN算法的正確率
    rows = norm_dataset.shape[0]
    ok = 0
    for i in range(rows):
        result = knn(date_labels,norm_dataset,norm_dataset[i,:],3)
        if result == date_labels[i]:
            ok += 1
        else:
            print("測試錯誤結果爲{},正確結果爲{}".format(result, date_labels[i]))
    print("測試總記錄數爲{},成功記錄數爲{},KNN算法成功率爲{}".format(rows,ok,ok/rows))

輸出:

5. 示例2:手寫識別系統

需求:

  根據dataset\trainingDigits文件夾中的樣本數據和dataset\testDigits文件夾中的樣本數據測試KNN算法

實現:

(1)將每一個文件中的數據(32*32)轉換爲matrix(m*1024)

def imgae2matrix(filepath):
    filelist = os.listdir(filepath)
    m = len(filelist)
    array_m_1024 = np.zeros((m,1024))
    k = 0
    labels = []
    for file in filelist:
        #對文件名進行處理獲得labels
        label = file.split('_')[0]
        labels.append(label)
        array_1_1024 = np.zeros((1,1024))
        with open(os.path.join(filepath,file),'r') as pf:
            for i in range(32):
                line = pf.readline()
                for j in range(32):
                    array_1_1024[0,32*i+j] = int(line[j])
        array_m_1024[k,:] = array_1_1024
        k+=1
    return array_m_1024,labels

(2)使用knn算法測試成功率

def test_numbers():
    array_m_1024,labels = imgae2matrix('dataset\\trainingDigits\\')
    test_array_m_1024,test_labels = imgae2matrix('dataset\\testDigits\\')
    ok = 0
    rows = test_array_m_1024.shape[0]
    for i in range(rows):
        in_data = test_array_m_1024[i,:]
        result = knn(labels, array_m_1024, in_data,5)
        if result == test_labels[i]:
            ok += 1
        else:
            print("測試錯誤結果爲{},正確結果爲{}".format(result, test_labels[i]))
    print("測試總記錄數爲{},成功記錄數爲{},KNN算法成功率爲{}".format(rows,ok,ok/rows))

(3)輸出

6. 總結

  K-近鄰算法是分類數據最簡單有效的算法,使用算法時必須有接近實際數據的訓練樣本數據,若是訓練數據集很大,必須使用大量的存儲空間,此外因爲必須對數據集中的每一個數據計算距離值,實際使用時可能很是耗時。

  K-近鄰算法的另外一個缺陷是它沒法給出任何數據的基礎結構信息,所以咱們也沒法知曉平均實例樣本和典型實例樣本具備什麼特徵。

  代碼和數據集都已上傳至:https://github.com/lizoo6zhi/MachineLearn.samples

相關文章
相關標籤/搜索