摘要:而產(chǎn)生這種現(xiàn)象的唯一遠(yuǎn)遠(yuǎn),僅僅是因?yàn)轱w行??屠锍虜?shù)遠(yuǎn)大于其他特征值。但海倫認(rèn)為這三種特征是同等重要的,因此作為三個(gè)等權(quán)重的特征之一,飛行??屠锍虜?shù)并不應(yīng)該如此嚴(yán)重的影響到計(jì)算結(jié)果。
一、KNN概述
簡單的說,k-近鄰算法采用測(cè)量不同特征值之間的距離方法進(jìn)行分類。
優(yōu)點(diǎn):精度高、對(duì)異常值不敏感、無數(shù)據(jù)輸入假定
缺點(diǎn):計(jì)算復(fù)雜度高、空間復(fù)雜度高
適用數(shù)據(jù)范圍:數(shù)值型和標(biāo)稱型
1.1 工作原理KNN可以說是最簡單的分類算法之一,同時(shí),它也是最常見的分類算法之一,注意KNN算法是有監(jiān)督學(xué)習(xí)的分類算法,它看起來和另外一個(gè)機(jī)器學(xué)習(xí)算法Kmeans有點(diǎn)像(Kmeans是無監(jiān)督學(xué)習(xí)算法)。
其工作原理是使用一個(gè)樣本數(shù)據(jù)集合,也稱為訓(xùn)練樣本集,并且樣本集中每個(gè)數(shù)據(jù)都存在標(biāo)簽,即我們知道樣本集中每一數(shù)據(jù)與所屬分類的對(duì)應(yīng)關(guān)系。輸入沒有標(biāo)簽的新數(shù)據(jù)后,將新數(shù)據(jù)的每個(gè)特征與樣本集中的數(shù)據(jù)對(duì)應(yīng)的特征進(jìn)行比較,然后算法提取樣本集中特征最相似(最近鄰)的分類標(biāo)簽。一般來說,我們只選擇樣本集中前k個(gè)最相似的數(shù)據(jù),這就是KNN中K的出處,最后使用Majority-Voting(多數(shù)表決)選擇k個(gè)最相似數(shù)據(jù)中次數(shù)出現(xiàn)最多的分類,作為新數(shù)據(jù)的分類。
1.2 三要素K的取值:可以使用Cross Validation(交叉驗(yàn)證)來選取合適的值
我們?cè)撊绾芜x擇合適的k值呢?通過將樣本數(shù)據(jù)按照一定比例,拆分出訓(xùn)練用的數(shù)據(jù)和驗(yàn)證用的數(shù)據(jù),比如6:4拆出訓(xùn)練數(shù)據(jù)和驗(yàn)證數(shù)據(jù),從選取一個(gè)較小的k值開始,不斷增加k的值,然后計(jì)算驗(yàn)證集合的方差,最終找到一個(gè)比較合適的k值。
距離度量 Metric / Distance Measure:距離度量一般都使用 Euclidean distance(歐氏距離)
二維空間兩個(gè)點(diǎn)的歐式距離公式如下
分類決策 Deision rule:分類決策即Majority-Voting ,選取票數(shù)最多的標(biāo)簽,在回歸中通常為k個(gè)最鄰近點(diǎn)的標(biāo)簽的平均值
1.3 在什么時(shí)候選擇KNN算法 二、實(shí)踐案例(主要重點(diǎn)是可視化) 2.1 實(shí)例一 :電影分類電影名稱 打斗鏡頭 接吻鏡頭 電影類型 Californla Man 3 104 愛情片 He`s Not Really into Dudes 2 100 愛情片 Beautiful Woman 1 81 愛情片 Kevin Longblade 101 10 動(dòng)作片 Robo Slayer 3000 99 5 動(dòng)作片 Ampedll 98 2 動(dòng)作片 ? 18 90 未知
首先我們通過 Python 的第三方庫進(jìn)行數(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近鄰算法最核心的部分就是歐式距離的計(jì)算,通過計(jì)算得到距離最近的k個(gè)數(shù)的標(biāo)簽,統(tǒng)計(jì)出現(xiàn)次數(shù)最多的標(biāo)簽,將其賦值給新數(shù)據(jù)。下面這段代碼就是KNN算法最基本的實(shí)例。通過傳入數(shù)據(jù)來預(yù)測(cè)電影的標(biāo)簽是什么!
from numpy import * import operator # 電影分類 # 歐式距離求解返回前k個(gè)標(biāo)簽 然后匯總出現(xiàn)次數(shù)最多的標(biāo)簽 def classify0(inX, dataSet, labels, k): dataSetSize = dataSet.shape[0] # 求inX與數(shù)據(jù)集中各個(gè)樣本的歐氏距離 diffMat = tile(inX, (dataSetSize,1)) - dataSet # numpy中的tile函數(shù)將inX復(fù)制為重復(fù)的dataSize個(gè)行和重復(fù)的1列,功能相當(dāng)于MATLAB中的repmat sqDiffMat = diffMat**2 sqDistances = sqDiffMat.sum(axis=1) # 按照x軸相加 distances = sqDistances**0.5 # print(distances) sortedDistIndicies = distances.argsort() # 從小到大排序后,返回索引 # 這個(gè)返回索引是關(guān)鍵 只有理解了這個(gè)返回索引才能理解k-nn算法 # print(sortedDistIndicies) # 字典,key存儲(chǔ)第i小的標(biāo)簽值,value為標(biāo)簽的次數(shù) classCount = {} for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] # 取第i個(gè)小的標(biāo)簽值 # print(sortedDistIndicies[i]) classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 # 根據(jù)標(biāo)簽統(tǒng)計(jì)標(biāo)簽次數(shù),如果沒找到返回0。統(tǒng)計(jì)前k個(gè)候選者中標(biāo)簽出現(xiàn)的次數(shù) sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # operator.itemgetter(1) 按照第2個(gè)元素,即標(biāo)簽出現(xiàn)的次數(shù)對(duì)classCount從大到小排序 # print(sortedClassCount) # 測(cè)試結(jié)果 [("B", 2), ("A", 1)] return sortedClassCount[0][0] # 返回最終的類別,即標(biāo)簽值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 # 測(cè)試代碼 group, labels = createDataSet() ans = classify0([18,90], group, labels, 3) print(ans) >>> A2.2 實(shí)例二:優(yōu)化約會(huì)匹配效果 1-項(xiàng)目概論
海倫使用約會(huì)網(wǎng)站尋求約會(huì)對(duì)象,經(jīng)過一段實(shí)踐之后,她發(fā)現(xiàn)曾交往過三類人:
不喜歡的人
魅力一般的人
極具魅力的人
她希望:
工作日與魅力一般的人約會(huì)
周末與極具魅力的人約會(huì)
不喜歡的人則直接排除掉
現(xiàn)在她收集到了一些約會(huì)網(wǎng)站未曾記錄的數(shù)據(jù)信息,這更有助于匹配對(duì)象的歸類。
2-開發(fā)流程1. 收集數(shù)據(jù):提供文本文件 2. 準(zhǔn)本數(shù)據(jù):使用Python解析文本文件 3. 分析數(shù)據(jù):使用Matplotlib 畫二維散點(diǎn)圖 4. 訓(xùn)練算法:此步驟不適用與KNN算法,但是也很重要 5. 測(cè)試數(shù)據(jù):使用海倫提供的部分?jǐn)?shù)據(jù)作為測(cè)試樣本 6. 使用算法:產(chǎn)生簡單的命令行程序,然后海倫可以輸入一些特征數(shù)據(jù)以判斷對(duì)方是否為自己喜歡的類型
測(cè)試樣本與非測(cè)試樣本的區(qū)別在于:
測(cè)試樣本是以及完成分類的數(shù)據(jù),如果測(cè)試分類與實(shí)際類不同,則標(biāo)記為一個(gè)錯(cuò)誤
海倫把這些約會(huì)對(duì)象的數(shù)據(jù)存放在文本文件 datingTestSet2.txt 中,總共有1000行,海倫約會(huì)的對(duì)象主要包含以下3種特征:
每年獲得的飛行常客里程數(shù)
玩視頻游戲所耗費(fèi)時(shí)間百分比
每周消費(fèi)的冰激凌公升數(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-準(zhǔn)備數(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 和對(duì)應(yīng)的類別 classLabelVector """ fr = open("datingTestSet2.txt") # 獲得文件中的數(shù)據(jù)行的行數(shù) numberOfLines = len(fr.readlines()) # 生成對(duì)應(yīng)的空矩陣 # 例如:zeros(2,3)就是生成一個(gè) 2*3 的矩陣,各個(gè)位置上全是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 標(biāo)簽數(shù)據(jù) classLabelVector.append(int(listFromLine[-1])) index += 1 # 返回?cái)?shù)據(jù)矩陣 returnMat 和對(duì)應(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畫二維散點(diǎn)圖
下面的代碼里面有三分可視化的結(jié)果,但是我們可以在 Notebook中很明顯的看到每年獲取的飛行里程數(shù)和玩視頻游戲所消耗的時(shí)間百分比所構(gòu)成的坐標(biāo)圖非常的清晰的分成三個(gè)部分,這就為我們后續(xù)的計(jì)算距離分類奠定基礎(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 和對(duì)應(yīng)的類別 classLabelVector """ fr = open("datingTestSet2.txt") # 獲得文件中的數(shù)據(jù)行的行數(shù) numberOfLines = len(fr.readlines()) # 生成對(duì)應(yīng)的空矩陣 # 例如:zeros(2,3)就是生成一個(gè) 2*3 的矩陣,各個(gè)位置上全是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 標(biāo)簽數(shù)據(jù) classLabelVector.append(int(listFromLine[-1])) index += 1 # 返回?cái)?shù)據(jù)矩陣 returnMat 和對(duì)應(yīng)的類別 classLabelVector # print(returnMat,classLabelVector) return returnMat,classLabelVector # 因?yàn)?matplotlib 中不可顯示中文,所以使用本機(jī)自帶的字體進(jìn)行替換 # 參考鏈接:https://www.cnblogs.com/pengsky2016/p/8126623.html # 該鏈接是本書的該可視化部分的詳細(xì)講解 非常不錯(cuò) 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 就是我們所選擇的橫坐標(biāo)和縱坐標(biāo)的選取值 # 我們可以根據(jù)這三個(gè)值的變動(dòng)來變動(dòng)我們的坐標(biāo)軸的選取方法 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ù)是一個(gè)讓權(quán)重變?yōu)榻y(tǒng)一的過程,比如你要買進(jìn)10噸鐵礦,用的人民幣和美元肯定不同,那么這10噸鐵礦的價(jià)值到底是多少,就需要一個(gè)統(tǒng)一的標(biāo)準(zhǔn)來衡量,全世界那么多國家,都要用自己國家的貨幣去買,到底該付多少就很迷茫。這時(shí),規(guī)定用美元統(tǒng)一結(jié)算,各國按照本國貨幣對(duì)比美元的匯率,再加上10噸鐵礦的美元價(jià)值,就可以算出自己應(yīng)付多少本國貨幣。
序號(hào) 玩視頻游戲所耗時(shí)間百分比 每年獲得的飛行??屠锍虜?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ù),如果想要計(jì)算樣本3和樣本4之間的距離,可以使用下面的方法:
√((0?67)^2+(20 000 ?32 000)^2+(1.1 ?0.1)^2 )
我們很容易發(fā)現(xiàn),上面方程中數(shù)字差值最大的數(shù)學(xué)對(duì)計(jì)算結(jié)果的影響最大,也就是說,每年獲取的飛行??屠锍虜?shù)對(duì)于計(jì)算結(jié)果的影響遠(yuǎn)遠(yuǎn)大于表2-
在處理這種不同取值范圍的特征值時(shí),我們通常采用的方法是將數(shù)值歸一化,如將取值范圍處理為0到1或-1到1之間。下面的公式可以將任意取值范圍的特征值轉(zhuǎn)換為0到1區(qū)間內(nèi)的值:
newValue = (oldValue - min ) / (max - min)
其中 min 和 max 分別是數(shù)據(jù)集中的最小特征值和最大特征值。雖然改變數(shù)值取值范圍增加了分類器的復(fù)雜度,但為了得到準(zhǔn)確結(jié)果,我們必須這樣子做。我們需要在文件中增加一個(gè)新的函數(shù) autoNorm(),該函數(shù)可以自動(dòng)將數(shù)字特征值轉(zhuǎn)換為0到1的區(qū)間。
2中其他兩個(gè)特征——玩視頻游戲和每周消費(fèi)冰激凌公升數(shù)——的影響。而產(chǎn)生這種現(xiàn)象的唯一遠(yuǎn)遠(yuǎn),僅僅是因?yàn)轱w行常客里程數(shù)遠(yuǎn)大于其他特征值。但海倫認(rèn)為這三種特征是同等重要的,因此作為三個(gè)等權(quán)重的特征之一,飛行??屠锍虜?shù)并不應(yīng)該如此嚴(yán)重的影響到計(jì)算結(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 和對(duì)應(yīng)的類別 classLabelVector """ fr = open("datingTestSet2.txt") # 獲得文件中的數(shù)據(jù)行的行數(shù) numberOfLines = len(fr.readlines()) # 生成對(duì)應(yīng)的空矩陣 # 例如:zeros(2,3)就是生成一個(gè) 2*3 的矩陣,各個(gè)位置上全是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 標(biāo)簽數(shù)據(jù) classLabelVector.append(int(listFromLine[-1])) index += 1 # 返回?cái)?shù)據(jù)矩陣 returnMat 和對(duì)應(yīng)的類別 classLabelVector # print(returnMat,classLabelVector) return returnMat,classLabelVector def autoNorm(dataset): """ Desc: 歸一化特征值,消除特征之間量級(jí)不同導(dǎo)致的影響 parameter: dataset:數(shù)據(jù)集 return : 歸一化后的數(shù)據(jù)集 normDataSet , ranges 和 minVals 即最小值與范圍,并沒有歸一化公式 歸一化公式: Y=(X-Xmin)/(Xmax - Xmin) 其中的 min 和 max 分別是數(shù)據(jù)集中的最小特征值和最大特征值,該函數(shù)可以自動(dòng)將數(shù)字特征值轉(zhuǎn)化為0到1的區(qū)間 """ # 計(jì)算每種屬性的最大值、最小值、范圍 minVals = dataset.min(0) maxVals = dataset.max(0) ranges = maxVals - minVals # 極差 normDataSet = zeros(shape(dataset)) m = dataset.shape[0] #生成與最小值之差組成的矩陣 # 因?yàn)樘卣髦稻仃囉?000 * 3 個(gè)值,而 minVals 和 range 的值都為1x3, # 為了解決這個(gè)問題,我們使用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)練算法
這個(gè)是核心內(nèi)容,即計(jì)算各個(gè)標(biāo)記點(diǎn)之間的距離并返回k個(gè)標(biāo)記點(diǎn)內(nèi)出現(xiàn)次數(shù)最多的標(biāo)簽。
對(duì)于每一個(gè)在數(shù)據(jù)集中的數(shù)據(jù)點(diǎn): 計(jì)算目標(biāo)的數(shù)據(jù)點(diǎn)(需要分類的數(shù)據(jù)點(diǎn)) 與該數(shù)據(jù)點(diǎn)的距離 將距離排序:從小到大 選取k個(gè)最短距離 選取這k個(gè)最多的分類類別 返回該類別來作為目標(biāo)數(shù)據(jù)點(diǎn)的預(yù)測(cè)值
整個(gè)訓(xùn)練算法和之前的電影分類的算法是一致的,該算法進(jìn)化的部分即對(duì)數(shù)據(jù)進(jìn)行了歸一化處理,導(dǎo)致我們傳入進(jìn)去的數(shù)據(jù)也需要進(jìn)行歸一化處理。
# 訓(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: 標(biāo)簽向量 :param k: K-NN中的k """ # shape 是array的屬性 ,描述一個(gè)多維數(shù)組的維度 dataSetSize = dataSet.shape[0] # 距離度量 度量公式為歐式距離 """ tile(inX,(dataSetSize,1)) : 把 inX 二維數(shù)組化,dataSetSize 表示生成數(shù)組后的行數(shù) 1 表示列的倍數(shù),整個(gè)這一行代表表示前一個(gè)二維數(shù)組矩陣的每一個(gè)元素減去后一個(gè)數(shù)組對(duì)應(yīng)的元素值 這樣子就實(shí)現(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)鍵是傳回的是位置索引 而這個(gè)索引就可以得到在標(biāo)簽中所對(duì)應(yīng)位置的標(biāo)簽 sortedDistIndicies = distances.argsort() #選取前k個(gè)最短距離,選取這k個(gè)中最多的分類類別 classCount = {} # print(labels) for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] # 這一行是python語法 看不懂基礎(chǔ)問題 # get()該方法是訪問字典項(xiàng)的方法,即訪問下標(biāo)為 voteIlabel的項(xiàng),如果沒有這一項(xiàng),那么初始值為0 # 然后把這一項(xiàng)的值加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-測(cè)試分類錯(cuò)誤所占百分比
該函數(shù)的代碼是統(tǒng)計(jì)該KNN算法的實(shí)現(xiàn)效果,抽取一部分的數(shù)據(jù)作為數(shù)據(jù)集,進(jìn)行測(cè)試然后統(tǒng)計(jì)測(cè)試錯(cuò)誤的百分比
# 測(cè)試分類錯(cuò)誤,錯(cuò)誤分辨?zhèn)€數(shù) def datingClassTest(): hoRatio = 0.08 # 隨機(jī)挖去 10% 的數(shù)據(jù)作為測(cè)試集 datingDataMat,datingLabels = file2matrix("datingTestSet2.txt") # 加載數(shù)據(jù)文件 normMat, ranges, minVals = autoNorm(datingDataMat) m = normMat.shape[0] numTestVecs = int(m*hoRatio) # 隨機(jī)挖去的行數(shù) errorCount = 0.0 for i in range(numTestVecs): # 前numTestVecs條作為測(cè)試集(一個(gè)一個(gè)測(cè)試),后面的數(shù)據(jù)作為訓(xùn)練樣本,訓(xùn)練樣本的標(biāo)簽,3個(gè)近鄰 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-實(shí)踐算法:調(diào)用算法接口進(jìn)行預(yù)測(cè)
直接在主函數(shù)中使用該函數(shù)調(diào)用數(shù)據(jù)預(yù)處理函數(shù)傳入數(shù)據(jù)、調(diào)用歸一化數(shù)據(jù)處理函數(shù)歸一化數(shù)據(jù)、調(diào)用訓(xùn)練算法傳入數(shù)據(jù)進(jìn)行預(yù)測(cè),最后輸出算法判斷后的結(jié)論。
# 實(shí)踐算法 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) # 為什么傳入的值需要進(jìn)行 如下操作呢 (inArry - minVals)/range # 因?yàn)槲覀冎皞魅氲闹刀际沁M(jìn)行過歸一化的 # 但是如果直接傳入值會(huì)過大 所以我們?cè)谇懊娴臍w一化操作中將兩個(gè)參數(shù)傳過來就是為了這里使用 # 但是這里傳入的測(cè)試參數(shù)也是一個(gè)1x3的舉證 所有 minVals 和 ranges 不需要進(jìn)行 tile化 classifierResult = classify0((inArr - minVals) / ranges, normMat, datingLabels, 3) print("You will probably like this person: ", resultList[classifierResult - 1]) # 主函數(shù) if __name__ == "__main__": # 實(shí)踐算法 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 和對(duì)應(yīng)的類別 classLabelVector """ fr = open("datingTestSet2.txt") # 獲得文件中的數(shù)據(jù)行的行數(shù) numberOfLines = len(fr.readlines()) # 生成對(duì)應(yīng)的空矩陣 # 例如:zeros(2,3)就是生成一個(gè) 2*3 的矩陣,各個(gè)位置上全是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 標(biāo)簽數(shù)據(jù) classLabelVector.append(int(listFromLine[-1])) index += 1 # 返回?cái)?shù)據(jù)矩陣 returnMat 和對(duì)應(yīng)的類別 classLabelVector # print(returnMat,classLabelVector) return returnMat, classLabelVector # 因?yàn)?matplotlib 中不可顯示中文,所以使用本機(jī)自帶的字體進(jìn)行替換 # 參考鏈接:https://www.cnblogs.com/pengsky2016/p/8126623.html # 該鏈接是本書的該可視化部分的詳細(xì)講解 非常不錯(cuò) from matplotlib.font_manager import FontProperties zhfont = FontProperties(fname="C:WindowsFontsmsyh.ttc", size=12) # 歸一化特征值 def autoNorm(dataset): """ Desc: 歸一化特征值,消除特征之間量級(jí)不同導(dǎo)致的影響 parameter: dataset:數(shù)據(jù)集 return : 歸一化后的數(shù)據(jù)集 normDataSet , ranges 和 minVals 即最小值與范圍,并沒有歸一化公式 歸一化公式: Y=(X-Xmin)/(Xmax - Xmin) 其中的 min 和 max 分別是數(shù)據(jù)集中的最小特征值和最大特征值,該函數(shù)可以自動(dòng)將數(shù)字特征值轉(zhuǎn)化為0到1的區(qū)間 """ # 計(jì)算每種屬性的最大值、最小值、范圍 minVals = dataset.min(0) maxVals = dataset.max(0) ranges = maxVals - minVals # 極差 normDataSet = zeros(shape(dataset)) m = dataset.shape[0] #生成與最小值之差組成的矩陣 # 因?yàn)樘卣髦稻仃囉?000 * 3 個(gè)值,而 minVals 和 range 的值都為1x3, # 為了解決這個(gè)問題,我們使用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: 標(biāo)簽向量 :param k: K-NN中的k """ # shape 是array的屬性 ,描述一個(gè)多維數(shù)組的維度 dataSetSize = dataSet.shape[0] # 距離度量 度量公式為歐式距離 """ tile(inX,(dataSetSize,1)) : 把 inX 二維數(shù)組化,dataSetSize 表示生成數(shù)組后的行數(shù) 1 表示列的倍數(shù),整個(gè)這一行代表表示前一個(gè)二維數(shù)組矩陣的每一個(gè)元素減去后一個(gè)數(shù)組對(duì)應(yīng)的元素值 這樣子就實(shí)現(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)鍵是傳回的是位置索引 而這個(gè)索引就可以得到在標(biāo)簽中所對(duì)應(yīng)位置的標(biāo)簽 sortedDistIndicies = distances.argsort() #選取前k個(gè)最短距離,選取這k個(gè)中最多的分類類別 classCount = {} # print(labels) for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] # 這一行是python語法 看不懂基礎(chǔ)問題 # get()該方法是訪問字典項(xiàng)的方法,即訪問下標(biāo)為 voteIlabel的項(xiàng),如果沒有這一項(xiàng),那么初始值為0 # 然后把這一項(xiàng)的值加1 classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 import operator sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1),reverse = True) return sortedClassCount[0][0] # 測(cè)試分類錯(cuò)誤,錯(cuò)誤分辨?zhèn)€數(shù) def datingClassTest(): hoRatio = 0.08 # 隨機(jī)挖去 10% 的數(shù)據(jù)作為測(cè)試集 datingDataMat,datingLabels = file2matrix("datingTestSet2.txt") # 加載數(shù)據(jù)文件 normMat, ranges, minVals = autoNorm(datingDataMat) m = normMat.shape[0] numTestVecs = int(m*hoRatio) # 隨機(jī)挖去的行數(shù) errorCount = 0.0 for i in range(numTestVecs): # 前numTestVecs條作為測(cè)試集(一個(gè)一個(gè)測(cè)試),后面的數(shù)據(jù)作為訓(xùn)練樣本,訓(xùn)練樣本的標(biāo)簽,3個(gè)近鄰 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))) # 實(shí)踐算法 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) # 為什么傳入的值需要進(jìn)行 如下操作呢 (inArry - minVals)/range # 因?yàn)槲覀冎皞魅氲闹刀际沁M(jìn)行過歸一化的 # 但是如果直接傳入值會(huì)過大 所以我們?cè)谇懊娴臍w一化操作中將兩個(gè)參數(shù)傳過來就是為了這里使用 # 但是這里傳入的測(cè)試參數(shù)也是一個(gè)1x3的舉證 所有 minVals 和 ranges 不需要進(jìn)行 tile化 classifierResult = classify0((inArr - minVals) / ranges, normMat, datingLabels, 3) print("You will probably like this person: ", resultList[classifierResult - 1]) # 主函數(shù) if __name__ == "__main__": # 實(shí)踐算法 validateTest() # 測(cè)試分類錯(cuò)誤:判斷程序的可行性 print("這是輸出判斷算法優(yōu)越性的結(jié)果:") datingClassTest()
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/45220.html
摘要:簡介源于數(shù)據(jù)挖掘的一個(gè)作業(yè),這里用來實(shí)現(xiàn)一下這個(gè)機(jī)器學(xué)習(xí)中最簡單的算法之一算法最近鄰分類法。其實(shí)這些標(biāo)簽就對(duì)應(yīng)于機(jī)器學(xué)習(xí)中的特征這一重要概念,而訓(xùn)練我們識(shí)別的過程就對(duì)應(yīng)于泛化這一概念。 1. 簡介 源于數(shù)據(jù)挖掘的一個(gè)作業(yè), 這里用Node.js來實(shí)現(xiàn)一下這個(gè)機(jī)器學(xué)習(xí)中最簡單的算法之一k-nearest-neighbor算法(k最近鄰分類法)。 k-nearest-neighbor-cl...
摘要:一定義二個(gè)人理解其實(shí)簡單理解就是通過計(jì)算新加入點(diǎn)與附近個(gè)點(diǎn)的距離,然后尋找到距離最近的個(gè)點(diǎn),進(jìn)行占比統(tǒng)計(jì),找到個(gè)點(diǎn)中數(shù)量占比最高的,那么新加入的樣本,它的就是頻數(shù)最高的三實(shí)踐語言歐拉距離樣本繪圖計(jì)算距離歐拉距離求出和相 一、定義 url:https://en.wikipedia.org/wiki... In pattern recognition, the k-nearest neig...
摘要:在本教程中,我們將學(xué)習(xí)如何使用八叉樹在點(diǎn)云數(shù)據(jù)中進(jìn)行空間分區(qū)和鄰居搜索。因此,搜索點(diǎn)和搜索結(jié)果之間的距離取決于八叉樹的分辨率參數(shù)。此外,先進(jìn)的內(nèi)存管理減少了八叉樹構(gòu)建過程中的內(nèi)存分配和釋放操作。總結(jié)八叉樹實(shí)現(xiàn)是空間分區(qū)和搜索操作的強(qiáng)大工具。 本教程代碼開源:GitHub 歡迎st...
k近鄰(k-Nearest Neighbor,kNN)算法是經(jīng)典的帶監(jiān)督的分類算法,核心思想是如果一個(gè)樣本在特征空間中的k個(gè)最相鄰的樣本中的大多數(shù)屬于某一個(gè)類別,則針對(duì)該樣本的劃分結(jié)果也屬于這個(gè)類別。 1. 算法步驟 準(zhǔn)備訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù); 確定參數(shù) k; 計(jì)算測(cè)試數(shù)據(jù)與各個(gè)訓(xùn)練數(shù)據(jù)之間的距離,距離的遞增關(guān)系進(jìn)行排序; 選取距離最小的 k 個(gè)點(diǎn); 確定前 k 個(gè)點(diǎn)所在類別的出現(xiàn)頻率; 返回前 ...
閱讀 2038·2021-11-22 09:34
閱讀 3363·2021-09-28 09:35
閱讀 13910·2021-09-09 11:34
閱讀 3692·2019-08-29 16:25
閱讀 2896·2019-08-29 15:23
閱讀 2102·2019-08-28 17:55
閱讀 2496·2019-08-26 17:04
閱讀 3099·2019-08-26 12:21