K-近鄰算法
機器學習與實戰是對《機器學習實戰》這本書的學習總結。
一:k-近鄰算法分析
簡單說,k-近鄰算法採用測量不同特徵值之間的舉例方法進行分類。
工作原理:存在一個樣本數據集合,也稱訓練樣本集,並且樣本集中每個數據都存在標籤,即我們知道樣本集中每一數據與所屬分類對應的關係。輸入沒有標籤的新數據後,將新數據的每個特徵與樣本集中數據對應的特徵進行比較,然後算法提取樣本集中特徵最相似的數據(最近鄰)的分類標籤。一般來說,我們只選擇樣本數據集中前k個最相似的數據,這就是k-近鄰算法k的出處,通常k是不大於20的整數。最後,選擇k個最相似數據中出現次數最多的分類,做爲新數據的標籤。
二:示例
注:示例中用的Numpy,Matplotlib等請自行網上下載安裝
示例1
from numpy import *
import operator
#創建數據集
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
#分類
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
#計算歐式距離
# tile(A, reps): 構造一個數據,重複 A reps 次
diffMat = tile(inX, (dataSetSize,1)) - dataSet # Subtract element-wise
sqDiffMat = diffMat**2 # 平方
sqDistances = sqDiffMat.sum(axis=1)# sum is performed by row
distances = sqDistances**0.5
# argsort() 升序方式排序,返回索引值
sortedDistIndicies = distances.argsort()
classCount = {} # 定義一個字典,可以追加元素
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
## 計算 label 出現的次數 ,如果沒有返回0
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
#返回最大值的類
maxCount = 0
for key, value in classCount.items():
if value > maxCount:
maxCount = value
maxIndex = key
return maxIndex
歐式距離公式:計算兩個向量A(x0,y0),B(x1,y1)的距離
測試:
group,labels = kNN.createDataSet();
kNN.classify0([0,0],group, labels, 3)
結果:
示例2 使用k-近鄰算法改進約會網站的配對效果
1、將文本記錄轉換爲NumPy的解析程序
def file2Matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines)#獲得行數
returnMat = zeros((numberOfLines,3))#創建一個相同行,3列的矩陣
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()#截取掉所有的回車字符
listFormLine = line.split('\t')#將整行數據分割成一個元素列表
returnMat[index,:] = listFormLine[0:3]#每行取前3個元素
classLabelVector.append(int(listFormLine[-1]))#將每行的最後一列的元素,添加到向量中
index +=1
return returnMat,classLabelVector
2、使用Matplotlib創建散點圖
from numpy import *
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import kNN
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15*array(datingLabels),15*array(datingLabels))
plt.show()
結果如下圖:
3、歸一化數值 數值的屬性對計算結果影響很大,因此在處理不同取值範圍的特徵值時,通常採用的方法是將數值歸一化。 將任意取值範圍的數值轉化爲0到1區間內:
newValue = (oldValue - min)/(man - min)
def autoNorm(dataSet):
minVals = dataSet.min(0)#每列的最小值
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))#創建和dataSet同樣維度的矩陣
m = dataSet.shape[0]#獲取dataSet的列數
normDataSet = dataSet - tile(minVals,(m,1)) #矩陣對應元素相減
normDataSet = dataSet / tile(ranges,(m,1))
return normDataSet, ranges, minVals
4、驗證分類器
#創建測試代碼, 10%用來測試
def datingClassTest():
hoRatio = 0.10 #10%
datingDataMat,datingLabels = file2Matrix('datingTestSet2.txt')
normMat,ranges,minVals = autoNorm(datingDataMat)
m = normMat.shape[0] # Matrix normMat's row number is m
numTestVecs = int(m * hoRatio)
errorCount = 0.0
for i in range(numTestVecs):
classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
print "the classifier came back with: %d , the real answer is: %d" %(classifierResult,datingLabels[i])
if(classifierResult != datingLabels[i]): errorCount +=1.0
print "the total error rate is : %f" %(errorCount/float(numTestVecs))
測試:kNN.datingClassTest()
測試結果
the classifier came back with: 1 , the real answer is: 1
the classifier came back with: 2 , the real answer is: 2
the classifier came back with: 1 , the real answer is: 1
the classifier came back with: 3 , the real answer is: 3
the classifier came back with: 3 , the real answer is: 3
the classifier came back with: 2 , the real answer is: 2
the classifier came back with: 1 , the real answer is: 1
the classifier came back with: 3 , the real answer is: 1
the total error rate is : 0.050000
示例3:手寫識別系統
#將一個filename中矩陣轉化爲一個向量
def img2vector(filename):
returnVect = zeros((1,1024)) #定義一個1行1024列的矩陣
fr = open(filename)
for i in range(32): #共32 行
lineStr = fr.readline() #讀一行
for j in range(32): #讀一個值
returnVect[0,32*i+j] = int(lineStr[j])
return returnVect
def handWritingClassTest():
hwLabels = [] #定義一個列表
trainingFileList = listdir('trainingDigits') #打開訓練集目錄,獲取目錄(trainingDigits)的內容
m = len(trainingFileList) #目錄中文件個數
trainingMat = zeros((m,1024)) #定義一個m行1024列的矩陣
for i in range(m):
fileNameStr = trainingFileList[i] #第i個文件名
fileStr = fileNameStr.split('.')[0] #以“.”分割文件名,取前面的部分
classNumStr = int(fileStr.split('_')[0])#以“-”分割文件名,取前面的部分
hwLabels.append(classNumStr) #將改文件代表的數字,添加到列表中
trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
testFileList = listdir('testDigits')#打開測試集目錄
errorCount = 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): errorCount += 1.0
print "\n the total number of errors is : %d " % errorCount
print "\n the total error rate is : %f " % (errorCount / float(mTest))
源代碼混合數據下載地址
(End)