K-近鄰演算法---分類
阿新 • • 發佈:2018-12-31
使用 k 近鄰演算法改進網站的配對效果
# 匯入程式所需要的模組
import numpy as np
import operator
定義資料集匯入函式
file2matrix函式實現的功能是讀取檔案資料,函式返回的returnMat和classLabelVector分別是資料集的特徵矩陣和輸出標籤向量。
def file2matrix(filename): love_dictionary = {'largeDoses':3, 'smallDoses':2, 'didntLike':1} # 三個類別 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') # 按'\t'對字串進行分割,listFromLine 是列表 returnMat[index, :] = listFromLine[0:3] # listFromLine的0,1,2元素是特徵,賦值給returnMat的當前行 if(listFromLine[-1].isdigit()): # 如果listFromLine最後一個元素是數字 classLabelVector.append(int(listFromLine[-1])) # 直接賦值給classLabelVector else: # 如果listFromLine最後一個元素不是數字,而是字串 classLabelVector.append(love_dictionary.get(listFromLine[-1])) # 根據字典love_dictionary轉化為數字 index += 1 return returnMat, classLabelVector # 返回的類別標籤classLabelVector是1,2,3
定義特徵歸一化函式
這裡為什麼要對特徵進行歸一化?
因為在處理這種不同取值範圍的特徵值時,數值歸一化能夠將不同特徵的取值範圍限定在同一區間例如[0,1]之間,讓不同特徵對距離的計算影響相同。具體可看《機器學習實戰》第2.2.3節內容。
def autoNorm(dataSet): minVals = dataSet.min(0) maxVals = dataSet.max(0) ranges = maxVals - minVals normDataSet = np.zeros(np.shape(dataSet)) m = dataSet.shape[0] normDataSet = dataSet - np.tile(minVals, (m, 1)) normDataSet = normDataSet/np.tile(ranges, (m, 1)) # normDataSet值被限定在[0,1]之間 return normDataSet, ranges, minVals
定義 k 近鄰演算法
def classify0(inX, dataSet, labels, k): # inX是測試集,dataSet是訓練集,lebels是訓練樣本標籤,k是取的最近鄰個數 dataSetSize = dataSet.shape[0] # 訓練樣本個數 diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet # np.tile: 重複n次 sqDiffMat = diffMat**2 sqDistances = sqDiffMat.sum(axis=1) distances = sqDistances**0.5 # distance是inX與dataSet的歐氏距離 sortedDistIndicies = distances.argsort() # 返回排序從小到達的索引位置 classCount = {} # 字典儲存k近鄰不同label出現的次數 for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 # 對應label加1,classCount中若無此key,則預設為0 sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # operator.itemgetter 獲取物件的哪個維度的資料 return sortedClassCount[0][0] # 返回k近鄰中所屬類別最多的哪一類
測試演算法:作為完整程式驗證分類器
def datingClassTest():
hoRatio = 0.10 #整個資料集的10%用來測試
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("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) # 列印錯誤個數
datingClassTest()
執行結果;
使用演算法:構建完整可用系統
根據使用者輸入,線上判斷類別。
def classifyPerson():
resultList = ['not at all', 'in small doses', 'in large doses']
percentTats = float(input(\
"percentage of time spent playing video games?"))
ffMiles = float(input("frequent flier miles earned per year?"))
iceCream = float(input("liters of ice cream consumed per year?"))
datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
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: %s" % resultList[classifierResult - 1])
classifyPerson()
執行結果: