Python3代碼實現《機器學習實戰》k近鄰算法改進約會網站配對效果中出現的問題

報錯1:No module named ‘kNN’

解決:

轉而在Spyder中,先保存在自己的學習目錄中,然後在命令提示符完成操作,保證目錄要一致,也就是下面圖中打馬賽克的4個。

 

報錯: name ‘reload’ is not defined

解決:

先調用imp標準庫模塊中可用的reload函數, 再模塊重載

報錯:ValueError: invalid literal for int() with base 10: 'largeDoses'

解決:

將datingClassTest()函數中第二行代碼,打開的文件名改爲datingTestSet2.txt即可。

原因:

比較datingTestSet.txt和datingTestSet2.txt,主要的區別是最後的標籤,datingTestSet.txt中使用字符串‘veryLike’作爲標籤,但是Python轉換會出現ValueError: invalid literal for int() with base 10: 'largeDoses'的錯誤。後面datingTestSet2.txt中直接用1 2 3 代表not like, general like, very like,所以可以正常解析。

最終成功執行結果:

附完整代碼:

# -*- coding: utf-8 -*-
"""
Created on Mon Feb 25 11:32:55 2019

@author: Administrator
"""

# 導入科學計算包Numpy
import numpy as np
# 導入運算符模塊,k-近鄰算法執行排序操作時將使用這個模塊提供的函數
import operator 
 
'''
爲了確保輸入相同的數據集,kNN模塊中定義了函數createDataSet
'''
def createDataSet():
    group = np.array([[1.0 , 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
    labels = ['A', 'A', 'B', 'B']  # 包含了每個數據點的標籤信息
    return group, labels

'''
classify0有四個輸入變量,用於分類的輸入向量是inX,輸入的樣本集是dataSet,
標籤向量爲labels,k是用於選擇最近的鄰居數目,其中標籤向量的元素數目和矩陣
dataSet的行數相同。
'''
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]  #返回矩陣的行數,即有多少組數據
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet  #tile函數的作用是讓某個數組以某種方式重複,構造出新的數組
    sqDiffMat = diffMat ** 2
    sqDistances = sqDiffMat.sum(axis = 1)  #將矩陣的每一行向量相加
    distances = sqDistances ** 0.5
    sortedDistIndicies = distances.argsort()  #對距離進行遞增排序,返回值是數值對應的索引值
    classCount = {}  #創建字典
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]  
        #get(voteIlabel, 0):返回指定鍵的值,若不在字典中就返回0
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1  
    #按照第二個元素的次序對元組進行從大到小的排序
    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)  #得到文件的行數
    returnMat = np.zeros((numberOfLines, 3))  #創建返回的Numpy矩陣
    classLabelVector = []  
    index = 0
    for line in arrayOLines:
        line = line.strip()   #截取掉所有的回車符
        listFromLine = line.split('\t')  #將整行數據分割成一個元素列表
        returnMat[index, :] = listFromLine[0: 3]  #選取前三個元素,將它們存儲到特徵矩陣中t
        classLabelVector.append(int(listFromLine[-1]))  #將列表中的最後一列存儲到向量中
        index += 1
    return returnMat, classLabelVector  #輸出爲訓練樣本矩陣和類標籤向量

'''
歸一化特徵值,將數字特徵值轉化爲0~1的區間
'''
def autoNorm(dataSet):
    minVals = dataSet.min(0)  #參數0使得函數可以從列中選取最小值,而不是選取當前行的最小值
    maxVals = dataSet.max(0)  #選取列的最大值
    ranges = maxVals - minVals  #返回矩陣的規模
    normDataSet = np.zeros(np.shape(dataSet))
    m = dataSet.shape[0]  #返回數據集中矩陣的行數
    # minVals與ranges都是1*3的矩陣,通過tile函數被擴展爲m*3的矩陣,這就是tile函數的作用
    normDataSet = dataSet - np.tile(minVals, (m,1))
    normDataSet = normDataSet / np.tile(ranges, (m,1))  #特徵值相除
    return normDataSet, ranges, minVals
        
'''
分類器針對約會網站的測試代碼
'''
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):
        #normMat[i,:]是指用於分類的測試數據;normMat[numTestVecs:m,:]是指其他90%的訓練數據;datingLabels[numTestVecs:m]是指訓練數據對應的標籤;k=3
        classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,:], datingLabels[numTestVecs:m], 3)       
        #datingLabels[i]是指測試數據在原數據集中的真實標籤
        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)))

'''
約會網站預測函數
'''           
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])  
    #classify0的三個輸入數據分別是:用於分類的輸入向量,輸入的數據集,標籤向量,最近的鄰居數目
    classifierResult = classify0((inArr-minVals) / ranges, normMat, datingLabels, 3) 
    print("You will probably like this person: ", resultList[classifierResult - 1])

'''
數據可視化  
'''
import matplotlib.pyplot as plt
datingDataMat,datingLabels = file2matrix("datingTestSet2.txt") 
#獲取figure對象
fig = plt.figure() 
#指定圖像所在的子視圖位置,add_subplot(nmi),意思爲在fig視圖被劃分爲n*m個子視圖,i指定接下來的圖像放在哪一個位置
ax = fig.add_subplot(111) 
#畫出散點圖,座標分別爲datingDataMat的第一列數據與第二列數據,利用15*datingLabels的1、2、3作爲不同點的顏色和尺寸
ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*np.array(datingLabels), 15.0*np.array(datingLabels))
plt.show()

'''
測試
'''
classifyPerson()
    
    

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章