1. 程式人生 > >機器學習之K-近鄰(KNN)算法

機器學習之K-近鄰(KNN)算法

實戰 http created 以及 dex mda 問題 可以轉化 占比

一 . K-近鄰算法(KNN)概述

最簡單最初級的分類器是將全部的訓練數據所對應的類別都記錄下來,當測試對象的屬性和某個訓練對象的屬性完全匹配時,便可以對其進行分類。但是怎麽可能所有測試對象都會找到與之完全匹配的訓練對象呢,其次就是存在一個測試對象同時與多個訓練對象匹配,導致一個訓練對象被分到了多個類的問題,基於這些問題呢,就產生了KNN。

KNN是通過測量不同特征值之間的距離進行分類。它的思路是:如果一個樣本在特征空間中的k個最相似(即特征空間中最鄰近)的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別,其中K通常是不大於20的整數。KNN算法中,所選擇的鄰居都是已經正確分類的對象。該方法在定類決策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。

下面通過一個簡單的例子說明一下:如下圖,綠色圓要被決定賦予哪個類,是紅色三角形還是藍色四方形?如果K=3,由於紅色三角形所占比例為2/3,綠色圓將被賦予紅色三角形那個類,如果K=5,由於藍色四方形比例為3/5,因此綠色圓被賦予藍色四方形類。

技術分享圖片

由此也說明了KNN算法的結果很大程度取決於K的選擇。

在KNN中,通過計算對象間距離來作為各個對象之間的非相似性指標,避免了對象之間的匹配問題,在這裏距離一般使用歐氏距離或曼哈頓距離:

技術分享圖片

同時,KNN通過依據k個對象中占優的類別進行決策,而不是單一的對象類別決策。這兩點就是KNN算法的優勢。

接下來對KNN算法的思想總結一下:就是在訓練集中數據和標簽已知的情況下,輸入測試數據,將測試數據的特征與訓練集中對應的特征進行相互比較,找到訓練集中與之最為相似的前K個數據,則該測試數據對應的類別就是K個數據中出現次數最多的那個分類,其算法的描述為:

1)計算測試數據與各個訓練數據之間的距離;

2)按照距離的遞增關系進行排序;

3)選取距離最小的K個點;

4)確定前K個點所在類別的出現頻率;

5)返回前K個點中出現頻率最高的類別作為測試數據的預測分類。

二 .python實現

首先呢,需要說明的是我用的是python3.4.3,裏面有一些用法與2.7還是有些出入。

建立一個KNN.py文件對算法的可行性進行驗證,如下:

技術分享圖片
#coding:utf-8

from numpy import *
import operator

##給出訓練數據以及對應的類別
def createDataSet():
    group = array([[1.0,2.0],[1.2,0.1],[0.1,1.4],[0.3,3.5]])
    labels = [A,A,B,B]
    return group,labels

###通過KNN進行分類
def classify(input,dataSe t,label,k):
    dataSize = dataSet.shape[0]
    ####計算歐式距離
    diff = tile(input,(dataSize,1)) - dataSet
    sqdiff = diff ** 2
    squareDist = sum(sqdiff,axis = 1)###行向量分別相加,從而得到新的一個行向量
    dist = squareDist ** 0.5
    
    ##對距離進行排序
    sortedDistIndex = argsort(dist)##argsort()根據元素的值從大到小對元素進行排序,返回下標

    classCount={}
    for i in range(k):
        voteLabel = label[sortedDistIndex[i]]
        ###對選取的K個樣本所屬的類別個數進行統計
        classCount[voteLabel] = classCount.get(voteLabel,0) + 1
    ###選取出現的類別次數最多的類別
    maxCount = 0
    for key,value in classCount.items():
        if value > maxCount:
            maxCount = value
            classes = key

    return classes
View Code

接下來,在命令行窗口或新建一個python文件輸入如下代碼:

技術分享圖片
#-*-coding:utf-8 -*-
import sys
sys.path.append("...文件路徑...")
import KNN
from numpy import *
dataSet,labels = KNN.createDataSet()
input = array([1.1,0.3])
K = 3
output = KNN.classify(input,dataSet,labels,K)
print("測試數據為:",input,"分類結果為:",output)
View Code

回車之後的結果為:

測試數據為: [ 1.1 0.3] 分類為: A

答案符合我們的預期,要證明算法的準確性,勢必還需要通過處理復雜問題進行驗證,之後另行說明。

三 實戰

之前,對KNN進行了一個簡單的驗證,今天我們使用KNN改進約會網站的效果,個人理解,這個問題也可以轉化為其它的比如各個網站迎合客戶的喜好所作出的推薦之類的,當然,今天的這個例子功能也實在有限。

