KNN算法可以說是機器學習分類中最簡單的一種算法了,KNN算法的工作原理是:存在一個樣本數據集,也稱訓練樣本集,在這個樣本集中每個數據都存在其對應的標籤,即我們知道樣本集中每一數據與所屬分類的對應關係。當我們輸入需要預測的數據時,我們將預測數據的每個特徵與樣本集中對應的特徵進行比較,然後提取樣本集中特徵最相似數據(最近鄰)的分類標籤。一般來說,我們只選擇樣本數據集中前K個最相似的數據,這就是KNN算法。通常來說我們的K都是不大於20的整數。最後我們選擇K個最相似數據中出現次數最多的分類,作爲預測數據的分類。
下面我們用python來實現KNN算法
'''
KNN算法(k-近鄰算法)實習步驟(僞代碼)如下:
對未知類別屬性的數據集中的點與當前點之間的距離執行以下操作:
1.計算已知類別數據集中的點與當前點之間的距離
2.按照距離遞增次序排序
3.選取與當前點距離最小的k個點
4.確定前k個點所在類別的出現頻率
5.返回前k個點出現頻率最高的類別作爲當前點的預測分類
計算距離時我們使用歐式距離公式
'''
# inX:用於分類的向量X(即需要預測數據), dataSet:輸入的訓練樣本集, labels:標籤向量, k:用於選擇最近鄰居的數目
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = tile(inX, (dataSetSize, 1)) - dataSet # tile()方法用於將輸入的預測數據擴展至於訓練樣本集同樣大小
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1) # axis=1 表示按列相加 即每行的所有列加一起求和
distance = sqDistances**0.5
# 按照升序進行快速排序,返回的是原數組的下標。
# 比如,x = [30, 10, 20, 40]
# 升序排序後應該是[10,20,30,40],他們的原下標是[1,2,0,3]
# 那麼,numpy.argsort(x) = [1, 2, 0, 3]
sortedDistIndicies = distance.argsort() # 在這裏就相當於告訴了每行數據(即每個數據點)離預測數據點是第幾近
classCount={}
# 上面是距離的計算,,下面是選擇距離最小的k個點
# 投票過程,就是統計前k個最近的樣本所屬類別包含的樣本個數
for i in range(k):
# index = sortedDistIndicies[i]是第i個最相近的樣本下標
# voteIlabel = labels[index]是樣本index對應的分類結果('A' or 'B')
voteIlabel = labels[sortedDistIndicies[i]]
# classCount.get(voteIlabel, 0)返回voteIlabel的值,如果不存在,則返回0
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # 排序
return sortedClassCount[0][0] # 返回第一近的數據點類別
下面我們使用KNN算法來進行手寫數字的識別,當然我們對於數據進行了預處理。手寫數字集來自www.manning.com/MachineLearninginAction中的CH02文件夾下的digits,zip
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 = os.listdir('trainingDigits') # 獲取目錄內容
m = len(trainingFileList)
# print(m)
trainingMat = zeros((m, 1024))
# 從文件名解析分類數字
for i in range(m):
fileNameStr = trainingFileList[i]
# print(fileNameStr)
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr)
testFileList = os.listdir("testDigits")
errcount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
print("The classifier came back with: %d, the real answer is :%d" % (classifierResult, classNumStr))
if (classifierResult != classNumStr):
errcount += 1
print("\nthe total number of erros is :%d" % errcount)
print("\nthe total error rate is : %f" % (errcount/float(mTest)))
總結
KNN算法是分類數據最簡單最有效的算法,KNN算法是基於實例的學習方法,使用算法時我們必須有接近實際數據的訓練樣本數據。KNN算法必須保存全部數據集,如果訓練數據集很大,必須使用大量的儲存空間。此外,由於必須對數據集中的每個數據計算距離值,所以實際用時會非常耗時。
KNN算法的另一個缺陷是它無法給出任何數據的基礎結構信息,因此我們無法知曉平均實例樣本和典型實例樣本具有什麼特徵