參考書籍《機(jī)器學(xué)習(xí)實戰(zhàn)》

圖片.png
舉例說明:
以二維數(shù)據(jù)簡單舉例:
已知數(shù)據(jù)集中含有 x1(1,1) x2(0,1)為A類,x3(1,0),x4(10,10) 為B類
判斷x5(2,2) 為哪一類。
方法:定k等于3,
分別計算x5與x1、x2、x3、x4的距離,可得出前k個離x5最近的點(diǎn)是x1,x2,x3。其中A類的有兩個,B類的有一個,因此判斷x5屬于A類
python中代碼實現(xiàn)
def classify0(x,dataSet,labels,k):#定義kNN算法
dataSetSize = dataSet.shape[0] #獲取數(shù)據(jù)集的行數(shù),即有多少個數(shù)
diffMat = np.tile(x,(dataSetSize,1))-dataSet #將要判斷類型的數(shù)據(jù)x,轉(zhuǎn)化成和數(shù)據(jù)集
#同樣結(jié)構(gòu),并求出和數(shù)據(jù)集的差(想像坐標(biāo)系中兩個二維點(diǎn)的x、y之差)
sqDiffMat = diffMat ** 2 #求x與數(shù)據(jù)集每個點(diǎn)差的平方(x差和y差的平方)
sqDistances = sqDiffMat.sum(axis=1) #求出x與數(shù)據(jù)集每個點(diǎn)的差方和(x差的平方+y差的平方)
distances = sqDistances ** 0.5 #求平方根(勾股定理),即為兩點(diǎn)之間的距離
sorteDistIndicies = distances.argsort() #返回distances中數(shù)值從小到大對應(yīng)的索引值
classCount = {} #統(tǒng)計類型,關(guān)鍵字為類型,值為類型的數(shù)量
for i in range(k): #從前k個最相近的判斷類型
voteIlabel = labels[sorteDistIndicies[i]] #取出類型
classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),
reverse=True)
#classCount.items()將字典轉(zhuǎn)為元組,并按照key指定的方式進(jìn)行排序,reverse為True,則為
#倒序,operator.itemgetter(1)是指按照元組索引為1的值進(jìn)行排序
return sortedClassCount[0][0] #取出排序后第一個元素的類型
以上即為kNN算法的python偽代碼
利用以上算法,完成書中的示例:
示例一:約會類型預(yù)測
首先來測試下錯誤率
file = 'datingTestSet2.txt'
def file2matrix(filename):#定義讀取文件函數(shù)
f = open(filename)
filelist = []
for i in f.readlines():
a,b,c,d = i.strip().split('\t')
filelist.append([a]+[b]+[c]+[d]) #將讀取到的信息以列表的形式存入列表
f.close()
filearray = np.array(filelist) #轉(zhuǎn)化為np.ndarry格式(向量格式)
returnMat = filearray[:,:-1] #構(gòu)建出數(shù)據(jù)集
classLabelVector = filearray[:,-1] #數(shù)據(jù)集對應(yīng)的類型
return returnMat,classLabelVector
def autoNorm(dataSet):#定義歸一化函數(shù)
ranges = dataSet.astype(float).max(axis=0)-dataSet.astype(float).min(axis=0)
#這里需要留意,數(shù)據(jù)的類型必須是數(shù)值型的才能參與計算
minVals = dataSet.astype(float).min(axis=0)
normDataSet = (dataSet.astype(float)-minVals)/ranges
return normDataSet,ranges,minVals
def datingClassTest(file): #定義檢驗函數(shù)
p = 0.1
datingDataMat,datingLabels = file2matrix(file)#讀取數(shù)據(jù)集
norMat,ranges,minVals = autoNorm(datingDataMat)#對數(shù)據(jù)集進(jìn)行歸一化
numTestVecs = int(len(norMat)*p) #取10%的作為測試集
errorCount = 0
for i in range(numTestVecs):
result = classify0(norMat[i,:],norMat[numTestVecs:,:],
datingLabels[numTestVecs:],3) #norMat從0到numTestVecs
#的為測試數(shù)據(jù),后面的為樣本集
print('the result is {},real answer is :{}'.format(result,datingLabels[i]))#輸出判斷過程
if result != datingLabels[i]:
errorCount += 1
print('the total error tate is {}'.format(errorCount/numTestVecs))#輸出最終錯誤率
print(datingClassTest(file))
錯誤率很低,可以用來進(jìn)行預(yù)判
def classifyPerson(file):#定義用戶使用函數(shù)
resultList = ['not at all','in small doses','in large doses'] #類型列表
ffMiles = float(input('輸入每年獲取的飛行??屠锍虜?shù):'))
percentTats = float(input('輸入玩視頻游戲所耗時間百分比:'))
iceCream = float(input('輸入每周消費(fèi)的冰淇淋公升數(shù):'))
inArr = np.array([ffMiles,percentTats,iceCream]) #將輸入的新數(shù)據(jù)轉(zhuǎn)化為向量格式
#注意順序要和數(shù)據(jù)集中的順序一致,即特征要對應(yīng)上
datingDataMat,datingLabels = file2matrix(file)
norMat,ranges,minVals = autoNorm(datingDataMat)
norinArr = (inArr-minVals)/ranges #將新數(shù)據(jù)進(jìn)行歸一化
result = classify0(norinArr,norMat,datingLabels,3)
print('該對象的類別是:{}'.format(resultList[result-1]))#-1是因為這里使用索引匹配
classifyPerson(file)
示例二:手寫識別系統(tǒng)
filepath1 = 'digits/trainingDigits/' #這個為數(shù)據(jù)集目錄
filepath2 = '/digits/testDigits/' #這個為測試數(shù)據(jù)目錄
def img2vector(file): #讀取文檔,并轉(zhuǎn)化為向量
returnVect = np.zeros((1,1024))#確保每一行是一個完整的數(shù)據(jù),因此將原維度32*32的數(shù)據(jù)改為維度是1*1024
num = 0
f = open(file)
for i in f.readlines():
ilen = int(len(i.strip()))
returnVect[:,num:num+ilen] = list(i.strip())#以切片方式寫入數(shù)據(jù)
num += ilen
f.close()
return returnVect
def readfile(path):#創(chuàng)建數(shù)據(jù)集及類別
filelist = os.listdir(path)
trainingMat = np.zeros((len(filelist),1024))#創(chuàng)建數(shù)據(jù)集的維度
hwLabels = []
num = 0
for i in filelist:
Vect = img2vector(path+i)
classNumstr = int(i.strip().split('_')[0])
trainingMat[num,:] = Vect #按行循環(huán)寫入數(shù)據(jù)
hwLabels.append(classNumstr)#將類別添加進(jìn)列表
num += 1
return trainingMat,hwLabels
def handwritingClassTest(file1,file2):
trainingMat,hwLabels = readfile(filepath1)#創(chuàng)建數(shù)據(jù)集
errorCount = 0
for i in os.listdir(filepath2):
vectorTest = img2vector(filepath2+i)#讀取測試數(shù)據(jù)
classNumstr = int(i.strip().split('_')[0])
result = classify0(vectorTest,trainingMat,hwLabels,3)
print('the result is {},real answer is :{}'.format(result,classNumstr))
if int(result) != classNumstr:
errorCount += 1
print('the total error tate is {}'.format(errorCount/len(os.listdir(filepath2))))
handwritingClassTest(filepath1,filepath2)