机器学习实战(笔记)------------KNN算法
1.KNN算法
KNN算法即K-臨近算法,采用測(cè)量不同特征值之間的距離的方法進(jìn)行分類。
以二維情況舉例:
? ? ? ? 假設(shè)一條樣本含有兩個(gè)特征。將這兩種特征進(jìn)行數(shù)值化,我們就可以假設(shè)這兩種特種分別為二維坐標(biāo)系中的橫軸和縱軸,將一個(gè)樣本以點(diǎn)的形式表示在坐標(biāo)系中。這樣,兩個(gè)樣本直接變產(chǎn)生了空間距離,假設(shè)兩點(diǎn)之間越接近越可能屬于同一類的樣本。如果我們有一個(gè)待分類數(shù)據(jù),我們計(jì)算該點(diǎn)與樣本庫(kù)中的所有點(diǎn)的距離,取前K個(gè)距離最近的點(diǎn),以這K個(gè)中出現(xiàn)次數(shù)最多的分類作為待分類樣本的分類。這樣就是KNN算法。
優(yōu)點(diǎn):精度高,對(duì)異常值不敏感,無數(shù)據(jù)輸入假定
缺點(diǎn):時(shí)間、空間復(fù)雜度太大(比如每一次分類都需要計(jì)算所有樣本點(diǎn)與測(cè)試點(diǎn)的距離)
2.KNN算法的Python實(shí)現(xiàn)
import operator from os import listdirimport matplotlib import matplotlib.pyplot as plt from numpy import array, shape, tile, zeros#分類方法 #inx 待分類向量 #dataSet 測(cè)試數(shù)據(jù) #labels 測(cè)試數(shù)據(jù)標(biāo)簽 #k 取前k個(gè)作為樣本 def classify(inX,dataSet,labels,k):dataSetSize=dataSet.shape[0]diffMat=tile(inX,(dataSetSize,1))-dataSet #tile方法利用輸入數(shù)組進(jìn)行擴(kuò)充sqDiffMat=diffMat**2sqDistance=sqDiffMat.sum(axis=1)distance=sqDistance**0.5index=distance.argsort() #返回按從小到大的順序排序后的元素下標(biāo)classCount={}for i in range(k):lable=labels[index[i]]classCount[lable]=classCount.get(lable,0)+1#在python3中dict.iteritems()被廢棄sortedClasssCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)return sortedClasssCount[0][0]????代碼傳入的三個(gè)參數(shù)分別為待分類向量,測(cè)試數(shù)據(jù),測(cè)試數(shù)據(jù)標(biāo)簽。代碼使用歐式距離公式計(jì)算向量點(diǎn)之間的距離。
\[ d=\sqrt{(xA_0-xB_0)^2-(xA_1-xB_1)^2} \]
numpy.tile(A,reps)
A指待輸入數(shù)組,reps則決定A的重復(fù)次數(shù)
sorted(iterable,cmp,key,reverse)
這里利用了key參數(shù)使得使用字典中的value值進(jìn)行排序
實(shí)例1:KNN算法改進(jìn)約會(huì)網(wǎng)站配對(duì)效果
背景
假設(shè)A在利用約會(huì)網(wǎng)站進(jìn)行約會(huì),她將自己交往過的人分為三類:
- 不喜歡的人
- 魅力一般的人
- 極具魅力的人
A收集這些人的生活記錄,從中提取中三類特征,存儲(chǔ)在文本datingTestSet2中:
- 每年獲得的飛行常客里程數(shù)
- 玩游戲視頻所耗時(shí)間百分比
- 每周消耗的冰淇淋公升數(shù)
利用這三類特征和標(biāo)簽組成的樣本庫(kù),我們可以在獲得一個(gè)人的這三種特征的特征值的情況下,利用KNN算法判斷該人是否會(huì)是A喜歡人
讀取數(shù)據(jù)
我們將數(shù)據(jù)從文本中讀出,并且以矩陣的形式進(jìn)行存儲(chǔ)
def file2matrix(filename):fr=open(filename)datalines=fr.readlines()numberoflines=len(datalines)returnMat=zeros((numberoflines,3))classlabelVector=[]index=0for line in datalines:line=line.strip()listfromline=line.split('\t')returnMat[index,:]=listfromline[0:3]classlabelVector.append(int(listfromline[-1]))index=index+1return returnMat,classlabelVector分析數(shù)據(jù)
我們可以利用Matplotlib制作原始數(shù)據(jù)的散點(diǎn)圖,觀察特征
def analydata():a,b=file2matrix('datingTestSet2.txt')#創(chuàng)建一個(gè)圖形實(shí)例fig=plt.figure()ax=fig.add_subplot(111)#scatter方法創(chuàng)建散點(diǎn)圖#分析圖像可以發(fā)現(xiàn)使用第一列和第二列數(shù)據(jù)特征更加明顯ax.scatter(a[:,0],a[:,1],15.0*array(b),15.0*array(b))plt.show()畫圖結(jié)果:
這里以“冰淇淋公斤數(shù)”和“玩視頻游戲所耗時(shí)間百分比”作為橫縱坐標(biāo)特征最為明顯
歸一化數(shù)據(jù)
在數(shù)據(jù)分析和機(jī)器學(xué)習(xí)中,經(jīng)常要進(jìn)行數(shù)據(jù)歸一化。因?yàn)椴煌奶卣髦凳褂貌煌牧慷?#xff0c;上下限不同,使得有的特征產(chǎn)生的差值很大,而有的很小,會(huì)影響算法準(zhǔn)確性。所以要先對(duì)數(shù)據(jù)預(yù)處理,進(jìn)行數(shù)據(jù)歸一化處理。
\[ newValue=(oldValue-min)/(max-min) \]
分類器與測(cè)試
我們利用KNN算法,以前10%的數(shù)據(jù)作為待分類數(shù)據(jù),后90%的數(shù)據(jù)作為樣本庫(kù)測(cè)試數(shù)據(jù),進(jìn)行分類與測(cè)試
def datingClassTest():hoRatio=0.10datingDataMat,datingLables=file2matrix('datingTestSet2.txt')normMat=data2normal(datingDataMat)m=normMat.shape[0]numTestVecs=int(hoRatio*m)errorCount=0for i in range(numTestVecs):result=classify(normMat[i,:],normMat[numTestVecs:m,:],datingLables[numTestVecs:m],3)print("the classify come back with: %d,the real answer is: %d"%(result,datingLables[i]))if(result!=datingLables[i]):errorCount+=1.0print("error rate is:%f"%(errorCount/float(numTestVecs)))測(cè)試結(jié)果,錯(cuò)誤率大概在5%左右。
我們可以改變hoRatio和k的值,檢查錯(cuò)誤率是否發(fā)生變化
實(shí)例2:手寫識(shí)別系統(tǒng)
背景
假設(shè)我們有一些手寫數(shù)字,以如下形式保存:
00000000000001100000000000000000 00000000000011111100000000000000 00000000000111111111000000000000 00000000011111111111000000000000 00000001111111111111100000000000 00000000111111100011110000000000 00000001111110000001110000000000 00000001111110000001110000000000 00000011111100000001110000000000 00000011111100000001111000000000 00000011111100000000011100000000 00000011111100000000011100000000 00000011111000000000001110000000 00000011111000000000001110000000 00000001111100000000000111000000 00000001111100000000000111000000 00000001111100000000000111000000 00000011111000000000000111000000 00000011111000000000000111000000 00000000111100000000000011100000 00000000111100000000000111100000 00000000111100000000000111100000 00000000111100000000001111100000 00000000011110000000000111110000 00000000011111000000001111100000 00000000011111000000011111100000 00000000011111000000111111000000 00000000011111100011111111000000 00000000000111111111111110000000 00000000000111111111111100000000 00000000000011111111110000000000 00000000000000111110000000000000這是一個(gè)32*32的矩陣,利用0代表背景,1來代表手寫數(shù)字
對(duì)于這些數(shù)據(jù),我們也可以利用KNN算法來識(shí)別寫的是0~9中的哪里數(shù)字
注:存儲(chǔ)數(shù)據(jù)的文件,例如:0_0.txt代碼數(shù)字0的第一個(gè)手寫樣本數(shù)據(jù)
數(shù)據(jù)預(yù)處理:轉(zhuǎn)換成測(cè)試向量
??數(shù)據(jù)使用32X32的矩陣形式存儲(chǔ),為了能夠使用我們實(shí)現(xiàn)的KNN分類器,我們必須將其轉(zhuǎn)化成1X1024的向量形式進(jìn)行表示,也可以叫做降維,將二維數(shù)據(jù)轉(zhuǎn)換成了一維數(shù)據(jù)
def img2vector(filename):fr=open(filename)returnVect=zeros((1,1024))for i in range(32):linestr=fr.readline()for j in range(32):returnVect[0,i*32+j]=int(linestr[j])return returnVect使用KNN算法進(jìn)行分類
??轉(zhuǎn)換成向量以后,我們就可以使用我們實(shí)現(xiàn)的KNN分類器進(jìn)行分類了
import operator from os import listdirimport matplotlib import matplotlib.pyplot as plt from numpy import array, shape, tile, zerosdef handwritingClassTest():hwlabels=[]traingfilelist=listdir('digits/trainingDigits')m=len(traingfilelist)trainingDataMat=zeros((m,1024))for i in range(m):filenameStr=traingfilelist[i]fileStr=filenameStr.split('.')[0]label=int(fileStr.split('_')[0])hwlabels.append(label)trainingDataMat[i,:]=img2vector('digits/trainingDigits/%s' % filenameStr)errorCount=0.0testfilelist=listdir('digits/testDigits')mTest=len(testfilelist)for i in range(mTest):filenameStr=testfilelist[i]fileStr=filenameStr.split('.')[0]label=int(fileStr.split('_')[0])testVector=img2vector('digits/testDigits/%s' %filenameStr)result=classify(testVector,trainingDataMat,hwlabels,3)print('come back with: %d,the real answer is: %d' % (int(result),label))if(int(result)!=label):errorCount=errorCount+1.0print('total number errors is :%f' % errorCount)print('error rate is :%f'% (errorCount/float(mTest)))os.listdir()
利用該方法,可以得到指定目錄里面的所有文件名
轉(zhuǎn)載于:https://www.cnblogs.com/DLKKILL/p/10371928.html
總結(jié)
以上是生活随笔為你收集整理的机器学习实战(笔记)------------KNN算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 这个家用电动缝纫机是什么牌子的呢
- 下一篇: 隐藏马尔科夫模型HMM