1. 程式人生 > >《機器學習實戰》學習筆記:k-近鄰演算法的兩個應用場景

《機器學習實戰》學習筆記:k-近鄰演算法的兩個應用場景

之前學習了k-近鄰演算法的實現後,參考《機器學習實戰》中的例子進行了k-近鄰演算法的測驗,主要測試了針對約會網站和手寫識別系統的資料分類,這兩個測試使用的是《機器學習實戰》提供的資料集。

在編寫函式前,需在.py檔案中新增以下內容:

from numpy import *
import numpy as np
import operator
from os import listdir

第一部分是針對約會網站的資料分類,用於改進約會網站的配對效果。該例項的簡介如下:

  • 海倫一直使用線上約會網站尋找合適自己的約會物件。儘管約會網站會推薦不同的人選,但她沒有從中找到喜歡的人。經過一番總結,她發現曾交往過三種類型的人:
    1.不喜歡的人( 以下簡稱1 );
    2.魅力一般的人( 以下簡稱2 );
    3.極具魅力的人( 以下簡稱3 )

  • 儘管發現了上述規律,但海倫依然無法將約會網站推薦的匹配物件歸入恰當的分類。她覺得可以在週一到週五約會哪些魅力一般的人,而週末則更喜歡與那些極具魅力的人為伴。海倫希望我們的分類軟體可以更好的幫助她將匹配物件劃分到確切的分類中。此外海倫還收集了一些約會網站未曾記錄的資料資訊,她認為這些資料更有助於匹配物件的歸類。

  • 這裡提取一下這個案例的目標:根據一些資料資訊,對指定人選進行分類(1或2或3)。為了使用kNN演算法達到這個目標,我們需要哪些資訊?前面提到過,就是需要樣本資料,仔細閱讀我們發現,這些樣本資料就是“海倫還收集了一些約會網站未曾記錄的資料資訊 ”。

針對以上的描述,需要進行以下步驟:

  1. 收集資料

  2. 準備資料

  3. 設計演算法分析資料

  4. 測試演算法

1.收集資料

海倫收集的資料是記錄一個人的三個特徵:每年獲得的飛行常客里程數;玩視訊遊戲所消耗的時間百分比;每週消費的冰淇淋公升數。資料是txt格式檔案,如下圖,前三列依次是三個特徵,第四列是分類(1:代表不喜歡的人,2:代表魅力一般的人,3:代表極具魅力的人),每一行資料代表一個人。

這裡寫圖片描述

2.準備資料

計算機需要對資料檔案txt讀取資料,因此需要把資料進行格式化,對於數學運算,計算機擅長把資料存放在矩陣中。以下程式碼中file2matrix(filename)函式完成了這一工作,該函式輸入資料檔名(字串),輸出訓練樣本矩陣和類標籤向量。

這一過程返回兩個矩陣:一個矩陣用於存放每個人的三個特徵資料,一個矩陣存放每個人對應的分類。

3.設計演算法分析資料

k-近鄰演算法的思想是尋找測試資料的前k個距離最近的樣本,然後根據這k個樣本的分類來確定該資料的分類,遵循“多數佔優”原則。因此,如何尋找樣本成為主要的問題,在訊號處理和模式識別領域中,常常使用“距離”來度量訊號或特徵的相似度。在這裡,我們假定可以使用三個特徵資料來代替每個人,比如第一個人的屬性我們用[40920, 8.326976, 0.953952]來代替,並且他的分類是3。那麼此時的距離就是點的距離。

求出測試樣本與訓練樣本中每個點的距離,然後進行從小到大排序,前k位的就是k-近鄰,然後看看這k位近鄰中佔得最多的分類是什麼,也就獲得了最終的答案。這一部分是k-近鄰演算法的核心,程式碼中classify()函式就實現了k-近鄰演算法的核心部分。

一個優化演算法效果的步驟——歸一化資料:

開啟資料檔案我們可用發現第一列代表的特徵數值遠遠大於其他兩項特徵,這樣在求距離的公式中就會佔很大的比重,致使兩個樣本的距離很大程度上取決於這個特徵,其他特徵的特性變得可有可無,這顯然有悖於實際情況。因此通常我們可用使用歸一化這一數學工具對資料進行預處理,這一處理過後的各個特徵既不影響相對大小又可以不失公平。Normalize(data)函式實現了這一功能。

4.測試演算法

