KNN(K近鄰)演算法的簡單入門
阿新 • • 發佈:2019-01-06
機器學習實戰(第二章:k-近鄰演算法)
今天學習了第二章,在此就我理解做一下簡單的總結,算是加深我的理解和用我自己的語言描述出這個演算法吧。
距離計算
基於向量空間的歐幾里得距離的計算。(L2距離)
特別情況下可採用Lp距離(明氏距離) L1距離。
簡單點來說就是 在一個具有大量樣本集中,每一個例項都具有3個或以上的特徵屬性,其中有一個屬性必然是分類屬性,其餘屬性為數值型屬性(即使是標稱型屬性,也可以通過 某些方法轉變過來),每一個例項都是由屬性特徵值組成的一個向量,一個樣本集就是多個向量組成。
例如下面這個例子
身高 | 體重 | 年齡 | 性別 |
170 | 140 | 22 | 男 |
160 | 100 | 21 | 女 |
“”性別“”可以看成是一個分類屬性,然後其他看特徵屬性 ,組成一個例項向量就為[170,140,22]和[160,100,21]
一、演算法步驟:
1、計算已知類別資料集中的點與當前點之間的距離;
2、按照距離遞增次序排序;
3、選取與當前點距離最小的k個點;
4、確定k個點所在類別的出現頻率;
(K用於選擇最近鄰的數目,K的選擇非常敏感。K值越小意味著模型複雜度越高,從而容易產生過擬合;K值越大則 意味著整體的模型變得簡單,學習的近似誤差會增大,在實際的應用中,一般採用一個比較小的K值,用交叉驗證的 方法,選取一個最優的K值。)
5、返回前k個點出現頻率最高的類別作為當前點的預測分類
二、例子說明(python)
首先按照演算法編寫一個knn演算法類'''
inX:用於分類的輸入向量
dataSet:訓練樣本集
labels:標籤向量
k:用於選擇最近鄰的數目
'''
def classify0(inX,dataSet,labels,k):
#距離計算
dataSetSize = dataSet.shape[0]
diffMat = tile(inX,(dataSetSize,1))-dataSet
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
sortedDistIndicies = distances.argsort()
#按從小到大的排序後的索引值
#選擇距離最小的k個點
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
#排序
sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
舉一個例項說明(手寫識別資料)
資料說明:
我們需要把每一個樣本資料轉變成向量的格式,由於圖片是32X32的txt文字格式存在,我們轉變成1X1024的向量,並把所有的訓練樣本儲存為一個矩陣,對應的每一行就是每一個例項。
#把一個32X32的變成1X1024的向量
def img2vector(filename):
returnVec = zeros((1,1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVec[0,32*i+j] = int(lineStr[j])
return returnVec
運用我們事先寫好的knn演算法類,按照格式代進去訓練並且計算錯誤率。
def handwritingClassTest():
hwLabels = []
#獲取訓練集
trainingFileList = os.listdir('digits//trainingDigits') #獲取該目錄下所有檔名 型別:list
m = len(trainingFileList)
trainingMat = zeros((m,1024))
for i in range(m):
fileNameStr = trainingFileList[i] #7_173.txt
fileStr = fileNameStr.split('.')[0] #'7_173' 'txt'
classNumStr = int(fileStr.split('_')[0]) #7 173
hwLabels.append(classNumStr)
trainingMat[i,:] = img2vector("digits//trainingDigits//"+fileNameStr)
#獲取測試集
testFileList = os.listdir("digits//testDigits")
errorCount = 0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0] # '7_173' 'txt'
classNumStr = int(fileStr.split('_')[0]) # 7 173
vectorUnderTest = img2vector("digits//testDigits//"+fileNameStr)
classifierResult = classify0(vectorUnderTest,trainingMat,hwLabels,3)
print("the classifier came back with: %d,the real answer is: %d"%(classifierResult,classNumStr))
if classifierResult != classNumStr:
errorCount += 1
print "the total number of errors is:%d" %errorCount
print "the total error rate is:%f" %(errorCount/float(mTest))
總結:
優點
1.精度高
2.對異常值不敏感
3.沒有對資料的分佈假設
缺點
1、knn演算法不像其他演算法有一個訓練的過程
2、knn演算法針對那些分類不均勻的分類訓練樣本可能誤差較大
3、計算量太大,每一個待測測試樣本都要遍歷一遍訓練樣本來計算距離
4、我們無法知曉例項樣本和典型例項樣本具有什麼特徵,無法給出任何資料的基礎結構資訊