本章內容
================================
(一)什么是k-近鄰分類算法
(二)怎樣從文件中解析和導入數據
(三)使用Matplotlib創建擴散圖
(四)對數據進行歸一化
=================================
(一) 什么是k-近鄰分類算法
簡單地說,k-近鄰算法采用測量不同特征值之間的距離方法進行分類,k-近鄰是一種有監督的分類算法。
k-近鄰的工作原理:存在一個樣本數據集,也稱之為訓練樣本集,並且樣本集中的每個數據都存在標簽,即每個樣本所屬的類別。輸入沒有標簽的新數據,將新數據的每個特征與樣本數據集中的每一個數據的特征進行比較,然后提取與新數據最相似的k個樣本數據集,根據這k個樣本數據集的類別標簽,這k個樣本數據中出現最多的類別即為新數據的類別標簽。
舉例:根據表中提供的信息,求最后一部電影的電影類型?下圖是每部電影的打斗鏡頭數、接吻鏡頭數以及電影評估類型

本文結合k-近鄰分類算法的一般步驟,利用python代碼實現。
k-近鄰分類算法的一般步驟:
(1)導入數據
1 from numpy import * 2 import operator 3 4 def createDataSet(): 5 ''' 6 Use two arrays represent the information of chart. 7 ''' 8 group = array([[3,104],[2,100],[1,81],[101,10],[99,5],[98,2]]) 9 label = ['love','love','love','action','action','action'] 10 return group, label
(2)分類器的實現
1 def classify(x, dataSet, label, k): 2 ''' 3 The kNN classifier. 4 ''' 5 6 ''' 7 Compute the distance 8 ''' 9 # shape return [m,n] 10 # m is the row number of the array 11 # n is the column number of the array 12 dataSetSize = dataSet.shape[0] 13 # tile can expand a vector to an array 14 # (dataSetSize, 1) expand row and column 15 # x = [1,3] 16 # print(tile(x,(3,1))) 17 # result [[1,3],[1,3],[1,3]] 18 diffMat = tile(x, (dataSetSize, 1)) - dataSet 19 sqDiffMat = diffMat ** 2 20 # sqDistance is a 1 x m array 21 sqDistance = sqDiffMat.sum(axis=1) 22 distances = sqDistance ** 0.5 23 24 ''' 25 Choose the k samples, according to the distances 26 ''' 27 sortedDistIndicies = distances.argsort() 28 classCount = {} 29 for i in range(k): 30 voteIlabel = label[sortedDistIndicies[i]] 31 classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 32 33 ''' 34 Sort and find the max class 35 ''' 36 sortedClassCount = sorted(classCount.iteritems(), 37 key = operator.itemgetter(1), 38 reverse = True) 39 return sortedClassCount[0][0]
(3)測試新數據
group , labels = createDataSet() x = [18, 90] print(classify(x,group,labels,3))
(4)實驗結果
1 love
===========================================
(二)怎樣從文件中解析和導入數據
一般原始的數據存放在文本文件中,每個樣本占據一行,N個樣本就有N行.每個樣本數據有n個特征,最后一列為樣本的類別。
怎樣將數據從文件中讀取到數組中呢?
1 def file2matrix(filename, n): 2 f = open(filename) 3 arrayOLines = f.readlines() 4 numberOfLines = len(arrayOLines) 5 returnMat = zeros((numberOfLines,n)) 6 classLabelVector = [] 7 index = 0 8 for line in arrayOLines: 9 line = line.strip() 10 listFormLine = line.split('\t') 11 returnMat[index,:] = listFormLine[0:n] 12 classLabelVector.append(int(listFormLine[-1])) 13 index += 1 14 return returnMat, classLabelVector
==========================================
(三)使用Matplotlib創建散點圖分析數據
Matplotlib可以將數據的兩種類型的特征表示在一張2D的圖中。
1 import matplotlib.pyplot as plt 2 from numpy import * 3 datmax = array([[2,3],[4,5]]) 4 plt.scatter(datmax[:,0],datmax[:,1]) 5 plt.xlabel('Feature0') 6 plt.ylabel('Feature1') 7 plt.show()
結果如下:

============================================
(四)歸一化數值
如下圖所示,我們很容易發現,使用歐式距離衡量數據之間的相似度,特數字差值最大的特征對計算結果影響最大,就如下圖,每年獲得的飛行常客里程數這個特征對計算結果的影響遠大於其他兩個特征的影響。若訓練過程中,我們認為每一特征是等權重的。

在處理這種不同取值范圍的特征值時,我們通常采用的方法是將數值歸一化,將取值范圍處理為[0,1]或[-1,1]。
本文以最大最小進行歸一化:
1 from numpy import * 2 3 def autoNorm(dataSet): 4 ''' 5 Use Max-min method to normalize the feature value 6 ''' 7 8 # find the min value of each feature 9 # minVals is a 1 X m (m is the number of feature) 10 minVals = dataSet.min(0) 11 # find the max value of each feature 12 # maxVals is a 1 X m (m is the number of feature) 13 maxVals = dataSet.max(0) 14 ranges = maxVals - minVals 15 normDataSet = zeros(shape(dataSet)) 16 # the number of samples 17 m = dataSet.shape[0] 18 normDataSet = dataSet - tile(minVals,(m,1)) 19 normDataSet = normDataSet / tile(ranges,(m,1))
20 return normDataSet, minVals, ranges
測試數據:
10%作為測試集
90%作為訓練集
1 def datingClassTest(): 2 ''' 3 Test 4 ''' 5 # hold out 10% 6 hoRatio = 0.10 7 # load dataSet file 8 datingDataMat, datingLabels = file2matrix('datingTestSet2.txt') #load data setfrom file 9 normMat, ranges, minVals = autoNorm(datingDataMat) 10 m = normMat.shape[0] 11 numTestVecs = int(m*hoRatio) 12 errorCount = 0.0 13 for i in range(numTestVecs): 14 classifierResult = classify(normMat[i], normMat[numTestVecs:m], datingLabels[numTestVecs:m], 3) 15 if (classifierResult != datingLabels[i]): 16 errorCount += 1.0 17 print ("the total error rate is: %f" % (errorCount/float(numTestVecs))) 18 print errorCount,numTestVecs
===========================================
(五)總結
優點:精度高、對異常值不敏感、無數據輸入假定。
缺點:計算復雜度高、空間復雜度高。
使用數據范圍:數值型和標稱型。