經過了對資料進行預處理後、歸一化數值,可用驗證kNN演算法有效性,測試程式碼為:WebClassTest() 由於資料有1000條,我們設定一個比率ratio = 0.1 也就是令 1000 * ratio = 100 條作為測試樣本,其餘900條作為訓練樣本,當然,ratio的值可用改變,對演算法效果是有影響的。

實現程式碼:

def classify(data, sample, label, k):
    SampleSize = sample.shape[0]
    DataMat = tile(data, (SampleSize, 1))
    delta = (DataMat - sample)**2
    distance = (delta.sum(axis = 1))**0.5 # 
    sortedDist = distance.argsort()
    classCount = {}

    for i in range(k):
        votedLabel = label[sortedDist[i]]
        classCount[votedLabel] = classCount.get(votedLabel, 0) + 1    
    result = sorted(classCount.iteritems(), key = operator.itemgetter(1), reverse = True)
    return result[0][0]

#print classify([10,0], sample, label, 3)

def file2matrix(filename):
    fil = open(filename)
    fileLines = fil.readlines() # Convert the contents of a file into a list
    lenOfLines = len(fileLines)
    Mat = zeros((lenOfLines, 3))
    classLabel = []
    index = 0
    for line in fileLines:
        line = line.strip()
        listFromLine = line.split('\t')
        Mat[index,: ] = listFromLine[0:3]
        classLabel.append(int(listFromLine[-1])) # the last one of listFromLine is Label
        index += 1
    return Mat, classLabel

mat,label = file2matrix('datingTestSet2.txt')

#print mat

# draw 

import matplotlib
import matplotlib.pyplot as plt

fil = open('datingTestSet2.txt')
fileLines = fil.readlines() # Convert the contents of a file into a list
lenOfLines = len(fileLines)

figure = plt.figure()
axis = figure.add_subplot(111)
lab = ['didntLike', 'smallDoses', 'largeDoses']

for i in range(3):
    n = []
    l = []
    for j in range(lenOfLines):
        if label[j] == i + 1:
            n.append(list(mat[j,0:3]))
            l.append(label[j])
    n = np.array(n)   # list to numpy.adarray
    #reshape(n, (3,k))
    axis.scatter(n[:,0], n[:,1], 15.0*array(l), 15.0*array(l), label = lab[i])
print type(mat)
print type(n)
plt.legend()
plt.show()

def Normalize(data):
    minValue = data.min(0)
    maxValue = data.max(0)
    ValueRange = maxValue - minValue
    norm_data = zeros(shape(data))
    k = data.shape[0]
    norm_data = data - tile(minValue, (k, 1))
    norm_data = norm_data / tile(ValueRange, (k, 1))
    return norm_data, ValueRange, minValue

def WebClassTest():
    ratio = 0.1
    dataMat, dataLabels = file2matrix('datingTestSet2.txt') 
    normMat, ValueRange, minValue = Normalize(dataMat)
    k = normMat.shape[0]
    num = int(k * ratio) # test sample : 10%
    errorCount = 0.0
    for i in range(num):
        result = classify(normMat[i,:], normMat[num:k,:],\
                          dataLabels[num:k], 7) # k = 3
        print "The classifier came back with: %d, the real answer is %d"\
                % (result, dataLabels[i])
        if (result != dataLabels[i]): errorCount += 1
    print "The total error rate is %f " % (errorCount / float(num))

WebClassTest()

在程式設計過程中,需要注意list、array、adarray等資料結構的使用,numpy.ndarray和標準Python庫類array.array功能是不相同的。以上程式碼中print type(mat)print type(n) 就是為了觀察各變數的型別。允許以上程式碼,可用畫出散點圖如下:

這裡寫圖片描述

以上散點使用資料集中第二維和第三維資料繪製而出,當然,你可用選擇其他維度的資料畫二維散點圖,或者使用所有維度的資料畫高維圖(未實現),如下圖所示:

這裡寫圖片描述

對約會網站分類的測試,由於分類效果依賴於引數k和測試樣本佔樣本數目的比例,開始測試按照書中的引數進行,取k=3,測試樣本佔總樣本比例為0.1進行測試,結果如下:

這裡寫圖片描述

理論上來說,增大k的取值可以提高準確率,但實際上若k值太大,也會造成準確率下降,而且運算複雜度增大。

k = 7:

這裡寫圖片描述

k = 17:

這裡寫圖片描述

另一方面,降低ratio值(即增大訓練樣本集的比率)也可以提高演算法的準確率,但由於每次演算法需要比較更多的樣本,因此演算法複雜度也會增加。

第二部分是手寫數字識別

