摘要:而產(chǎn)生這種現(xiàn)象的唯一遠遠,僅僅是因為飛行常客里程數(shù)遠大于其他特征值。但海倫認為這三種特征是同等重要的,因此作為三個等權(quán)重的特征之一,飛行常客里程數(shù)并不應(yīng)該如此嚴重的影響到計算結(jié)果。
一、KNN概述
簡單的說,k-近鄰算法采用測量不同特征值之間的距離方法進行分類。
優(yōu)點:精度高、對異常值不敏感、無數(shù)據(jù)輸入假定
缺點:計算復(fù)雜度高、空間復(fù)雜度高
適用數(shù)據(jù)范圍:數(shù)值型和標稱型
1.1 工作原理KNN可以說是最簡單的分類算法之一,同時,它也是最常見的分類算法之一,注意KNN算法是有監(jiān)督學(xué)習(xí)的分類算法,它看起來和另外一個機器學(xué)習(xí)算法Kmeans有點像(Kmeans是無監(jiān)督學(xué)習(xí)算法)。
其工作原理是使用一個樣本數(shù)據(jù)集合,也稱為訓(xùn)練樣本集,并且樣本集中每個數(shù)據(jù)都存在標簽,即我們知道樣本集中每一數(shù)據(jù)與所屬分類的對應(yīng)關(guān)系。輸入沒有標簽的新數(shù)據(jù)后,將新數(shù)據(jù)的每個特征與樣本集中的數(shù)據(jù)對應(yīng)的特征進行比較,然后算法提取樣本集中特征最相似(最近鄰)的分類標簽。一般來說,我們只選擇樣本集中前k個最相似的數(shù)據(jù),這就是KNN中K的出處,最后使用Majority-Voting(多數(shù)表決)選擇k個最相似數(shù)據(jù)中次數(shù)出現(xiàn)最多的分類,作為新數(shù)據(jù)的分類。
1.2 三要素K的取值:可以使用Cross Validation(交叉驗證)來選取合適的值
我們該如何選擇合適的k值呢?通過將樣本數(shù)據(jù)按照一定比例,拆分出訓(xùn)練用的數(shù)據(jù)和驗證用的數(shù)據(jù),比如6:4拆出訓(xùn)練數(shù)據(jù)和驗證數(shù)據(jù),從選取一個較小的k值開始,不斷增加k的值,然后計算驗證集合的方差,最終找到一個比較合適的k值。
距離度量 Metric / Distance Measure:距離度量一般都使用 Euclidean distance(歐氏距離)
二維空間兩個點的歐式距離公式如下
分類決策 Deision rule:分類決策即Majority-Voting ,選取票數(shù)最多的標簽,在回歸中通常為k個最鄰近點的標簽的平均值
1.3 在什么時候選擇KNN算法 二、實踐案例(主要重點是可視化) 2.1 實例一 :電影分類電影名稱 打斗鏡頭 接吻鏡頭 電影類型 Californla Man 3 104 愛情片 He`s Not Really into Dudes 2 100 愛情片 Beautiful Woman 1 81 愛情片 Kevin Longblade 101 10 動作片 Robo Slayer 3000 99 5 動作片 Ampedll 98 2 動作片 ? 18 90 未知
首先我們通過 Python 的第三方庫進行數(shù)據(jù)可視化處理
import matplotlib.pyplot as plt import numpy as np import operator # 已知分類的數(shù)據(jù) x1=np.array([3,2,1]) y1=np.array([104,100,81]) x2=np.array([101,99,98]) y2=np.array([10,5,2]) scatter1 = plt.scatter(x1,y1,c="r") scatter2 = plt.scatter(x2,y2,c="b") # 求未知數(shù)據(jù) x = np.array([18]) y = np.array([90]) scatter3 = plt.scatter(x,y,c="k") #畫圖例 plt.legend(handles=[scatter1,scatter2,scatter3],labels=["labelA","labelB","X"],loc = "best" ) plt.show()
KNN近鄰算法最核心的部分就是歐式距離的計算,通過計算得到距離最近的k個數(shù)的標簽,統(tǒng)計出現(xiàn)次數(shù)最多的標簽,將其賦值給新數(shù)據(jù)。下面這段代碼就是KNN算法最基本的實例。通過傳入數(shù)據(jù)來預(yù)測電影的標簽是什么!
from numpy import * import operator # 電影分類 # 歐式距離求解返回前k個標簽 然后匯總出現(xiàn)次數(shù)最多的標簽 def classify0(inX, dataSet, labels, k): dataSetSize = dataSet.shape[0] # 求inX與數(shù)據(jù)集中各個樣本的歐氏距離 diffMat = tile(inX, (dataSetSize,1)) - dataSet # numpy中的tile函數(shù)將inX復(fù)制為重復(fù)的dataSize個行和重復(fù)的1列,功能相當(dāng)于MATLAB中的repmat sqDiffMat = diffMat**2 sqDistances = sqDiffMat.sum(axis=1) # 按照x軸相加 distances = sqDistances**0.5 # print(distances) sortedDistIndicies = distances.argsort() # 從小到大排序后,返回索引 # 這個返回索引是關(guān)鍵 只有理解了這個返回索引才能理解k-nn算法 # print(sortedDistIndicies) # 字典,key存儲第i小的標簽值,value為標簽的次數(shù) classCount = {} for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] # 取第i個小的標簽值 # print(sortedDistIndicies[i]) classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 # 根據(jù)標簽統(tǒng)計標簽次數(shù),如果沒找到返回0。統(tǒng)計前k個候選者中標簽出現(xiàn)的次數(shù) sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # operator.itemgetter(1) 按照第2個元素,即標簽出現(xiàn)的次數(shù)對classCount從大到小排序 # print(sortedClassCount) # 測試結(jié)果 [("B", 2), ("A", 1)] return sortedClassCount[0][0] # 返回最終的類別,即標簽值key # 傳輸數(shù)據(jù) def createDataSet(): group = array([[3,104],[2,100],[1,81],[101,10],[99,5],[98,2]]) labels = ["A","A","A","B","B","B"] return group, labels # 測試代碼 group, labels = createDataSet() ans = classify0([18,90], group, labels, 3) print(ans) >>> A2.2 實例二:優(yōu)化約會匹配效果 1-項目概論
海倫使用約會網(wǎng)站尋求約會對象,經(jīng)過一段實踐之后,她發(fā)現(xiàn)曾交往過三類人:
不喜歡的人
魅力一般的人
極具魅力的人
她希望:
工作日與魅力一般的人約會
周末與極具魅力的人約會
不喜歡的人則直接排除掉
現(xiàn)在她收集到了一些約會網(wǎng)站未曾記錄的數(shù)據(jù)信息,這更有助于匹配對象的歸類。
2-開發(fā)流程1. 收集數(shù)據(jù):提供文本文件 2. 準本數(shù)據(jù):使用Python解析文本文件 3. 分析數(shù)據(jù):使用Matplotlib 畫二維散點圖 4. 訓(xùn)練算法:此步驟不適用與KNN算法,但是也很重要 5. 測試數(shù)據(jù):使用海倫提供的部分數(shù)據(jù)作為測試樣本 6. 使用算法:產(chǎn)生簡單的命令行程序,然后海倫可以輸入一些特征數(shù)據(jù)以判斷對方是否為自己喜歡的類型
測試樣本與非測試樣本的區(qū)別在于:
測試樣本是以及完成分類的數(shù)據(jù),如果測試分類與實際類不同,則標記為一個錯誤
海倫把這些約會對象的數(shù)據(jù)存放在文本文件 datingTestSet2.txt 中,總共有1000行,海倫約會的對象主要包含以下3種特征:
每年獲得的飛行常客里程數(shù)
玩視頻游戲所耗費時間百分比
每周消費的冰激凌公升數(shù)
文本文件數(shù)據(jù)格式如下
40920 8.326976 0.953952 3 14488 7.153469 1.673904 2 26052 1.441871 0.805124 1 75136 13.147394 0.428964 1 38344 1.669788 0.134296 14-準備數(shù)據(jù):使用python解析文本
將文本記錄轉(zhuǎn)換為 NUmPy的解析程序
from numpy import zeros def file2matrix(filename): """ Desc: 導(dǎo)入訓(xùn)練數(shù)據(jù) Parameters: filename:數(shù)據(jù)文件路徑 return: 數(shù)據(jù)矩陣 returnMat 和對應(yīng)的類別 classLabelVector """ fr = open("datingTestSet2.txt") # 獲得文件中的數(shù)據(jù)行的行數(shù) numberOfLines = len(fr.readlines()) # 生成對應(yīng)的空矩陣 # 例如:zeros(2,3)就是生成一個 2*3 的矩陣,各個位置上全是0 returnMat = zeros((numberOfLines , 3)) # prepare matrix to return classLabelVector = [] fr = open("datingTestSet2.txt") index =0 for line in fr.readlines(): # str.strip([chars]) -- 返回已移除字符串頭尾指定字符所生成的新字符串 line = line.strip() # 以 切割字符串 listFromLine = line.split(" ") # 每列的屬性數(shù)據(jù) returnMat[index , : ] = listFromLine[0:3] # 每列的類別數(shù)據(jù),就是 label 標簽數(shù)據(jù) classLabelVector.append(int(listFromLine[-1])) index += 1 # 返回數(shù)據(jù)矩陣 returnMat 和對應(yīng)的類別 classLabelVector print(returnMat,classLabelVector) return returnMat,classLabelVector if __name__=="__main__": file2matrix(1) >>> [[4.0920000e+04 8.3269760e+00 9.5395200e-01] [1.4488000e+04 7.1534690e+00 1.6739040e+00] [2.6052000e+04 1.4418710e+00 8.0512400e-01] ... [2.6575000e+04 1.0650102e+01 8.6662700e-01] [4.8111000e+04 9.1345280e+00 7.2804500e-01] [4.3757000e+04 7.8826010e+00 1.3324460e+00]] [3, 2, 1, 1, 1, 1, 3, 3, 1, 3, 1, 1, 2, 1, 1, 1, 1, 1, 2, 3, 2, 1, 2, 3, 2, 3, 2, 3, 2, 1, 3, 1, 3, 1, 2, 1, 1, 2, 3, 3, 1, 2, 3, 3, 3, 1, 1, 1, 1, 2, 2, 1, 3, 2, 2, 2, 2, 3, 1, 2, 1, 2, 2, 2, 2, 2, 3, 2, 3, 1, 2, 3, 2, 2, 1, 3, 1, 1, 3, 3, 1, 2, 3, 1, 3, 1, 2, 2, 1, 1, 3, 3, 1, 2, 1, 3, 3, 2, 1, 1, 3, 1, 2, 3, 3, 2, 3, 3, 1, 2, 3, 2, 1, 3, 1, 2, 1, 1, 2, 3, 2, 3, 2, 3, 2, 1, 3, 3, 3, 1, 3, 2, 2, 3, 1, 3, 3, 3, 1, 3, 1, 1, 3, 3, 2, 3, 3, 1, 2, 3, 2, 2, 3, 3, 3, 1, 2, 2, 1, 1, 3, 2, 3, 3, 1, 2, 1, 3, 1, 2, 3, 2, 3, 1, 1, 1, 3, 2, 3, 1, 3, 2, 1, 3, 2, 2, 3, 2, 3, 2, 1, 1, 3, 1, 3, 2, 2, 2, 3, 2, 2, 1, 2, 2, 3, 1, 3, 3, 2, 1, 1, 1, 2, 1, 3, 3, 3, 3, 2, 1, 1, 1, 2, 3, 2, 1, 3, 1, 3, 2, 2, 3, 1, 3, 1, 1, 2, 1, 2, 2, 1, 3, 1, 3, 2, 3, 1, 2, 3, 1, 1, 1, 1, 2, 3, 2, 2, 3, 1, 2, 1, 1, 1, 3, 3, 2, 1, 1, 1, 2, 2, 3, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 3, 2, 3, 3, 3, 3, 1, 2, 3, 1, 1, 1, 3, 1, 3, 2, 2, 1, 3, 1, 3, 2, 2, 1, 2, 2, 3, 1, 3, 2, 1, 1, 3, 3, 2, 3, 3, 2, 3, 1, 3, 1, 3, 3, 1, 3, 2, 1, 3, 1, 3, 2, 1, 2, 2, 1, 3, 1, 1, 3, 3, 2, 2, 3, 1, 2, 3, 3, 2, 2, 1, 1, 1, 1, 3, 2, 1, 1, 3, 2, 1, 1, 3, 3, 3, 2, 3, 2, 1, 1, 1, 1, 1, 3, 2, 2, 1, 2, 1, 3, 2, 1, 3, 2, 1, 3, 1, 1, 3, 3, 3, 3, 2, 1, 1, 2, 1, 3, 3, 2, 1, 2, 3, 2, 1, 2, 2, 2, 1, 1, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 3, 1, 1, 2, 2, 1, 2, 2, 2, 3, 1, 1, 1, 3, 1, 3, 1, 3, 3, 1, 1, 1, 3, 2, 3, 3, 2, 2, 1, 1, 1, 2, 1, 2, 2, 3, 3, 3, 1, 1, 3, 3, 2, 3, 3, 2, 3, 3, 3, 2, 3, 3, 1, 2, 3, 2, 1, 1, 1, 1, 3, 3, 3, 3, 2, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 2, 3, 2, 1, 2, 2, 2, 3, 2, 1, 3, 2, 3, 2, 3, 2, 1, 1, 2, 3, 1, 3, 3, 3, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 3, 2, 1, 3, 3, 2, 2, 2, 3, 1, 2, 1, 1, 3, 2, 3, 2, 3, 2, 3, 3, 2, 2, 1, 3, 1, 2, 1, 3, 1, 1, 1, 3, 1, 1, 3, 3, 2, 2, 1, 3, 1, 1, 3, 2, 3, 1, 1, 3, 1, 3, 3, 1, 2, 3, 1, 3, 1, 1, 2, 1, 3, 1, 1, 1, 1, 2, 1, 3, 1, 2, 1, 3, 1, 3, 1, 1, 2, 2, 2, 3, 2, 2, 1, 2, 3, 3, 2, 3, 3, 3, 2, 3, 3, 1, 3, 2, 3, 2, 1, 2, 1, 1, 1, 2, 3, 2, 2, 1, 2, 2, 1, 3, 1, 3, 3, 3, 2, 2, 3, 3, 1, 2, 2, 2, 3, 1, 2, 1, 3, 1, 2, 3, 1, 1, 1, 2, 2, 3, 1, 3, 1, 1, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 2, 2, 3, 1, 3, 1, 2, 3, 2, 2, 3, 1, 2, 3, 2, 3, 1, 2, 2, 3, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 2, 3, 2, 1, 3, 3, 3, 1, 1, 3, 1, 2, 3, 3, 2, 2, 2, 1, 2, 3, 2, 2, 3, 2, 2, 2, 3, 3, 2, 1, 3, 2, 1, 3, 3, 1, 2, 3, 2, 1, 3, 3, 3, 1, 2, 2, 2, 3, 2, 3, 3, 1, 2, 1, 1, 2, 1, 3, 1, 2, 2, 1, 3, 2, 1, 3, 3, 2, 2, 2, 1, 2, 2, 1, 3, 1, 3, 1, 3, 3, 1, 1, 2, 3, 2, 2, 3, 1, 1, 1, 1, 3, 2, 2, 1, 3, 1, 2, 3, 1, 3, 1, 3, 1, 1, 3, 2, 3, 1, 1, 3, 3, 3, 3, 1, 3, 2, 2, 1, 1, 3, 3, 2, 2, 2, 1, 2, 1, 2, 1, 3, 2, 1, 2, 2, 3, 1, 2, 2, 2, 3, 2, 1, 2, 1, 2, 3, 3, 2, 3, 1, 1, 3, 3, 1, 2, 2, 2, 2, 2, 2, 1, 3, 3, 3, 3, 3, 1, 1, 3, 2, 1, 2, 1, 2, 2, 3, 2, 2, 2, 3, 1, 2, 1, 2, 2, 1, 1, 2, 3, 3, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 3, 3, 2, 3, 2, 3, 3, 2, 2, 1, 1, 1, 3, 3, 1, 1, 1, 3, 3, 2, 1, 2, 1, 1, 2, 2, 1, 1, 1, 3, 1, 1, 2, 3, 2, 2, 1, 3, 1, 2, 3, 1, 2, 2, 2, 2, 3, 2, 3, 3, 1, 2, 1, 2, 3, 1, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 1, 3, 3, 3]5-分析數(shù)據(jù):使用Matplotlib畫二維散點圖
下面的代碼里面有三分可視化的結(jié)果,但是我們可以在 Notebook中很明顯的看到每年獲取的飛行里程數(shù)和玩視頻游戲所消耗的時間百分比所構(gòu)成的坐標圖非常的清晰的分成三個部分,這就為我們后續(xù)的計算距離分類奠定基礎(chǔ)。
from numpy import zeros import numpy as np def file2matrix(filename): """ Desc: 導(dǎo)入訓(xùn)練數(shù)據(jù) Parameters: filename:數(shù)據(jù)文件路徑 return: 數(shù)據(jù)矩陣 returnMat 和對應(yīng)的類別 classLabelVector """ fr = open("datingTestSet2.txt") # 獲得文件中的數(shù)據(jù)行的行數(shù) numberOfLines = len(fr.readlines()) # 生成對應(yīng)的空矩陣 # 例如:zeros(2,3)就是生成一個 2*3 的矩陣,各個位置上全是0 returnMat = zeros((numberOfLines , 3)) # prepare matrix to return classLabelVector = [] fr = open("datingTestSet2.txt") index =0 for line in fr.readlines(): # str.strip([chars]) -- 返回已移除字符串頭尾指定字符所生成的新字符串 line = line.strip() # 以 切割字符串 listFromLine = line.split(" ") # 每列的屬性數(shù)據(jù) returnMat[index , : ] = listFromLine[0:3] # 每列的類別數(shù)據(jù),就是 label 標簽數(shù)據(jù) classLabelVector.append(int(listFromLine[-1])) index += 1 # 返回數(shù)據(jù)矩陣 returnMat 和對應(yīng)的類別 classLabelVector # print(returnMat,classLabelVector) return returnMat,classLabelVector # 因為 matplotlib 中不可顯示中文,所以使用本機自帶的字體進行替換 # 參考鏈接:https://www.cnblogs.com/pengsky2016/p/8126623.html # 該鏈接是本書的該可視化部分的詳細講解 非常不錯 from matplotlib.font_manager import FontProperties zhfont = FontProperties(fname="C:WindowsFontsmsyh.ttc",size=12) if __name__=="__main__": datingDataMat,datingLabels = file2matrix(1) # print(datingDataMat) # print(datingLabels) import matplotlib import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) from numpy import * datingLabels = np.array(datingLabels) # 每年獲取的飛行里程數(shù)-玩視頻游戲所消耗的事件百分比 # datingDataMat[idx_1,0] 中的參數(shù) 0 和 1 以及 2 就是我們所選擇的橫坐標和縱坐標的選取值 # 我們可以根據(jù)這三個值的變動來變動我們的坐標軸的選取方法 idx_1 = np.where(datingLabels==1) p1 = ax.scatter(datingDataMat[idx_1,0],datingDataMat[idx_1,1],marker = "*",color = "r",label="1",s=10) idx_2 = np.where(datingLabels==2) p2 = ax.scatter(datingDataMat[idx_2,0],datingDataMat[idx_2,1],marker = "o",color ="g",label="2",s=20) idx_3 = np.where(datingLabels==3) p3 = ax.scatter(datingDataMat[idx_3,0],datingDataMat[idx_3,1],marker = "+",color ="b",label="3",s=30) plt.xlabel(u"每年獲取的飛行里程數(shù)", fontproperties=zhfont) plt.ylabel(u"玩視頻游戲所消耗的事件百分比", fontproperties=zhfont) ax.legend((p1, p2, p3), (u"不喜歡", u"魅力一般", u"極具魅力"), loc=2, prop=zhfont) plt.show() # 玩視頻游戲所消耗的事件百分比-每周消耗的冰激凌公升數(shù) # datingLabels = np.array(datingLabels) # idx_1 = np.where(datingLabels==1) # p1 = ax.scatter(datingDataMat[idx_1,1],datingDataMat[idx_1,2],marker = "*",color = "r",label="1",s=10) # idx_2 = np.where(datingLabels==2) # p2 = ax.scatter(datingDataMat[idx_2,1],datingDataMat[idx_2,2],marker = "o",color ="g",label="2",s=20) # idx_3 = np.where(datingLabels==3) # p3 = ax.scatter(datingDataMat[idx_3,1],datingDataMat[idx_3,2],marker = "+",color ="b",label="3",s=30) # plt.xlabel(u"玩視頻游戲所消耗的事件百分比", fontproperties=zhfont) # plt.ylabel(u"", fontproperties=zhfont) # ax.legend((p1, p2, p3), (u"不喜歡", u"魅力一般", u"極具魅力"), loc=2, prop=zhfont) # plt.show() # 飛行??屠锍虜?shù) - 每周消耗的冰激凌公升數(shù) # datingLabels = np.array(datingLabels) # idx_1 = np.where(datingLabels==1) # p1 = ax.scatter(datingDataMat[idx_1,0],datingDataMat[idx_1,2],marker = "*",color = "r",label="1",s=10) # idx_2 = np.where(datingLabels==2) # p2 = ax.scatter(datingDataMat[idx_2,0],datingDataMat[idx_2,2],marker = "o",color ="g",label="2",s=20) # idx_3 = np.where(datingLabels==3) # p3 = ax.scatter(datingDataMat[idx_3,0],datingDataMat[idx_3,2],marker = "+",color ="b",label="3",s=30) # plt.xlabel(u"每年獲取的飛行里程數(shù)", fontproperties=zhfont) # plt.ylabel(u"玩視頻游戲所消耗的事件百分比", fontproperties=zhfont) # ax.legend((p1, p2, p3), (u"不喜歡", u"魅力一般", u"極具魅力"), loc=2, prop=zhfont) # plt.show()6-歸一化數(shù)值
歸一化數(shù)據(jù)是一個讓權(quán)重變?yōu)榻y(tǒng)一的過程,比如你要買進10噸鐵礦,用的人民幣和美元肯定不同,那么這10噸鐵礦的價值到底是多少,就需要一個統(tǒng)一的標準來衡量,全世界那么多國家,都要用自己國家的貨幣去買,到底該付多少就很迷茫。這時,規(guī)定用美元統(tǒng)一結(jié)算,各國按照本國貨幣對比美元的匯率,再加上10噸鐵礦的美元價值,就可以算出自己應(yīng)付多少本國貨幣。
序號 玩視頻游戲所耗時間百分比 每年獲得的飛行??屠锍虜?shù) 每周消耗的冰激凌公升數(shù) 樣本分類 1 0.8 400 0.5 1 2 12 134000 0.9 3 3 0 20000 1.1 2 4 67 32000 0.1 2
表2-2給出了提取的四組數(shù)據(jù),如果想要計算樣本3和樣本4之間的距離,可以使用下面的方法:
√((0?67)^2+(20 000 ?32 000)^2+(1.1 ?0.1)^2 )
我們很容易發(fā)現(xiàn),上面方程中數(shù)字差值最大的數(shù)學(xué)對計算結(jié)果的影響最大,也就是說,每年獲取的飛行??屠锍虜?shù)對于計算結(jié)果的影響遠遠大于表2-
在處理這種不同取值范圍的特征值時,我們通常采用的方法是將數(shù)值歸一化,如將取值范圍處理為0到1或-1到1之間。下面的公式可以將任意取值范圍的特征值轉(zhuǎn)換為0到1區(qū)間內(nèi)的值:
newValue = (oldValue - min ) / (max - min)
其中 min 和 max 分別是數(shù)據(jù)集中的最小特征值和最大特征值。雖然改變數(shù)值取值范圍增加了分類器的復(fù)雜度,但為了得到準確結(jié)果,我們必須這樣子做。我們需要在文件中增加一個新的函數(shù) autoNorm(),該函數(shù)可以自動將數(shù)字特征值轉(zhuǎn)換為0到1的區(qū)間。
2中其他兩個特征——玩視頻游戲和每周消費冰激凌公升數(shù)——的影響。而產(chǎn)生這種現(xiàn)象的唯一遠遠,僅僅是因為飛行??屠锍虜?shù)遠大于其他特征值。但海倫認為這三種特征是同等重要的,因此作為三個等權(quán)重的特征之一,飛行??屠锍虜?shù)并不應(yīng)該如此嚴重的影響到計算結(jié)果。
from numpy import zeros import numpy as np def file2matrix(filename): """ Desc: 導(dǎo)入訓(xùn)練數(shù)據(jù) Parameters: filename:數(shù)據(jù)文件路徑 return: 數(shù)據(jù)矩陣 returnMat 和對應(yīng)的類別 classLabelVector """ fr = open("datingTestSet2.txt") # 獲得文件中的數(shù)據(jù)行的行數(shù) numberOfLines = len(fr.readlines()) # 生成對應(yīng)的空矩陣 # 例如:zeros(2,3)就是生成一個 2*3 的矩陣,各個位置上全是0 returnMat = zeros((numberOfLines , 3)) # prepare matrix to return classLabelVector = [] fr = open("datingTestSet2.txt") index =0 for line in fr.readlines(): # str.strip([chars]) -- 返回已移除字符串頭尾指定字符所生成的新字符串 line = line.strip() # 以 切割字符串 listFromLine = line.split(" ") # 每列的屬性數(shù)據(jù) returnMat[index , : ] = listFromLine[0:3] # 每列的類別數(shù)據(jù),就是 label 標簽數(shù)據(jù) classLabelVector.append(int(listFromLine[-1])) index += 1 # 返回數(shù)據(jù)矩陣 returnMat 和對應(yīng)的類別 classLabelVector # print(returnMat,classLabelVector) return returnMat,classLabelVector def autoNorm(dataset): """ Desc: 歸一化特征值,消除特征之間量級不同導(dǎo)致的影響 parameter: dataset:數(shù)據(jù)集 return : 歸一化后的數(shù)據(jù)集 normDataSet , ranges 和 minVals 即最小值與范圍,并沒有歸一化公式 歸一化公式: Y=(X-Xmin)/(Xmax - Xmin) 其中的 min 和 max 分別是數(shù)據(jù)集中的最小特征值和最大特征值,該函數(shù)可以自動將數(shù)字特征值轉(zhuǎn)化為0到1的區(qū)間 """ # 計算每種屬性的最大值、最小值、范圍 minVals = dataset.min(0) maxVals = dataset.max(0) ranges = maxVals - minVals # 極差 normDataSet = zeros(shape(dataset)) m = dataset.shape[0] #生成與最小值之差組成的矩陣 # 因為特征值矩陣有1000 * 3 個值,而 minVals 和 range 的值都為1x3, # 為了解決這個問題,我們使用Numpy庫中的tile()函數(shù)將變量內(nèi)容復(fù)制成輸入矩陣同樣大小的矩陣, # 注意這是具體特征值相除,而不是矩陣除法,否則還需要使用函數(shù)linalg.solve(matA,matB) normDataSet = dataset - tile(minVals, (m,1)) # 將最小值之差除以范圍組成矩陣 normDataSet = normDataSet / tile(ranges, (m,1)) return normDataSet,range,minVals if __name__=="__main__": datingDataMat,datingLabels = file2matrix(1) normMat,ranges,minVals = autoNorm(datingDataMat) print(normMat) print(range) print(minVals)7-訓(xùn)練算法
這個是核心內(nèi)容,即計算各個標記點之間的距離并返回k個標記點內(nèi)出現(xiàn)次數(shù)最多的標簽。
對于每一個在數(shù)據(jù)集中的數(shù)據(jù)點: 計算目標的數(shù)據(jù)點(需要分類的數(shù)據(jù)點) 與該數(shù)據(jù)點的距離 將距離排序:從小到大 選取k個最短距離 選取這k個最多的分類類別 返回該類別來作為目標數(shù)據(jù)點的預(yù)測值
整個訓(xùn)練算法和之前的電影分類的算法是一致的,該算法進化的部分即對數(shù)據(jù)進行了歸一化處理,導(dǎo)致我們傳入進去的數(shù)據(jù)也需要進行歸一化處理。
# 訓(xùn)練算法 # 詳解 k-nn訓(xùn)練算法 :https://www.cnblogs.com/BaiYiShaoNian/p/4567446.html def classify0(inX,dataSet,labels,k): """ :param inX: 用于分類的輸入向量 :param dataSet: 訓(xùn)練樣本集合 :param labels: 標簽向量 :param k: K-NN中的k """ # shape 是array的屬性 ,描述一個多維數(shù)組的維度 dataSetSize = dataSet.shape[0] # 距離度量 度量公式為歐式距離 """ tile(inX,(dataSetSize,1)) : 把 inX 二維數(shù)組化,dataSetSize 表示生成數(shù)組后的行數(shù) 1 表示列的倍數(shù),整個這一行代表表示前一個二維數(shù)組矩陣的每一個元素減去后一個數(shù)組對應(yīng)的元素值 這樣子就實現(xiàn)了矩陣之間的減法,簡單方便 """ diffMat = tile(inX,(dataSetSize,1)) - dataSet sqDiffMat = diffMat ** 2 sqDistances = sqDiffMat.sum(axis=1) # axis=1 表示矩陣中行之間數(shù)的求和 axis=0表示列之間數(shù)的求和 distances = sqDistances ** 0.5 # 將距離排序:從小到大 # 關(guān)鍵是傳回的是位置索引 而這個索引就可以得到在標簽中所對應(yīng)位置的標簽 sortedDistIndicies = distances.argsort() #選取前k個最短距離,選取這k個中最多的分類類別 classCount = {} # print(labels) for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] # 這一行是python語法 看不懂基礎(chǔ)問題 # get()該方法是訪問字典項的方法,即訪問下標為 voteIlabel的項,如果沒有這一項,那么初始值為0 # 然后把這一項的值加1 classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 import operator sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1),reverse = True) return sortedClassCount[0][0]8-測試分類錯誤所占百分比
該函數(shù)的代碼是統(tǒng)計該KNN算法的實現(xiàn)效果,抽取一部分的數(shù)據(jù)作為數(shù)據(jù)集,進行測試然后統(tǒng)計測試錯誤的百分比
# 測試分類錯誤,錯誤分辨?zhèn)€數(shù) def datingClassTest(): hoRatio = 0.08 # 隨機挖去 10% 的數(shù)據(jù)作為測試集 datingDataMat,datingLabels = file2matrix("datingTestSet2.txt") # 加載數(shù)據(jù)文件 normMat, ranges, minVals = autoNorm(datingDataMat) m = normMat.shape[0] numTestVecs = int(m*hoRatio) # 隨機挖去的行數(shù) errorCount = 0.0 for i in range(numTestVecs): # 前numTestVecs條作為測試集(一個一個測試),后面的數(shù)據(jù)作為訓(xùn)練樣本,訓(xùn)練樣本的標簽,3個近鄰 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 number of errr is: %d" % int(errorCount)) print("The total error rate is: %f" % (errorCount / float(numTestVecs))) >>>The number of errr is: 2 >>>The total error rate is: 0.0250009-實踐算法:調(diào)用算法接口進行預(yù)測
直接在主函數(shù)中使用該函數(shù)調(diào)用數(shù)據(jù)預(yù)處理函數(shù)傳入數(shù)據(jù)、調(diào)用歸一化數(shù)據(jù)處理函數(shù)歸一化數(shù)據(jù)、調(diào)用訓(xùn)練算法傳入數(shù)據(jù)進行預(yù)測,最后輸出算法判斷后的結(jié)論。
# 實踐算法 def validateTest(): resultList = ["not at all", "in small doses", "in large doses"] percentTats = float(input("percentage of time spent playing video games ?")) ffMiles = float(input("frequent filer 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 = array([ffMiles, percentTats, iceCream]) # print(str(inArr),str(minVals),str(ranges),normMat,datingLabels) # 為什么傳入的值需要進行 如下操作呢 (inArry - minVals)/range # 因為我們之前傳入的值都是進行過歸一化的 # 但是如果直接傳入值會過大 所以我們在前面的歸一化操作中將兩個參數(shù)傳過來就是為了這里使用 # 但是這里傳入的測試參數(shù)也是一個1x3的舉證 所有 minVals 和 ranges 不需要進行 tile化 classifierResult = classify0((inArr - minVals) / ranges, normMat, datingLabels, 3) print("You will probably like this person: ", resultList[classifierResult - 1]) # 主函數(shù) if __name__ == "__main__": # 實踐算法 validateTest() >>>percentage of time spent playing video games ?10 >>>frequent filer miles earned per year?10000 >>>liters of ice cream consumed per year?0.5 >>>You will probably like this person: in small doses10-完整代碼
from numpy import zeros import numpy as np from numpy import * import operator # 數(shù)據(jù)預(yù)處理 def file2matrix(filename): """ Desc: 導(dǎo)入訓(xùn)練數(shù)據(jù) Parameters: filename:數(shù)據(jù)文件路徑 return: 數(shù)據(jù)矩陣 returnMat 和對應(yīng)的類別 classLabelVector """ fr = open("datingTestSet2.txt") # 獲得文件中的數(shù)據(jù)行的行數(shù) numberOfLines = len(fr.readlines()) # 生成對應(yīng)的空矩陣 # 例如:zeros(2,3)就是生成一個 2*3 的矩陣,各個位置上全是0 returnMat = zeros((numberOfLines, 3)) # prepare matrix to return classLabelVector = [] fr = open("datingTestSet2.txt") index = 0 for line in fr.readlines(): # str.strip([chars]) -- 返回已移除字符串頭尾指定字符所生成的新字符串 line = line.strip() # 以 切割字符串 listFromLine = line.split(" ") # 每列的屬性數(shù)據(jù) returnMat[index, :] = listFromLine[0:3] # 每列的類別數(shù)據(jù),就是 label 標簽數(shù)據(jù) classLabelVector.append(int(listFromLine[-1])) index += 1 # 返回數(shù)據(jù)矩陣 returnMat 和對應(yīng)的類別 classLabelVector # print(returnMat,classLabelVector) return returnMat, classLabelVector # 因為 matplotlib 中不可顯示中文,所以使用本機自帶的字體進行替換 # 參考鏈接:https://www.cnblogs.com/pengsky2016/p/8126623.html # 該鏈接是本書的該可視化部分的詳細講解 非常不錯 from matplotlib.font_manager import FontProperties zhfont = FontProperties(fname="C:WindowsFontsmsyh.ttc", size=12) # 歸一化特征值 def autoNorm(dataset): """ Desc: 歸一化特征值,消除特征之間量級不同導(dǎo)致的影響 parameter: dataset:數(shù)據(jù)集 return : 歸一化后的數(shù)據(jù)集 normDataSet , ranges 和 minVals 即最小值與范圍,并沒有歸一化公式 歸一化公式: Y=(X-Xmin)/(Xmax - Xmin) 其中的 min 和 max 分別是數(shù)據(jù)集中的最小特征值和最大特征值,該函數(shù)可以自動將數(shù)字特征值轉(zhuǎn)化為0到1的區(qū)間 """ # 計算每種屬性的最大值、最小值、范圍 minVals = dataset.min(0) maxVals = dataset.max(0) ranges = maxVals - minVals # 極差 normDataSet = zeros(shape(dataset)) m = dataset.shape[0] #生成與最小值之差組成的矩陣 # 因為特征值矩陣有1000 * 3 個值,而 minVals 和 range 的值都為1x3, # 為了解決這個問題,我們使用Numpy庫中的tile()函數(shù)將變量內(nèi)容復(fù)制成輸入矩陣同樣大小的矩陣, # 注意這是具體特征值相除,而不是矩陣除法,否則還需要使用函數(shù)linalg.solve(matA,matB) normDataSet = dataset - tile(minVals, (m,1)) # 將最小值之差除以范圍組成矩陣 normDataSet = normDataSet / tile(ranges, (m,1)) return normDataSet,ranges,minVals # 訓(xùn)練算法 # 詳解 k-nn訓(xùn)練算法 :https://www.cnblogs.com/BaiYiShaoNian/p/4567446.html def classify0(inX,dataSet,labels,k): """ :param inX: 用于分類的輸入向量 :param dataSet: 訓(xùn)練樣本集合 :param labels: 標簽向量 :param k: K-NN中的k """ # shape 是array的屬性 ,描述一個多維數(shù)組的維度 dataSetSize = dataSet.shape[0] # 距離度量 度量公式為歐式距離 """ tile(inX,(dataSetSize,1)) : 把 inX 二維數(shù)組化,dataSetSize 表示生成數(shù)組后的行數(shù) 1 表示列的倍數(shù),整個這一行代表表示前一個二維數(shù)組矩陣的每一個元素減去后一個數(shù)組對應(yīng)的元素值 這樣子就實現(xiàn)了矩陣之間的減法,簡單方便 """ diffMat = tile(inX,(dataSetSize,1)) - dataSet sqDiffMat = diffMat ** 2 sqDistances = sqDiffMat.sum(axis=1) # axis=1 表示矩陣中行之間數(shù)的求和 axis=0表示列之間數(shù)的求和 distances = sqDistances ** 0.5 # 將距離排序:從小到大 # 關(guān)鍵是傳回的是位置索引 而這個索引就可以得到在標簽中所對應(yīng)位置的標簽 sortedDistIndicies = distances.argsort() #選取前k個最短距離,選取這k個中最多的分類類別 classCount = {} # print(labels) for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] # 這一行是python語法 看不懂基礎(chǔ)問題 # get()該方法是訪問字典項的方法,即訪問下標為 voteIlabel的項,如果沒有這一項,那么初始值為0 # 然后把這一項的值加1 classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 import operator sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1),reverse = True) return sortedClassCount[0][0] # 測試分類錯誤,錯誤分辨?zhèn)€數(shù) def datingClassTest(): hoRatio = 0.08 # 隨機挖去 10% 的數(shù)據(jù)作為測試集 datingDataMat,datingLabels = file2matrix("datingTestSet2.txt") # 加載數(shù)據(jù)文件 normMat, ranges, minVals = autoNorm(datingDataMat) m = normMat.shape[0] numTestVecs = int(m*hoRatio) # 隨機挖去的行數(shù) errorCount = 0.0 for i in range(numTestVecs): # 前numTestVecs條作為測試集(一個一個測試),后面的數(shù)據(jù)作為訓(xùn)練樣本,訓(xùn)練樣本的標簽,3個近鄰 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 number of errr is: %d" % int(errorCount)) print("The total error rate is: %f" % (errorCount / float(numTestVecs))) # 實踐算法 def validateTest(): resultList = ["not at all", "in small doses", "in large doses"] percentTats = float(input("percentage of time spent playing video games ?")) ffMiles = float(input("frequent filer 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 = array([ffMiles, percentTats, iceCream]) # print(str(inArr),str(minVals),str(ranges),normMat,datingLabels) # 為什么傳入的值需要進行 如下操作呢 (inArry - minVals)/range # 因為我們之前傳入的值都是進行過歸一化的 # 但是如果直接傳入值會過大 所以我們在前面的歸一化操作中將兩個參數(shù)傳過來就是為了這里使用 # 但是這里傳入的測試參數(shù)也是一個1x3的舉證 所有 minVals 和 ranges 不需要進行 tile化 classifierResult = classify0((inArr - minVals) / ranges, normMat, datingLabels, 3) print("You will probably like this person: ", resultList[classifierResult - 1]) # 主函數(shù) if __name__ == "__main__": # 實踐算法 validateTest() # 測試分類錯誤:判斷程序的可行性 print("這是輸出判斷算法優(yōu)越性的結(jié)果:") datingClassTest()
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/45220.html
摘要:簡介源于數(shù)據(jù)挖掘的一個作業(yè),這里用來實現(xiàn)一下這個機器學(xué)習(xí)中最簡單的算法之一算法最近鄰分類法。其實這些標簽就對應(yīng)于機器學(xué)習(xí)中的特征這一重要概念,而訓(xùn)練我們識別的過程就對應(yīng)于泛化這一概念。 1. 簡介 源于數(shù)據(jù)挖掘的一個作業(yè), 這里用Node.js來實現(xiàn)一下這個機器學(xué)習(xí)中最簡單的算法之一k-nearest-neighbor算法(k最近鄰分類法)。 k-nearest-neighbor-cl...
摘要:一定義二個人理解其實簡單理解就是通過計算新加入點與附近個點的距離,然后尋找到距離最近的個點,進行占比統(tǒng)計,找到個點中數(shù)量占比最高的,那么新加入的樣本,它的就是頻數(shù)最高的三實踐語言歐拉距離樣本繪圖計算距離歐拉距離求出和相 一、定義 url:https://en.wikipedia.org/wiki... In pattern recognition, the k-nearest neig...
摘要:在本教程中,我們將學(xué)習(xí)如何使用八叉樹在點云數(shù)據(jù)中進行空間分區(qū)和鄰居搜索。因此,搜索點和搜索結(jié)果之間的距離取決于八叉樹的分辨率參數(shù)。此外,先進的內(nèi)存管理減少了八叉樹構(gòu)建過程中的內(nèi)存分配和釋放操作??偨Y(jié)八叉樹實現(xiàn)是空間分區(qū)和搜索操作的強大工具。 本教程代碼開源:GitHub 歡迎st...
k近鄰(k-Nearest Neighbor,kNN)算法是經(jīng)典的帶監(jiān)督的分類算法,核心思想是如果一個樣本在特征空間中的k個最相鄰的樣本中的大多數(shù)屬于某一個類別,則針對該樣本的劃分結(jié)果也屬于這個類別。 1. 算法步驟 準備訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù); 確定參數(shù) k; 計算測試數(shù)據(jù)與各個訓(xùn)練數(shù)據(jù)之間的距離,距離的遞增關(guān)系進行排序; 選取距離最小的 k 個點; 確定前 k 個點所在類別的出現(xiàn)頻率; 返回前 ...
閱讀 1901·2021-11-22 09:34
閱讀 3039·2021-09-28 09:35
閱讀 13474·2021-09-09 11:34
閱讀 3603·2019-08-29 16:25
閱讀 2834·2019-08-29 15:23
閱讀 2048·2019-08-28 17:55
閱讀 2438·2019-08-26 17:04
閱讀 3053·2019-08-26 12:21