博客內容源於《統計機器學習》一書的閱讀筆記。Python的源碼實現源於《機器學習實戰》部分內容。
1. K近臨算法
【算法描述】給定一個訓練數據集,對於新的輸入實例,在訓練數據集中找到與該實例最近臨的K個實例,這個k個實例的多數屬於某個類,就把該輸入實例分爲這個類。
【數學描述】
輸入:訓練數據集
其中,
輸出:實例
【算法求解過程】
1. 根據給定的距離度量,在訓練集
2. 在
上式中,函數
2. K近臨模型
K近臨模型由三個參數決定:距離度量,k值和分類決策規則。
2.1 距離度量
設特徵空間
2.1.1 歐氏距離(Euclidean Distance)
歐氏距離是最易於理解的一種距離計算方法,源自歐氏空間中兩點間的距離公式。上述公式中
2.1.2 曼哈頓距離(Manhattan Distance)
2.1.3 夾角餘弦(Cosine)
幾何中夾角餘弦可用來衡量兩個向量方向的差異,機器學習常常中用這一概念來衡量樣本向量之間的差異。
2.2 K值選取
K值的選取會對k近臨算法的結果產生很大的影響。
- K值很小時,預測結果會對噪聲特別敏感。假設臨近的實例點恰好是噪聲,預測的結果就會出錯。
- K值很大,與輸入實例距離較遠的實例點也會起作用,導致預測的結果出錯。
2.3 分類決策
k近臨中的分類決策規則往往使用多數表決,即由輸入實例的k個鄰近的訓練實例中的多數類決定輸入實例的類。
【多數表決】
如果分類的損失函數爲0-1損失函數,分類函數爲
那麼誤分的概率是
對於給定的實例
要使誤分類率最小(經驗風險最小),就要使
3. K近臨舉例
數據來自於《機器學習實戰》一書中,數據下載鏈接:
https://github.com/bzhou830/ML-python/blob/master/ch1-KNN/datingTestSet2.txt
1.從文件中導入元數據
def file2matrix(filename):
fr = open(filename) #打開文件
arrayOfLines = fr.readlines() #讀取文件行數
numberOfLines = len(arrayOfLines) #文件行數
returnMat=zeros((numberOfLines,3)) #矩陣
classLabelVector = [] #標籤
index = 0
for line in arrayOfLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat,classLabelVector
2.使用matplotlib繪製數據集合圖像
def PrintFigure(datingDataMat,datingLabels):
fig = plt.figure()
ax=fig.add_subplot(111, projection='3d')
#繪製三維圖
num = len(datingDataMat)
for i in range(num):
if datingLabels[i] == 1:
ax.scatter(datingDataMat[i][0],datingDataMat[i][1],datingDataMat[i][2], c='b', marker='x')
elif datingLabels[i] == 2:
ax.scatter(datingDataMat[i][0],datingDataMat[i][1],datingDataMat[i][2], c='r', marker='o')
elif datingLabels[i] == 3:
ax.scatter(datingDataMat[i][0],datingDataMat[i][1],datingDataMat[i][2], c='g',marker='*')
elif datingLabels[i] == 0:
ax.scatter(datingDataMat[i][0],datingDataMat[i][1],datingDataMat[i][2], marker='1')
plt.show()
可以直觀的看到元數據有三類。
3.完整程序
'''
inx 輸入向量
dataSet 訓練數據集
labels 訓練數據集標籤
k 最臨近數目
'''
def classify0(inx,dataSet,labels,k):
dataSetSize=dataSet.shape[0] #樣本集的個數
diffMat=tile(inx,(dataSetSize,1)) - dataSet #矩陣之差
sqDiffMat = diffMat**2 #矩陣之差的平方
sqDistances=sqDiffMat.sum(axis=1) #矩陣的每一行相加,得到一個向量
distances=sqDistances**0.5 #向量的長度
sortedDistIndicies = distances.argsort() #數組從小到大的索引值
classCount={} #類統計
for i in range(k): #最臨近數目
voteIlabel = labels[sortedDistIndicies[i]] #最臨近數的標籤
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #統計標籤個數
sortedClassCount=sorted(classCount.iteritems(),
key=operator.itemgetter(1),reverse=True)#排序
return sortedClassCount[0][0] #返回數量最多的標籤
def file2matrix(filename):
fr = open(filename) #打開文件
arrayOfLines = fr.readlines() #讀取文件行數
numberOfLines = len(arrayOfLines) #文件行數
returnMat=zeros((numberOfLines,3)) #矩陣
classLabelVector = [] #標籤
index = 0
for line in arrayOfLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat,classLabelVector
'''
dataSet 傳入矩陣數據集
normDataSet 返回歸一化後數據集
ranges
minVals
'''
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():
hoRatio = 0.20 #測試數據集所佔比例
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #加載數據
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 "Rt is %d, Real is %d" % (classifierResult,datingLabels[i])
if(classifierResult != datingLabels[i]):
errorcount += 1.0
print " %f " % (errorcount/float(numTestVecs))
程序文件可以可以到github上下載:https://github.com/bzhou830/ML-python/