首先來看看書本給出的資料集:

def img2vector(filename):
    returnVect = zeros((1,1024))
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0,32*i+j] = int(lineStr[j])
    return returnVect

def handwritingClassTest():
    hwLabels = []
    trainingFileList = listdir('trainingDigits')    #load the training set
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]     # take off .txt
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
    testFileList = listdir('testDigits')        # iterate through the test set
    errorCount = 0.0
    mTest = len(testFileList)
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]     # take off .txt
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
        classifierResult = classify(vectorUnderTest, trainingMat, hwLabels, 3) # k = 3
        print "The classifier came back with: %d, the real answer is: %d"\
        % (classifierResult, classNumStr)
        if (classifierResult != classNumStr): errorCount = errorCount + 1.0
    print "\nThe total number of errors is: %d" % errorCount
    print "\nThe total error rate is: %f" % (errorCount/float(mTest))

handwritingClassTest()

一個結果(k = 3):

這裡寫圖片描述

k = 7時的結果,正確率並不比k = 3時要好:

這裡寫圖片描述

在手寫數字識別過程中,隨著k值得增大,準確率反而降低了。k的取值並不是越大越好。

至此,完成了k-近鄰演算法的學習和例項驗證。比起其他機器學習方法,k-近鄰演算法是最簡單最有效的分類資料演算法,使用演算法時必須有接近實際資料的訓練樣本資料。但是如前一節所說的,該演算法的缺點也很多,最大的一點是無法給出資料的內在含義。事實上k決策樹是k-近鄰演算法的優化版本,比起前者,決策樹有效減少了儲存空間和計算空間的開銷,後期需繼續深入學習!

相關推薦

Python3《機器學習實戰筆記K-近鄰演算法

2.1 實施KNN演算法 python3實現KNN演算法,本書採用的是python2,轉化為python3 import numpy as np #運算子模組 import operator def createDataSet(): group = np

Python3《機器學習實戰》01k-近鄰演算法(完整程式碼及註釋)

執行平臺: Windows Python版本: Python3 IDE: Anaconda3 # -*- coding: utf-8 -*- """ Created on Sun Apr 29 20:32:03 2018 @author: Wang

機器學習實戰學習筆記k-近鄰演算法應用場景

之前學習了k-近鄰演算法的實現後,參考《機器學習實戰》中的例子進行了k-近鄰演算法的測驗,主要測試了針對約會網站和手寫識別系統的資料分類,這兩個測試使用的是《機器學習實戰》提供的資料集。 在編寫函式前,需在.py檔案中新增以下內容: from numpy

機器學習實戰》第二章——k-近鄰演算法——筆記

在看這一章的書之前,在網上跟著博主Jack-Cui的部落格學習過,非常推薦。 部落格地址:http://blog.csdn.net/c406495762  《Python3《機器學習實戰》學習筆記(一):k-近鄰演算法(史詩級乾貨長文)》 講述的非常細緻,文字幽默有趣,演算法細

程式碼註釋機器學習實戰第2章 k-近鄰演算法

寫在開頭的話:在學習《機器學習實戰》的過程中發現書中很多程式碼並沒有註釋,這對新入門的同學是一個挑戰,特此貼出我對程式碼做出的註釋,僅供參考,歡迎指正。 1、匯入資料: #coding:gbk from numpy import * import operator de

機器學習實戰讀書筆記(1)--k鄰近演算法

kNN演算法 kNN演算法概述 kNN演算法和kmeans演算法的比較 knn工作原理: 存在一個樣本資料集合(訓練樣本集),並且每個樣本都具有標籤,輸入新的樣本後,我們將樣本的特徵與訓練樣本集中的資料特徵比較,演算法提取特徵最相似的k個樣本的標籤,採用少數服從多數的

機器學習實戰(一)k-近鄰演算法kNN(k-Nearest Neighbor)

