K近鄰算法


K-近鄰算法(KNN)是分類數據最簡單最有效的算法。

核心思想

采用不同特征值之間的距離方法進行分類
首先:

我們有一個樣本集(也稱訓練樣本集),樣本中的每個數據都存在標簽,即樣本集中每一個數據對應與所屬分類的對應關系。

之后:

輸入沒有標簽的新數據時,將新數據的每個特征與樣本集中數據的特征進行比較,(一般是計算歐氏距離)然后算法提取樣本集中特征最相近數據(最近鄰)的分類標簽

附:一本只選擇樣本數據集中前K個最相近的數據,這就是k近鄰中的k。k一般不超過20的整數

KNN算法的過程為:

  • 選擇一種距離計算方式, 通過數據所有的特征計算新數據與已知類別數據集中的數據點的距離
  • 按照距離遞增次序進行排序,選取與當前距離最小的k個點
  • 對于離散分類,返回k個點出現頻率最多的類別作預測分類;對于回歸則返回k個點的加權值作為預測值

kNN的優缺點

優點:簡單有效
缺點:
一是必須有接近實際數據的訓練樣本數據,且要保存全部數據集,占用存儲空間且計算耗時;
二是無法給出任何數據的急促結構信息,無法知曉平均實例樣本和典型實例樣本具有什么特征。使用概率測量方法可以解決這個問題

算法實例

創建kNN.py
(1)創建數據集

#創造數據集
def createDataSet():
    group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
    labels = ['A', 'A', 'B', 'B']
    return group, labels

有四個數據,其標簽分別為(A,A,B,B)
(2) 構照kNN分類器

#第一個kNN分類器  
#inX-測試數據 dataSet-樣本數據  labels-標簽 k-鄰近的k個樣本
def classify0(inX,dataSet,labels,k):  
    dataSetSize = dataSet.shape[0]  #dataSet.shape[0]是第一維的數目    
    '''
    計算與所有點的距離,并進行排序
    '''
    diffMat = tile(inX,(dataSetSize,1)) - dataSet #要分類的新數據與原始數據做差 
    sqDiffMat = diffMat**2  #求差的平方  
    sqDistance = sqDiffMat.sum(axis=1)  #求差的平方的和    
    distances = sqDistance**0.5 #求標準差   
    sortDistIndicies = distances.argsort() #距離排序    
    classCount = {}  #定義元字典   
    '''
    遍歷前k個元素,選擇距離最小的k個點
    '''
    for i in range(k):  
        voteIlabel = labels[sortDistIndicies[i]]  #獲得前k個元素的標簽 
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1#計算前k個數據標簽出現的次數   
    '''
    排序
    '''
    sortedClassCount =sorted(classCount.iteritems(),key = operator.itemgetter(1),reverse = True) #對得到的標簽字典按降序排列   
    return sortedClassCount[0][0] #返回出現次數最多的標簽  

結果測試

group, labels = kNN.createDataSet( )
kNN.classfy0([0,0],group,labels,3)

結果為B

(3)讀取文本文件中的數據

def file2matrix(filename):

    fr = open(filename)# 打開文件
    numberOfLines = len(fr.readlines()) # 計算文本文件的行數
    returnMat = zeros((numberOfLines,3))# 創建返回的數據矩陣
    classLabelVector = []# 創建類標簽
    fr = open(filename) # 打開文件
    index = 0 # 定義索引
    # 讀取文件的每一行并處理
    for line in fr.readlines():
        line = line.strip()# 去除行的尾部的換行符
        listFromLine = line.split('\t') # 將一行數據按空進行分割
        returnMat[index,:] = listFromLine[0:3] # 0:3列為數據集的數據
        classLabelVector.append((listFromLine[-1])) # 最后一列為數據的分類標簽
        index += 1# 索引加1
   
    return returnMat,classLabelVector # 返回數據集和對應的類標簽

(4)顯示散點圖

import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(111)
datingDataMat,datingLabels = kNN.file2matrix('datingTestSet.txt')
#ax.scatter(datingDataMat[:,1], datingDataMat[:,2])

ax1.scatter(datingDataMat[:, 1], datingDataMat[:, 2], 15.0*array(datingLabels), 15.0*array(datingLabels))

ax.axis([-2, 25, -0.2, 2.0])
plt.xlabel(u"玩游戲視頻所耗時間百分比")
plt.ylabel(u"每周消費的冰淇淋公升數")
plt.show()

(5)歸一化數值
為了防止特征值數量的差異對預測結果的影響(比如計算距離,量值較大的特征值影響肯定很大),我們將所有的特征值都歸一化到[0,1]

def autoNorm(dataSet):
    minVals = dataSet.min(0) # 求數據矩陣每一列的最小值
    maxVals = dataSet.max(0)# 求數據矩陣每一列的最大值
    ranges = maxVals - minVals# 求數據矩陣每一列的最大最小值差值
    #normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0] # 返回數據矩陣第一維的數目
    normDataSet = dataSet - tile(minVals, (m, 1)) # 求矩陣每一列減去該列最小值,得出差值
    normDataSet = normDataSet / tile(ranges, (m, 1)) # 用求的差值除以最大最小值差值,即數據的變化范圍,即歸一化
    return normDataSet, ranges, minVals # 返回歸一化后的數據,最大最小值差值,最小值

附:numpy函數小結

#coding=utf-8
__author__ = 'Administrator'
from numpy import *

a = array([[0, 1, 0], [1, 1, 2]])
print a

aSize = a.shape[0] #可以認為是輸出列數
print aSize

b = arange(7, dtype=uint16) #dtype為數據類型對象
print b

'''
tile
將數組a重復n次
'''
c = array([0, 1])
d = tile(c, (3, 1))
print d

c = zeros((3, 1), dtype=int)
print c

輸出結果

[[0 1 0]
[1 1 2]]
2
[0 1 2 3 4 5 6]
[[0 1]
[0 1]
[0 1]]
[[0]
[0]
[0]]

參考文獻:

http://www.aichengxu.com/yejie/512129.htm
http://blog.csdn.net/quincuntial/article/details/50471423
http://blog.csdn.net/suipingsp/article/details/41964713

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容