1. 程式人生 > >《機器學習實戰》學習筆記(一):k-近鄰演算法

《機器學習實戰》學習筆記(一):k-近鄰演算法

k-近鄰演算法

原書中程式碼為python2中語法,python3的語法參考連結:https://blog.csdn.net/c406495762/article/details/75172850

給出k-近鄰演算法的完整程式碼(海倫相親程式)

import numpy as np
import operator

"""
函式說明:kNN演算法,分類器

Parameters:
    inX - 用於分類的資料(測試集)
    dataSet - 用於訓練的資料(訓練集)
    labes - 分類標籤
    k - kNN演算法引數,選擇距離最小的k個點
Returns:
    sortedClassCount[0][0] - 分類結果

Modify:
    2017-03-24
"""
def classify0(inX, dataSet, labels, k):
    #numpy函式shape[0]返回dataSet的行數
    dataSetSize = dataSet.shape[0]
    #在列向量方向上重複inX共1次(橫向),行向量方向上重複inX共dataSetSize次(縱向)
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
    #二維特徵相減後平方
    sqDiffMat = diffMat**2
    #sum()所有元素相加,sum(0)列相加,sum(1)行相加
    sqDistances = sqDiffMat.sum(axis=1)
    #開方,計算出距離
    distances = sqDistances**0.5
    #返回distances中元素從小到大排序後的索引值
    sortedDistIndices = distances.argsort()
    #定一個記錄類別次數的字典
    classCount = {}
    for i in range(k):
        #取出前k個元素的類別
        voteIlabel = labels[sortedDistIndices[i]]
        #dict.get(key,default=None),字典的get()方法,返回指定鍵的值,如果值不在字典中返回預設值。
        #計算類別次數
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    #python3中用items()替換python2中的iteritems()
    #key=operator.itemgetter(1)根據字典的值進行排序
    #key=operator.itemgetter(0)根據字典的鍵進行排序
    #reverse降序排序字典
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    #返回次數最多的類別,即所要分類的類別
    return sortedClassCount[0][0]


"""
函式說明:開啟並解析檔案,對資料進行分類:1代表不喜歡,2代表魅力一般,3代表極具魅力

Parameters:
    filename - 檔名
Returns:
    returnMat - 特徵矩陣
    classLabelVector - 分類Label向量

Modify:
    2017-03-24
"""
def file2matrix(filename):
    #開啟檔案
    fr = open(filename)
    #讀取檔案所有內容
    arrayOLines = fr.readlines()
    #得到檔案行數
    numberOfLines = len(arrayOLines)
    #返回的NumPy矩陣,解析完成的資料:numberOfLines行,3列
    returnMat = np.zeros((numberOfLines,3))
    #返回的分類標籤向量
    classLabelVector = []
    #行的索引值
    index = 0
    for line in arrayOLines:
        #s.strip(rm),當rm空時,預設刪除空白符(包括'\n','\r','\t',' ')
        line = line.strip()
        #使用s.split(str="",num=string,cout(str))將字串根據'\t'分隔符進行切片。
        listFromLine = line.split('\t')
        #將資料前三列提取出來,存放到returnMat的NumPy矩陣中,也就是特徵矩陣
        returnMat[index,:] = listFromLine[0:3]
        #根據文字中標記的喜歡的程度進行分類,1代表不喜歡,2代表魅力一般,3代表極具魅力
        if listFromLine[-1] == 'didntLike':
            classLabelVector.append(1)
        elif listFromLine[-1] == 'smallDoses':
            classLabelVector.append(2)
        elif listFromLine[-1] == 'largeDoses':
            classLabelVector.append(3)
        index += 1
    return returnMat, classLabelVector

"""
函式說明:對資料進行歸一化

Parameters:
    dataSet - 特徵矩陣
Returns:
    normDataSet - 歸一化後的特徵矩陣
    ranges - 資料範圍
    minVals - 資料最小值

Modify:
    2017-03-24
"""
def autoNorm(dataSet):
    #獲得資料的最小值
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    #最大值和最小值的範圍
    ranges = maxVals - minVals
    #shape(dataSet)返回dataSet的矩陣行列數
    normDataSet = np.zeros(np.shape(dataSet))
    #返回dataSet的行數
    m = dataSet.shape[0]
    #原始值減去最小值
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    #除以最大和最小值的差,得到歸一化資料
    normDataSet = normDataSet / np.tile(ranges, (m, 1))
    #返回歸一化資料結果,資料範圍,最小值
    return normDataSet, ranges, minVals

"""
函式說明:通過輸入一個人的三維特徵,進行分類輸出

Parameters:
    無
Returns:
    無

Modify:
    2017-03-24
"""
def classifyPerson():
    #輸出結果
    resultList = ['討厭','有些喜歡','非常喜歡']
    #三維特徵使用者輸入
    precentTats = float(input("玩視訊遊戲所耗時間百分比:"))
    ffMiles = float(input("每年獲得的飛行常客里程數:"))
    iceCream = float(input("每週消費的冰激淋公升數:"))
    #開啟的檔名
    filename = "datingTestSet.txt"
    #開啟並處理資料
    datingDataMat, datingLabels = file2matrix(filename)
    #訓練集歸一化
    normMat, ranges, minVals = autoNorm(datingDataMat)
    #生成NumPy陣列,測試集
    inArr = np.array([precentTats, ffMiles, iceCream])
    #測試集歸一化
    norminArr = (inArr - minVals) / ranges
    #返回分類結果
    classifierResult = classify0(norminArr, normMat, datingLabels, 3)
    #列印結果
    print("你可能%s這個人" % (resultList[classifierResult-1]))

"""
函式說明:main函式

Parameters:
    無
Returns:
    無

Modify:
    2017-03-24
"""
if __name__ == '__main__':
    classifyPerson()