機器學習實戰-KNN演算法實現及遇到的問題總結
阿新 • • 發佈:2019-01-29
最近在看《機器學習實戰》這本書,內容充實,重視實踐,很不錯,也很適合機器學習的入門。下面貼上用python編寫的KNN演算法程式碼,放在部落格裡安全啊~~我的電腦隨時都會崩潰的....
在程式設計期間,有一個錯誤困惑了我很長時間,就是在載入KNN.py檔案後,執行handwritingClassTest函式的時候,總會出現如下錯誤:from numpy import * import operator from os import listdir def classify0(inx,dataset,labels,k): datasetsize=dataset.shape[0] temp=tile(inx,(datasetsize,1)) distance2=(temp-dataset)**2 distance=sum(distance2,axis=1)**0.5 """sum(a,axis=0)求每一列上所有數之和,sum(a,axis=1)求每一行上所有數之和""" sorteddistance=distance.argsort() classcount={} for i in range(k): classlabel=labels[sorteddistance[i]] classcount[classlabel]=classcount.get(classlabel,0)+1 sortedclasscount=sorted(classcount.items(),key=operator.itemgetter(1),reverse=True) return sortedclasscount[0][0] def file2matrix(filename): with open(filename) as fr: arrayOLines=fr.readlines() numberOfLines=len(arrayOLines) returnMat=zeros((numberOfLines,3)) classLabelVector=[] index=0 for each_line in arrayOLines: listFromLine=each_line.strip().split('\t') returnMat[index]=listFromLine[0:3] classLabelVector.append(int(listFromLine[3])) #classLabelVector[index]=listFromLine[3] index+=1 return returnMat,classLabelVector def autoNorm(dataSet): minVals=dataSet.min(0) maxVals=dataSet.max(0) ranges=maxVals-minVals normDataSet=zeros(shape(dataSet)) m=dataSet.shape[0] normDataSet=dataSet-tile(minVals,(m,1)) normDataSet=normDataSet/tile(ranges,(m,1)) return normDataSet,ranges,minVals def datingClassTest(): testratio=0.2 datingDataMat,datinglabels=file2matrix('datingTestSet2.txt') normDataSet,ranges,minVals=autoNorm(datingDataMat) m=normDataSet.shape[0] textnum=int(m*testratio) errorcount=0 for i in range(textnum): classifierResult=classify0(normDataSet[i,:],normDataSet[textnum:m,:],datinglabels[textnum:m],3) print("分類器返回的結果為:%d,正確答案是:%d"%(classifierResult,datinglabels[i])) if classifierResult != datinglabels[i]: errorcount+=1 print("臥槽,錯了*********************************************************************************************") print("總錯誤率是:%f"%(errorcount/float(textnum))) def classifyPerson(): result=['不感興趣','一般有魅力','很有魅力'] datingDataMat,datinglabels=file2matrix('datingTestSet2.txt') normDataSet,ranges,minVals=autoNorm(datingDataMat) miles=float(input('每年獲得的飛機常客里程數:')) games=float(input('玩視訊遊戲所耗時間百分比:')) icecream=float(input('每週消耗的冰淇淋公升數:')) textData=array([miles,games,icecream]) classifierResult=classify0((textData-minVals)/ranges,normDataSet,datinglabels,3) return result[classifierResult-1] def img2vector(filename): returnVect = zeros((1,1024)) fr = open(filename) for i in range(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') m=len(trainingFileList) trainingMat=zeros((m,1024)) for i in range(m): fileNameStr = trainingFileList[i] fileStr=fileNameStr.split('.')[0] classnumberstr=int(fileStr.split('_')[0]) hwLabels.append(classnumberstr) trainingMat[i,:]=img2vector('trainingDigits/%s'%trainingFileList[i]) testFileList=listdir('testDigits') errorcount=0.0 mTest=len(testFileList) for j in range(mTest): fileNameStr=testFileList[j] fileStr=fileNameStr.split('.')[0] classnumberstr=int(fileStr.split('_')[0]) vectorundertest=img2vector('testDigits/%s'%testFileList[j]) result=classify0(vectorundertest,trainingMat,hwLabels,3) print('分類器輸出結果是:%d,正確結果為:%d'%(result,classnumberstr)) if result!=classnumberstr: errorcount+=1 print('一共錯了:%d'%errorcount) print('錯誤率:%f'%(errorcount/mTest)) def testnum(): hwLabels=[] trainingFileList=listdir('trainingDigits') m=len(trainingFileList) trainingMat=zeros((m,1024)) for i in range(m): fileNameStr = trainingFileList[i] fileStr=fileNameStr.split('.')[0] classnumberstr=int(fileStr.split('_')[0]) hwLabels.append(classnumberstr) trainingMat[i,:]=img2vector('trainingDigits/%s'%trainingFileList[i]) testvector=img2vector('test.txt') result=classify0(testvector,trainingMat,hwLabels,3) return(result)
問題出在open()函式的flags引數上。可是問題是我們平常使用open()函式的時候基本就沒有用到什麼所謂的flags引數有木有!!!
後來我覺得可能是import這裡出現了問題,然後我發現了我寫的一個語句:
from os import *
應該就是這句話有問題,因為查資料可以得到,那個所謂的flags引數是與os庫有關的,至此我更加堅信了自己的判斷。
為什麼我當初要寫 from os import * 這句話呢?因為我要用到os庫裡面的listdir函式,這個函式可以返回一個資料夾裡面所有檔案的檔名。
我將 from os import * 改為from os import listdir 問題解決。
所以這麼看來,from os import *這種形式雖然方便,但是確實存在一定的風險啊~~~