k-近邻算法1(kNN)使用kNN算法改进约会网站的配对效果
最近邊看NG老師的機器學習課程和西瓜書,無奈交織著各種數學推導,有些晦澀難懂,看到網上推薦了《machine learning in action》比較適合新手入門,
書中數據和源碼在此?http://pan.baidu.com/s/1miIcMPM
書中也有代碼實現。便開始混著看。順便學一下python。這是廖雪峰老師的課程網站 https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000
?
首先是第二章 k-近鄰算法 (k-Nearest Neighbor 土話就是k個最近的鄰居)
簡單的說,k-近鄰算法采用測量不同特征值之間的距離方法進行分類,注:本文參考了https://www.cnblogs.com/xiaoyesoso/p/5208079.html的內容,侵刪
主要有5個步驟
(1)計算已知類別數據集中的點與當前點之間的距離
(2)按照距離遞增次序排序
(3)選取與當前點距離最小的k個點
(4)確定前k個點所在類別的出現頻率
(5)返回前k個點出現頻率最高的類別作為當前點的預測分類
?
示例代碼
from numpy import * import operatordef createDataSet():group = array([[1.0, 1.1], [1.0, 1.], [0, 0.], [0, 0.1]])labels = ['A', 'A', 'B', 'B']return group, labelsdef classify0(inX, dataSet, labels, k):dataSetSize = dataSet.shape[0]#1距離計算diffMat = tile(inX, (dataSetSize, 1)) - dataSetsqDiffMat = diffMat ** 2sqDistances = sqDiffMat.sum(axis=1)distances = sqDistances ** 0.5sortedDistIndicies = distances.argsort()#2選擇距離最小的k個點classCount = {}for i in range(k):voteIlabel = labels[sortedDistIndicies[i]]classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1#3排序sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)return sortedClassCount[0][0]注意點:
(1)tile函數說明 代碼來源 http://blog.csdn.net/ksearch/article/details/21388985
>>> import numpy >>> numpy.tile([0,0],5)#在列方向上重復[0,0]5次,默認行1次 array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) >>> numpy.tile([0,0],(1,1))#在列方向上重復[0,0]1次,行1次 array([[0, 0]]) >>> numpy.tile([0,0],(2,1))#在列方向上重復[0,0]1次,行2次 array([[0, 0], [0, 0]]) >>> numpy.tile([0,0],(3,1)) array([[0, 0], [0, 0], [0, 0]]) >>> numpy.tile([0,0],(1,3))#在列方向上重復[0,0]3次,行1次 array([[0, 0, 0, 0, 0, 0]]) >>> numpy.tile([0,0],(2,3))<span style="font-family: Arial, Helvetica, sans-serif;">#在列方向上重復[0,0]3次,行2次</span> array([[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]) tileDetails.py簡單說就是tile([a,b],(x,y)) 把矩陣[a,b]在行方向重復x次,在列方向重復y次
?
(2)sum函數說明 代碼來源?http://blog.csdn.net/ikerpeng/article/details/17026011
? 1.python的sum
>>> sum([0,1,2]) 3 >>> sum([0,1,2],3) 6 >>> sum([0,1,2],[3,2,1]) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can only concatenate list (not "int") to list pythonSum2.numpy的sum
>>> import numpy as np >>> a=np.sum([[0,1,2],[2,1,3]]) >>> a 9 >>> a.shape () >>> a=np.sum([[0,1,2],[2,1,3]],axis=0) >>> a array([2, 2, 5]) >>> a.shape (3,) >>> a=np.sum([[0,1,2],[2,1,3]],axis=1) >>> a array([3, 6]) >>> a.shape (2,) numpuSum所以上面的axis=1就是按行相加
?
函數的前五行即算出了輸出點和樣本集的歐氏距離
?
(3)argsort函數說明 好吧,我又要引用了,來源?https://www.zhihu.com/question/24029886/answer/26444149
所以就能選擇到前k個距離最近的點。我比較笨。。想了一會兒才明白
?
(4)sorted函數 繼續引用..
來源?https://www.cnblogs.com/xiaoyesoso/p/5208079.html?
https://www.cnblogs.com/sysu-blackbear/p/3283993.html
這里我第一個參數用的是classCount.items()。而書上用的是classCount.iteritems()。因為前者py3后者py2。所以上面的代碼只要改這個地方就可以在2下運行。
詳情見 http://www.runoob.com/python/att-dictionary-items.html??Python 字典(Dictionary) items() 函數以列表返回可遍歷的(鍵, 值) 元組數組。
?
所以上面最后是將字典分解為元組列表,然后按照第二個元素的次序對元組進行逆序排序,最后返回發生頻率最高的元素標簽。
?測試一下
然而這并沒有什么卵用,下面繼續。
?
?
Demo:使用kNN算法改進約會網站的配對效果
(1)準備數據:從文本文件中解析數據
文本文件下載地址?https://pan.baidu.com/s/1o8BSXWu
?
def file2matrix(filename):fr = open(filename)arrayOLines = fr.readlines()#得到文件行數numberOfLines = len(arrayOLines)#創建以0填充的矩陣returnMat = zeros((numberOfLines, 3))classLabelVector = []index = 0for line in arrayOLines:#截取掉所有回車字符line = line.strip()#將整行數據分割成一個元素列表listFromLine = line.split('\t')returnMat[index, :] = listFromLine[0:3]classLabelVector.append(int(listFromLine[-1]))index += 1return returnMat, classLabelVector?
測試一下
?
?
(2)分析數據:使用Matplotlib創建散點圖(在命令行中或main函數)
?
import matplotlibimport matplotlib.pyplot as pltfig = plt.figure() # figure創建一個繪圖對象ax = fig.add_subplot(111) # 若參數為349,意思是:將畫布分割成3行4列,圖像畫在從左到右從上到下的第9塊,datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2])plt.show()?
散點圖使用datingDataMat矩陣的第二、三列數據,分別表示特征值“玩視頻游戲所耗時間百分比”和“每周所消耗的冰淇淋公升數”。
可以用色彩或者其他的幾號來標記不同樣本分類,以便更好的理解數據信息。
?改進如下
import matplotlibimport matplotlib.pyplot as pltfig = plt.figure() # figure創建一個繪圖對象ax = fig.add_subplot(111) # 若參數為349,意思是:將畫布分割成3行4列,圖像畫在從左到右從上到下的第9塊,datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')'''matplotlib.pyplot.scatter(x, y, s=20, c='b', marker='o', cmap=None,norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, verts=None, hold=None,**kwargs)其中,xy是點的坐標,s是點的大小maker是形狀可以maker=(5,1)5表示形狀是5邊型,1表示是星型(0表示多邊形,2放射型,3圓形)alpha表示透明度;facecolor=‘none’表示不填充。'''# ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2])# 設置字體防止中文亂碼zhfont = matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\STXINGKA.TTF')plt.xlabel('玩視頻游戲所耗時間百分比', fontproperties=zhfont)plt.ylabel('每周消費的冰淇淋公升數', fontproperties=zhfont)ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2],15.0 * array(datingLabels), 15.0 * array(datingLabels))plt.show()其中設置字體的說明可以參照?https://www.cnblogs.com/nolonely/p/6944150.html 和?http://blog.csdn.net/u012705410/article/details/47379957
scatter函數使用說明可以參照?https://www.cnblogs.com/shanlizi/p/6850318.html
效果圖
基本上可以看到數據點所屬三個樣本分類的區域輪廓,但是用矩陣的第一第二列屬性可以得到更好的展示效果。
emmmm。。。這里畫圖例又參照了
https://www.zhihu.com/question/37146648
https://www.zhihu.com/question/37146648/answer/80425957?
?
def draw():fig = plt.figure() # figure創建一個繪圖對象ax = fig.add_subplot(111) # 若參數為349,意思是:將畫布分割成3行4列,圖像畫在從左到右從上到下的第9塊,datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')type1_x = []type1_y = []type2_x = []type2_y = []type3_x = []type3_y = []for i in range(len(datingLabels)):if datingLabels[i] == 1: # 不喜歡 type1_x.append(datingDataMat[i][0])type1_y.append(datingDataMat[i][1])if datingLabels[i] == 2: # 魅力一般 type2_x.append(datingDataMat[i][0])type2_y.append(datingDataMat[i][1])if datingLabels[i] == 3: # 極具魅力 type3_x.append(datingDataMat[i][0])type3_y.append(datingDataMat[i][1])type1 = ax.scatter(type1_x, type1_y, s=20, c='red')type2 = ax.scatter(type2_x, type2_y, s=30, c='green')type3 = ax.scatter(type3_x, type3_y, s=40, c='blue')# 設置字體防止中文亂碼zhfont = matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\STXINGKA.TTF')plt.xlabel('每年獲取的飛行常客里程數', fontproperties=zhfont)plt.ylabel('玩視頻游戲所耗時間百分比', fontproperties=zhfont)ax.legend((type1, type2, type3), (u'不喜歡', u'魅力一般', u'極具魅力'), loc=2, prop=zhfont)plt.show()?
?
?
?
?(3)準備數據:歸一化數值
寫了這么長,然而我們的重點剛要開始...真是一篇又臭又長各種引用的博客
我們發現,歐式距離方程中,數字差值最大的屬性對計算結果的影響最大,即每年獲取的飛行常客里程數對于計算結果的影響將遠遠大于其他兩個特征。
然而這僅僅是因為此特征值遠大于其他特征值,不應該如此嚴重的影響到計算結果。(這里假設三個特征同等重要)
在處理不同取值范圍的特征值時,采用數值歸一化,如將取值范圍處理為0-到1或-1到1。
下面的公式可以將任意取值范圍的特征值轉化為0到1區間內的值:
newValue=(oldValue-min)/(max-min)
實現函數如下
# newValue=(oldValue-min)/(max-min) def autoNorm(dataSet):# 參數0使得函數可以從列中選取最小值minVals = dataSet.min(0)maxVals = dataSet.max(0)ranges = maxVals - minValsnormDataSet = zeros(shape(dataSet))m = dataSet.shape[0]normDataSet = dataSet - tile(minVals, (m, 1))normDataSet = normDataSet / tile(ranges, (m, 1))return normDataSet, ranges, minVals?
?(4)測試算法:作為完整程序驗證分類器
def datingClassTest():#測試數據所占的比例hoRatio = 0.1datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')normMat, ranges, minVals = autoNorm(datingDataMat)# 矩陣第一維大小m = normMat.shape[0]# 測試向量的數量numTestVecs = int(m * hoRatio)errorCount = 0.0for 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.0print("the total error rate is: %f" % (errorCount / float(numTestVecs)))測試結果
?
?(5)使用算法:構建完整可用系統
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 = array([ffMiles, percentTats, iceCream])classifierResult = classify0(inArr, datingDataMat, datingLabels, 3)print("You will probably like this person: ", resultList[classifierResult - 1])注:python3中?raw_input() 變成了?input()
?emmmmmm....運行結果如下
完整代碼如下
#!usr/bin/env python3 # -*-coding:utf-8 -*-from numpy import * import operator import matplotlib import matplotlib.pyplot as pltdef createDataSet():group = array([[1.0, 1.1], [1.0, 1.], [0, 0.], [0, 0.1]])labels = ['A', 'A', 'B', 'B']return group, labelsdef classify0(inX, dataSet, labels, k):dataSetSize = dataSet.shape[0]# 1距離計算diffMat = tile(inX, (dataSetSize, 1)) - dataSetsqDiffMat = diffMat ** 2sqDistances = sqDiffMat.sum(axis=1)distances = sqDistances ** 0.5sortedDistIndicies = distances.argsort()# 2選擇距離最小的k個點classCount = {}for i in range(k):voteIlabel = labels[sortedDistIndicies[i]]classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1# 3排序sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)return sortedClassCount[0][0]def file2matrix(filename):fr = open(filename)arrayOLines = fr.readlines()# 得到文件行數numberOfLines = len(arrayOLines)# 創建以0填充的矩陣returnMat = zeros((numberOfLines, 3))classLabelVector = []index = 0for line in arrayOLines:# 截取掉所有回車字符line = line.strip()# 將整行數據分割成一個元素列表listFromLine = line.split('\t')returnMat[index, :] = listFromLine[0:3]classLabelVector.append(int(listFromLine[-1]))index += 1return returnMat, classLabelVector# newValue=(oldValue-min)/(max-min) def autoNorm(dataSet):# 參數0使得函數可以從列中選取最小值minVals = dataSet.min(0)maxVals = dataSet.max(0)ranges = maxVals - minValsnormDataSet = zeros(shape(dataSet))m = dataSet.shape[0]normDataSet = dataSet - tile(minVals, (m, 1))normDataSet = normDataSet / tile(ranges, (m, 1))return normDataSet, ranges, minValsdef datingClassTest():# 測試數據所占的比例hoRatio = 0.1datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')normMat, ranges, minVals = autoNorm(datingDataMat)# 矩陣第一維大小m = normMat.shape[0]# 測試向量的數量numTestVecs = int(m * hoRatio)errorCount = 0.0for 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.0print("the total error rate is: %f" % (errorCount / float(numTestVecs)))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 = array([ffMiles, percentTats, iceCream])classifierResult = classify0(inArr, datingDataMat, datingLabels, 3)print("You will probably like this person: ", resultList[classifierResult - 1])def draw():fig = plt.figure() # figure創建一個繪圖對象ax = fig.add_subplot(111) # 若參數為349,意思是:將畫布分割成3行4列,圖像畫在從左到右從上到下的第9塊,datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')'''matplotlib.pyplot.scatter(x, y, s=20, c='b', marker='o', cmap=None,norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, verts=None, hold=None,**kwargs)其中,xy是點的坐標,s是點的大小maker是形狀可以maker=(5,1)5表示形狀是5邊型,1表示是星型(0表示多邊形,2放射型,3圓形)alpha表示透明度;facecolor=‘none’表示不填充。'''type1_x = []type1_y = []type2_x = []type2_y = []type3_x = []type3_y = []for i in range(len(datingLabels)):if datingLabels[i] == 1: # 不喜歡 type1_x.append(datingDataMat[i][0])type1_y.append(datingDataMat[i][1])if datingLabels[i] == 2: # 魅力一般 type2_x.append(datingDataMat[i][0])type2_y.append(datingDataMat[i][1])if datingLabels[i] == 3: # 極具魅力 type3_x.append(datingDataMat[i][0])type3_y.append(datingDataMat[i][1])type1 = ax.scatter(type1_x, type1_y, s=20, c='red')type2 = ax.scatter(type2_x, type2_y, s=30, c='green')type3 = ax.scatter(type3_x, type3_y, s=40, c='blue')# ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2])# 設置字體防止中文亂碼zhfont = matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\STXINGKA.TTF')plt.xlabel('每年獲取的飛行常客里程數', fontproperties=zhfont)plt.ylabel('玩視頻游戲所耗時間百分比', fontproperties=zhfont)# ax.scatter(datingDataMat[:, 0], datingDataMat[:, 1],# 15.0 * array(datingLabels), 15.0 * array(datingLabels))ax.legend((type1, type2, type3), (u'不喜歡', u'魅力一般', u'極具魅力'), loc=2, prop=zhfont)plt.show()if __name__ == "__main__":classifyPerson()轉載于:https://www.cnblogs.com/wangkaipeng/p/7872516.html
總結
以上是生活随笔為你收集整理的k-近邻算法1(kNN)使用kNN算法改进约会网站的配对效果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java实现 LeetCode 623
- 下一篇: 项目实战-图像识别项目-通过QT制作图形