目的:改進約會網站配對效果
數據樣本 下載地址 (百度網盤)
讀取txt數據的代碼
1 def file2matrix(filename): 2 fr = open(filename) 3 arrayOfLines = fr.readlines() 4 numberOfLines = len(arrayOfLines) 5 retMat = zeros((numberOfLines,3)) 6 classLabelVector = [] 7 index = 0 8 for line in arrayOfLines: 9 line = line.strip() 10 listFromLine = line.split('\t') 11 retMat[index,:] = listFromLine[0:3]#attention 12 classLabelVector.append(int(listFromLine[-1]))#why int 13 index += 1 14 return retMat,classLabelVector
這段代碼沒有什么好解釋的,注意一點 listFromLine[0:3] 表示的是0,1,2下標的值(不包含3)
matplotlib
matplotlib可以認為是python下的MATLAB,集成了各種畫圖api。給個比較好的教程 點擊鏈接
作圖代碼
1 import kNN 2 from numpy import * 3 import matplotlib 4 import matplotlib.pyplot as plt 5 6 group,labels = kNN.createDataSet() 7 kNN.classify0([0,0],group,labels,3) 8 datingDataMat,datingLabels = kNN.file2matrix('F:\Documents\Python Code\machinelearninginaction\Ch02\datingTestSet2.txt') 9 fig = plt.figure() 10 ax = fig.add_subplot(1,1,1) 11 ax.scatter(datingDataMat[:,1],datingDataMat[:,2], 12 15.0*array(datingLabels),15.0*array(datingLabels)) 13 plt.show()
這段代碼中需要注意的可能就只有幾點:
1. fig.add_subplot(1,1,1)表示作一個1*1的圖,其中激活第一個圖。
2. scatter() 函數,確定橫縱坐標,以及圖中點的大小以及顏色。
結果如圖:
圖中的橫縱坐標分別表示 玩游戲所耗時間的百分比 以及 每周消費冰激凌公升數,但是我們從圖中很難獲取到有用的信息。下面我們再來用另外一維數據試試,也就是每年飛行里數這個特征,作圖如下(程序與上面那段代碼幾乎相同):
怎么樣,效果立馬不一樣了吧。
到此為止,可能認為這個問題已經搞定了,給定一個人,只需要看看離他最近的人的分類就可以啦。可是問題在於這個“近”是怎么判定的呢?上面我們用的是歐氏距離,這有木有問題呢?很不幸,有問題,其中一個最明顯的問題就是,算了,先看計算距離的公式吧。
((0-67)^2+(20000-32000)^2+(1.1-0.1)^2 )^0.5
發現了沒有啊,相對於第二項,第一項和第三項幾乎不起任何作用啊!
於是乎,怎么辦呢,歸一化!下面是歸一化的函數:
1 def autoNorm(dataSet): 2 minVals = dataSet.min(0) 3 maxVals = dataSet.max(0) 4 ranges = maxVals - minVals 5 normDataSet = zeors(shape(dataSet)) 6 m = dataSet.shape[0] 7 normDataSet = dataSet - tile(minVals,(m,1)) 8 normDataSet = normDataSet/tile(ranges,(m,1)) 9 return normDataSet,ranges,minVals
歸一化是如何實現的呢?首先找到每一列的最小值和最大值,然后求出范圍。注意以上的操作都是基於array的,雖然表面看起來是一個數字,但實際上是數組。
這段程序實現的功能就是 (數組 - 數組中的最小值)/(最大值-最小值),於是乎,歸一化完成了。
然后測試該算法的准確性。使用隨機選取的90%的樣本訓練,10%的樣本檢測。代碼如下:
1 def datingClassTest(): 2 hoRatio = 0.10 3 datingDataMat,datingLabels = file2matrix('datingTestSet.txt') 4 normMat,ranges,minVals = autoNorm(datingDataMat) 5 m = normMat.shape[0] 6 numTestVecs = int(m*hoRatio) 7 errorCount = 0.0 8 for i in range(numTestVecs): 9 classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],\ 10 datingLabels[numTestVecs:m],3) 11 print "the classifier came back with: %d, the real answer is: %d"\ 12 % (classsifierresult, datingLabels[i]) 13 if (classifierResult != datingLabels[i]):errorCount += 1.0 14 print "the total error rate is: %f" % (errorCount/float(numTestVecs))
這段代碼的作用就是檢測分類器效果的。
程序首先讀取數據,並進行歸一化的處理,接着調用了我們之前寫的 calssify0 這段分類程序,對normMat中的數據進行分類。
下面給出一段程序,這段程序用於輸入用戶的信息來預測海倫對他的喜歡程度
def classifyPerson(): #定義喜歡程度 resultList = ['not at all','in small doses','in large doses'] #輸入玩游戲時間,飛行公里,和冰激凌消耗量 percentTats = float(raw_input("percentage of time spent playing video games?")) ffMiles = float(raw_input("frequent flier miles earned per year")) iceCream = float(raw_input("liters of ice cream consumed per year")) #建立knn原始數據 datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #特征歸一化 normMat,ranges,minVals = autoNorm(datingDataMat) #將輸入量建成三個特征 inArr = array([ffMiles,percentTats,iceCream]) #最近鄰 classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3) #輸出結果 print "You will probably like this person: ", resultList[classifierResult - 1]
怎么樣不難吧?