在這裏根據一個人收集的約會數據,根據主要的樣本特征以及得到的分類,對一些未知類別的數據進行分類,大致就是這樣。

我使用的是python 3.4.3,首先建立一個文件,例如date.py,具體的代碼如下:

技術分享圖片
#coding:utf-8

from numpy import *
import operator
from collections import Counter
import matplotlib
import matplotlib.pyplot as plt


###導入特征數據
def file2matrix(filename):
    fr = open(filename)
    contain = fr.readlines()###讀取文件的所有內容
    count = len(contain)
    returnMat = zeros((count,3))
    classLabelVector = []
    index = 0
    for line in contain:
        line = line.strip() ###截取所有的回車字符
        listFromLine = line.split(\t)
        returnMat[index,:] = listFromLine[0:3]###選取前三個元素,存儲在特征矩陣中
        classLabelVector.append(listFromLine[-1])###將列表的最後一列存儲到向量classLabelVector中
        index += 1
    
    ##將列表的最後一列由字符串轉化為數字,便於以後的計算
    dictClassLabel = Counter(classLabelVector)
    classLabel = []
    kind = list(dictClassLabel)
    for item in classLabelVector:
        if item == kind[0]:
            item = 1
        elif item == kind[1]:
            item = 2
        else:
            item = 3
        classLabel.append(item)
    return returnMat,classLabel#####將文本中的數據導入到列表

##繪圖(可以直觀的表示出各特征對分類結果的影響程度)
datingDataMat,datingLabels = file2matrix(D:\python\Mechine learing in Action\KNN\datingTestSet.txt)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*array(datingLabels),15.0*array(datingLabels))
plt.show()

## 歸一化數據,保證特征等權重
def autoNorm(dataSet):
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))##建立與dataSet結構一樣的矩陣
    m = dataSet.shape[0]
    for i in range(1,m):
        normDataSet[i,:] = (dataSet[i,:] - minVals) / ranges
    return normDataSet,ranges,minVals

##KNN算法
def classify(input,dataSet,label,k):
    dataSize = dataSet.shape[0]
    ####計算歐式距離
    diff = tile(input,(dataSize,1)) - dataSet
    sqdiff = diff ** 2
    squareDist = sum(sqdiff,axis = 1)###行向量分別相加,從而得到新的一個行向量
    dist = squareDist ** 0.5
    
    ##對距離進行排序
    sortedDistIndex = argsort(dist)##argsort()根據元素的值從大到小對元素進行排序,返回下標

    classCount={}
    for i in range(k):
        voteLabel = label[sortedDistIndex[i]]
        ###對選取的K個樣本所屬的類別個數進行統計
        classCount[voteLabel] = classCount.get(voteLabel,0) + 1
    ###選取出現的類別次數最多的類別
    maxCount = 0
    for key,value in classCount.items():
        if value > maxCount:
            maxCount = value
            classes = key
    return classes

##測試(選取10%測試)
def datingTest():
    rate = 0.10
    datingDataMat,datingLabels = file2matrix(D:\python\Mechine learing in Action\KNN\datingTestSet.txt)
    normMat,ranges,minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]
    testNum = int(m * rate)
    errorCount = 0.0
    for i in range(1,testNum):
        classifyResult = classify(normMat[i,:],normMat[testNum:m,:],datingLabels[testNum:m],3)
        print("分類後的結果為:,", classifyResult)
        print("原結果為:",datingLabels[i])
        if(classifyResult != datingLabels[i]):
                                  errorCount += 1.0
    print("誤分率為:",(errorCount/float(testNum)))
                                  
###預測函數
def classifyPerson():
    resultList = [一點也不喜歡,有一丟丟喜歡,灰常喜歡]
    percentTats = float(input("玩視頻所占的時間比?"))
    miles = float(input("每年獲得的飛行常客裏程數?"))
    iceCream = float(input("每周所消費的冰淇淋公升數?"))
    datingDataMat,datingLabels = file2matrix(D:\python\Mechine learing in Action\KNN\datingTestSet2.txt)
    normMat,ranges,minVals = autoNorm(datingDataMat)
    inArr = array([miles,percentTats,iceCream])
    classifierResult = classify((inArr-minVals)/ranges,normMat,datingLabels,3)
    print("你對這個人的喜歡程度:",resultList[classifierResult - 1])
View Code

新建test.py文件了解程序的運行結果,代碼:

技術分享圖片
#coding:utf-8

from numpy import *
import operator
from collections import Counter
import matplotlib
import matplotlib.pyplot as plt

import sys
sys.path.append("D:\python\Mechine learing in Action\KNN")
import date
date.classifyPerson()
View Code

運行結果如下圖:

技術分享圖片

機器學習之K-近鄰(KNN)算法