機器學習實戰---k近鄰演算法(程式碼及執行)
阿新 • • 發佈:2019-02-16
import numpy as np #匯入numpy
import operator #運算子模組
#k-近鄰演算法
#計算距離
def classify0(inX,dataSet,labels,k):
dataSetSize=dataSet.shape[0] #shape讀取資料矩陣第一維度的長度
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet #tile重複陣列inX,有dataSet行 1個dataSet列,減法計算差值
sqDiffMat=diffMat**2 #**是冪運算的意思,這裡用的歐式距離
sqDisttances=sqDiffMat.sum(axis =1) #普通sum預設引數為axis=0為普通相加,axis=1為一行的行向量相加
distances=sqDisttances**0.5
sortedDistIndicies=distances.argsort() #argsort返回數值從小到大的索引值(陣列索引0,1,2,3)
#選擇距離最小的k個點
classCount={}
for i in range(k):
voteIlabel=labels[sortedDistIndicies[i]] #根據排序結果的索引值返回靠近的前k個標籤
classCount[voteIlabel]=classCount.get(voteIlabel,0 )+1 #各個標籤出現頻率
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) #排序頻率
#!!!!! classCount.iteritems()修改為classCount.items()
#sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list。
# reverse預設升序 key關鍵字排序itemgetter(1)按照第一維度排序(0,1,2,3)
return sortedClassCount[0][0] #找出頻率最高的
#建立資料集
def createDataSet():
group=np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels=['A','A','B','B']
return group,labels
#import kn
#group,labels=kn.createDataSet()
def file2matrix(filename):
fr=open(filename)
arrayOLines=fr.readlines()
numberOfLines=len(arrayOLines) #讀出資料行數
returnMat=np.zeros((numberOfLines,3)) #建立返回矩陣
classLabelVector=[]
index=0
for line in arrayOLines:
line=line.strip() #刪除空白符
listFromLine=line.split('\t') #split指定分隔符對資料切片
returnMat[index,:]=listFromLine[0:3] #選取前3個元素(特徵)儲存在返回矩陣中
classLabelVector.append(int(listFromLine[-1]))
#-1索引表示最後一列元素,位label資訊儲存在classLabelVector
index+=1
return returnMat,classLabelVector
#datingDatMat,datingLabels=kn.file2matrix('datingTestSet2.txt')
##使用matplotlib建立散點圖
#import matplotlib
#import matplotlib.pyplot as plt
##figure指定圖表名稱
#fig=plt.figure()
##在整張圖上加入一個子圖,111的意思是在一個1行1列的子圖中的第一張
#ax=fig.add_subplot(111)
##標明畫散點圖,plot為預設為華連線圖
#ax.scatter(datingDatMat[:,1],datingDatMat[:,2])
##一定要加上這句話才能讓畫顯示在螢幕上
#plt.show
#ax=fig.add_subplot(121)
#ax.scatter(datingDatMat[:,1],datingDatMat[:,2],15.0*np.array(datingLabels),15.0*np.array(datingLabels))
#plt.show
#ax=fig.add_subplot(131)
##第一二列屬性
#ax.scatter(datingDatMat[:,0],datingDatMat[:,1],15.0*np.array(datingLabels),15.0*np.array(datingLabels))
#plt.show
#歸一化特徵值
#歸一化公式 :(當前值-最小值)/range
def autoNorm(dataSet):
minVals=dataSet.min(0) #存放每列最小值,引數0使得可以從列中選取最小值,而不是當前行
maxVals=dataSet.max(0) #存放每列最大值
ranges = maxVals - minVals
normDataSet=np.zeros(np.shape(dataSet)) #初始化歸一化矩陣為讀取的dataSet
m=dataSet.shape[0] #m儲存第一行
# 特徵矩陣是3x1000,min max range是1x3 因此採用tile將變數內容複製成輸入矩陣同大小
normDataSet=dataSet-np.tile(minVals,(m,1))
normDataSet=normDataSet/np.tile(ranges,(m,1))
return normDataSet, ranges, minVals
#normMat,ranges,minVals=kn.autoNorm(datingDatMat)
#測試約會網站分類結果程式碼
def datingClassTest():
hoRatio = 0.10 #hold out 10%
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #load data setfrom file
normMat, ranges, minVals = autoNorm(datingDataMat)
m = normMat.shape[0]
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)))
#print(errorCount)
#完整的約會網站預測:給定一個人,判斷時候適合約會
def classifyPerson():
resultList=['not at all','in small doses','in large doses']
percentTats=float(input("percentage of time spent playing video games?"))
#書中raw_input在python3中修改為input()
ffMiles=float(input("frequent flier miles earned per year?"))
iceCream=float(input("liters of ice cream consumed per year?"))
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')#原書沒有2
normMat, ranges, minVals = autoNorm(datingDataMat)
inArr=np.array([ffMiles,percentTats,iceCream])
classifierResult=classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
print("You will probably like this person:", resultList[classifierResult-1])
#kn.classifyPerson()
import os#, sys
def img2vector(filename):
returnVect=np.zeros((1,1024))#每個手寫識別為32x32大小的二進位制影象矩陣 轉換為1x1024 numpy向量陣列returnVect
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])#將每行的32個字元值儲存在numpy陣列中
return returnVect
#testvector=kn.img2vector('testDigits/0_13.txt')
#測試演算法
def handwritingClassTest():
hwLabels=[]
trainingFileList=os.listdir('trainingDigits')#修改 import os 這裡加上os.
m=len(trainingFileList)
trainingMat=np.zeros((m,1024)) #定義檔案數x每個向量的訓練集
for i in range(m):
fileNameStr=trainingFileList[i]
fileStr=fileNameStr.split('.')[0]#解析檔案
classNumStr=int(fileStr.split('_')[0])#解析檔名
hwLabels.append(classNumStr)#儲存類別
trainingMat[i,:]=img2vector('trainingDigits/%s'%fileNameStr) #訪問第i個檔案內的資料
#測試資料集
testFileList=os.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)#訪問第i個檔案內的測試資料,不儲存類 直接測試
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("\nthe total number of errors is: %d" % errorCount)
print("\nthe total rate is:%f"% (errorCount/float(mTest)))
#kn.handwritingClassTest()