目錄 0. 前言 簡單案例 學習完機器學習實戰的k-近鄰演算法,簡單的做個筆記。文中部分描述屬於個人消化後的理解,僅供參考。 如果這篇文章對你有一點小小的幫助,請給個關注喔~我會非常開心的~ 0. 前言 k-近鄰演算法kNN(k-Neare

機器學習實戰(2)—— k-近鄰演算法

老闆:來了,老弟! 我:來了來了。 老闆:今天你要去看看KNN了,然後我給你安排一個工作! 我:好嘞!就是第二章嗎? 老闆:對!去吧! 可惡的老闆又給我安排任務了! 《機器學習實戰》這本書中的第二章為我們介紹了K-近鄰演算法,這是本書中第一個機器學習演算法,它非常有效而且易於

機器學習實戰(一)--k近鄰演算法

機器學習實戰(一)–k近鄰演算法 最近在學習機器學習,順便做個記錄,一方面給自己加深印象,另一方面與大家共勉,希望能給大家一些幫助,我也是剛入門的新手,有不對的地方還請多多指教。 我用的Python3.5,有些程式碼與書上不太一樣。 程式清單2-1 k-近

機器學習實戰》第二章——K-近鄰演算法

1.K-近鄰演算法(kNN)1.1K-近鄰演算法概述簡單的說,K-近鄰演算法採用測量不同特徵值之間的距離方法進行分類優點:精度高、對異常值不敏感、無資料輸入假定缺點:計算複雜度高、空間複雜度高適用資料範圍:數值型和標稱型1.2KNN演算法原理 存在一個樣本訓練資料集合,並且每

機器學習實戰》——kNN(k近鄰演算法

原作者寫的太好了,包括排版都特別整齊(其中有一個錯誤之處就是在約會網站配對效果判定的時候,列表順序不對,導致結果有誤,這裡我已做出修改)執行平臺: Windows Python版本: Python3.x IDE: Sublime text3一 簡單k-近鄰演算法    本文將

Python3《機器學習實戰學習筆記(一)k-近鄰演算法

**轉載:**http://blog.csdn.net/c406495762執行平臺: WindowsPython版本: Python3.xIDE: Sublime text3 他的個人網站:http://cuijiahua.com   文章目錄

機器學習實戰筆記K-近鄰演算法在約會網站上的應用

K-近鄰演算法概述 簡單的說,K-近鄰演算法採用不同特徵值之間的距離方法進行分類  K-近鄰演算法 優點:精度高、對異常值不敏感、無資料輸入假定。 缺點:計算複雜度高、空間複雜度高。 適用範圍:數值型和標稱型。   k-近鄰演算法的一般流程 收集資料:可使用任何方法

機器學習實戰筆記(一)K-近鄰演算法

一、K-近鄰演算法 1.1 k-近鄰演算法簡介 簡單的說,K-近鄰演算法採用測量不同特徵值之間的距離的方法進行分類。 1.2 原理 存在一個樣本資料集合,也稱作訓練樣本集,並且樣本集中每個資料都存在標籤,即我們知道樣本集中每一資料 與所屬分類的對應關係。輸入沒有標籤的新資料

機器學習實戰學習筆記(一)k-近鄰演算法

k-近鄰演算法 原書中程式碼為python2中語法,python3的語法參考連結:https://blog.csdn.net/c406495762/article/details/75172850 給出k-近鄰演算法的完整程式碼(海倫相親程式) import numpy a

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

一、KNN的工作原理 假設有一個帶有標籤的樣本資料集(訓練樣本集),其中包含每條資料與所屬分類的對應關係。 輸入沒有標籤的新資料後,將新資料的每個特徵與樣本集中資料對應的特徵進行比較。 1) 計算新資料與樣本資料集中每條資料的距離。 2) 對求得的所有距離進

python3.5《機器學習實戰學習筆記(一)k近鄰演算法

轉載請註明作者和出處:http://blog.csdn.net/u013829973 系統版本:window 7 (64bit) python版本:python 3.5 IDE:Spyder (一個比較方便的辦法是安裝anaconda,那麼Spyder和

python3.5《機器學習實戰學習筆記(三)k近鄰演算法scikit-learn實戰手寫體識別

轉載請註明作者和出處:http://blog.csdn.net/u013829973 系統版本:window 7 (64bit) 我的GitHub:https://github.com/weepon python版本:python 3.5 IDE:Spy

Python3《機器學習實戰學習筆記(一)k-近鄰演算法(史詩級乾貨長文)

#一 簡單k-近鄰演算法     本文將從k-鄰近演算法的思想開始講起,使用python3一步一步編寫程式碼進行實戰訓練。並且,我也提供了相應的資料集,對程式碼進行了詳細的註釋。除此之外,本文也對sklearn實現k-鄰近演算法的方法進行了講解。實戰例項:

機器學習實戰學習筆記K近鄰演算法

K近鄰演算法kNN演算法的原理:存在一個樣本資料集合,且每個樣本資料都有對應的標籤,即我們知道樣本集合中每一資料與所屬分類的對應關係。輸入沒有標籤的新資料後,將新資料的每個特徵與樣本集合中資料對應的特徵