KNN:分類算法
目標:
對未知類別的樣本進行分類預測
步驟:
1.對於某個未知類別樣本,根據距離度量計算每個已知類別樣本與其距離。
2.選出K個與該未知類別樣本距離最小的已知類別的樣本。
3.在K個已知類別樣本里得到頻數最多的類別,該類別就是未知類別樣本的預測。
KNN算法:
# 尋找K值 1~60 打印誤差最小的K值和對應的誤差個數及誤差率
from numpy import *
import operator # 引入運算符模塊,K鄰近算法會使用到其中的函數
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 classifyO(inX, dataSet, labels, k): # KNN算法
# 用於分類的輸入向量是inX,
# 輸入的訓練樣本集爲dataSet,標籤向量爲labe1s,最後的參數k表示用於選擇最近鄰居的數目,
# 其中標籤向量的元素數目和矩陣dataset的行數相同。
dataSetSize = dataSet.shape[0] # shape[0]就是讀取矩陣第一維度的長度。
diffMat = tile(inX, (dataSetSize, 1)) - dataSet
#根據公式可推測出計算差值
# 把inx行列重複copy(dataSetSize,1)次。
# inX是個向量,而dataset是個矩陣,兩者之間要進行相減的運算,需要把這個向量也補成一個和dataset有相同行數列數的矩陣,
# tile()的第二個參數,也就是(datasetsize,1),這個參數的意思就是把inX補成有datasetsize行數的矩陣。
# 然後和dataset相減就是根據矩陣的減法進行的。因此diffMat是一個差值矩陣。
sqDiffMat = diffMat ** 2 # 歐氏距離計算公式
sqDistances = sqDiffMat.sum(axis=1) # axis這個參數,它決定對矩陣求和時候的順序,axis=0是按照行求和,axis=1是按照列進行求和。
distances = sqDistances ** 0.5 # 0.5次方即開根號
sortedDisIndicies = distances.argsort() # 就是把向量中每個元素進行排序,而它的結果是元素的索引(原來的下標)形成的向量。
classCount = {} # 生成字典,對classCount元素賦值,其實是個計數器
# 選擇距離待分類點最小的k個點
for i in range(k): # 遍歷k,尋找該樣本標籤的類型
voteIlabel = labels[sortedDisIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
# python3字典的 items() 方法,以列表的形式返回可遍歷的(鍵,值)元組數組。
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
# 內建函數 sorted 方法返回的是一個新的 list,而不是在原來的基礎上進行的操作與sort方法不一樣。
# reverse -- 排序規則,reverse = True 降序 , reverse = False 升序(默認)。
# sorted函數返回類型爲list
return sortedClassCount[0][0] # 返回前k個點出現頻率最高的類別作爲當前點的預測分類。即最符合的標籤
# 文件導入
def file2matrix(filename):
fr = open(filename)
# 得到文件行數
arrayOLines = fr.readlines()
# 創建返回的NumPy矩陣
numberOfLines = len(arrayOLines)
returnMat = zeros((numberOfLines, 3))
# 解析文件數據到列表
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index, :] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat, classLabelVector
#散點圖代碼塊 (已註釋需要運行出圖片解註釋即可)
#from numpy import array
#import matplotlib
#import matplotlib.pyplot as plt
#fig = plt.figure()
#ax = fig.add_subplot(111)
#datingDataMat,datingLabels = file2matrix('F:\python項目\KNN\datingTestSet2.txt')
#ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
#plt.show()
#歸一化特徵值
def autoNorm(dataSet):
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
#將每列的最小值放在變量minvals中,將最大值放在變量maxVals中,
# 其中dataset.min(0)中的參數0使得函數可以從列中選取最小值,而不是選取當前行的最小值。
# 然後,函數計算可能的取值範圍,並創建新的返回矩陣。
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m,1))#特徵在短陣有1000×3個值,而minvals與raange的值都爲1×3。因此利用tile()
#函數將變量內容複製成輸入矩陣同樣大小的矩陣
normDataSet = normDataSet/tile(ranges, (m,1)) #矩陣除法
return normDataSet, ranges, minVals
#自動化調試模塊代碼
def Autodebug(k):
minCount = 20 #假如其中有20個誤差,結果當然沒有這麼多,設置這麼大也沒關係,反正minCount會被覆蓋掉
for k in range(1,60):
datingClassTest(k)
#print("the total error rate is : ", datingClassTest(k)[1]) #該條註釋用來驗證結果
#print("the total error count is : ", datingClassTest(k)[0]) #該條註釋用來驗證結果
if(datingClassTest(k)[0]<minCount):
#誤差最小一定誤差數最少,誤差數最少,誤差率一定最小
minCount=datingClassTest(k)[0]
print("The minErroK's minErroCount= ",minCount)
print("The minErroK's minErroRate=",minCount/100)
for k in range(1,60):
datingClassTest(k)
if datingClassTest(k)[0]==minCount:
print("The nice K= ",datingClassTest(k)[2])
#分類器
def datingClassTest(k):
hoRatio=0.1
datingDataMat,datingLabels=file2matrix('F:\python項目\KNN\datingTestSet2.txt')
normMat,minVals,ranges=autoNorm(datingDataMat)
m=normMat.shape[0]
errorCount=0.0
numTestVecs=int(m*hoRatio)
for i in range(numTestVecs):
classifierResult=classifyO(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],k) #//K取3時
if (classifierResult!=datingLabels[i]):
errorCount+=1.0
x=errorCount/float(numTestVecs)
return (errorCount,x,k) #稍作修改,方便Autodebug()函數調用,自動化測試,返回誤差個數和誤差率即可
Autodebug(1) #直接Run即可
#如果k值選擇較大的話,距離較遠的訓練樣本也能夠對實例預測結果產生影響。
# 這時候,模型相對比較魯棒,不會因爲個別噪聲點對最終預測結果產生影響。
# 但是缺點也十分明顯:算法的近鄰誤差會偏大,距離較遠的點(與預測實例不相似)也會同樣對預測結果產生影響,
# 使得預測結果產生較大偏差,此時模型容易發生欠擬合。
#因此,在實際工程實踐中,我們一般採用交叉驗證的方式選取k值。
# 通過以上分析可知,一般k值選得比較小,我們會在較小範圍內選取k值。
# 同時把測試集上準確率最高的那個確定爲最終的算法超參數k。
#雖然K值4與7都滿足最小誤差率,但k值4作爲超參數更好