k-近鄰算法(kNN)

最近開始學習《機器學習實戰》這本書,以下是在學習過程中學到的一些python基礎知識以及算法思想。
python版本:3.6

1、算法核心思想概述

算法思想:k-近鄰算法采用測量不同特征值之間的距離方法進行分類。
優點:精度高、對異常值不敏感、無數據輸入假定
缺點:計算復雜度高、空間復雜度高
適用數據范圍:數值型、標稱型

一個樣本在特征空間里k個距離最短的樣本中,大多數樣本屬于A類,則這個樣本也屬于A類。

1.1 k-近鄰算法的一般流程

(1)收集數據:可以使用任何方法
(2)準備數據:距離計算所需的數值,最好是結構化的數據格式
(3)分析數據:可以使用任何方法
(4)測試數據:計算錯誤率
(5)使用算法:首先需要輸入樣本數據和結構化的輸出結果,然后運行kNN算法判定輸入數據屬于哪個分類,最后應用對計算出的分類執行后續的處理。

1.2 分類函數

本函數的功能為:使用kNN算法將每組數據劃分到某個類別中。首先計算出特征向量間的距離,然后選取與當前距離最小的k個點,并通過這k個點類別出現的頻率來確定當前點的預測分類。
在最初的學習中遇到以下幾個python相關的基礎知識:
(1)shape函數
a.shape[0]計算行數
a.shape[1]計算列數
(2)title函數

>>>a = array([1,2])
>>>title(a, (3,2))
array([[1, 2, 1, 2],
       [1, 2, 1, 2],
       [1, 2, 1, 2]])

(3)axis=0 矩陣每一列相加, axis=1矩陣每一行相加
(4)argsort函數:返回數組的索引值
(5)dict.get(key, default=None)
key:要查找的鍵;default:指定鍵的值不存在則返回默認值。
以下是算法詳細代碼:

from numpy import *
import operator


def createDataSet():
    group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
    labels = ['A', 'A', 'B', 'B']
    return group, labels


def classify0(inK, dataSet, labels, k):
    # 計算訓練樣本的行數,也就是有幾組訓練樣本
    dataSetSize = dataSet.shape[0]
    # 將新樣本與每一個訓練樣本相減
    diffMat = tile(inK, (dataSetSize, 1)) - dataSet
    sqDiffMat = diffMat ** 2
    # 將結果每一行相加,平方和
    sqDistances = sqDiffMat.sum(axis=1)
    # 求距離
    distances = sqDistances ** 0.5
    # 將距離按照從小到大順序排列
    sortedDistIndicies = distances.argsort()  # argsort返回的是索引值
    classCount = {}
    # 選取與當前點距離最小的K個點,確定前K個點所在類別的出現頻率
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    # 將前K個值按照出現頻率最高的類別進行逆序排序
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

執行代碼如下

import kNN

input = [3, 0]
group, labels = kNN.createDataSet()
output = kNN.classify0(input, group, labels, 3)
print("分類結果為:", output)

源碼下載

2、改進約會網站配對效果

示例內容:產生簡單的命令行程序,用戶可以輸入一些特征數據來判斷對方是否為自己喜歡的類型。

2.1準備數據:從文本文件中解析數據

此時數據已經存放在文本文件中,在將數據輸入到分類器之前,需要將待處理的數據變成分類器可以接受的格式。(數據為看數據所占時間數、每年的飛行里程數、每周消耗的冰淇淋公升數)
創建一個file2matrix的函數,用來解析數據。函數的輸入為文件名稱字符,輸出為訓練樣本矩陣和類標簽向量。
以下是學到的一些小知識:
(1)readlines()函數
使用方法:fileObject.readlines( );
返回值:返回列表,包含所有的行
(2)numpy高維數組操作
本部分主要是想提一下以slice的方式來獲取數據
下圖來自博客園

555058-20160922145821965-2072195840.png

以下是算法詳細代碼:

def file2matrix(filename):
    # 得到文件的行數
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)
    # 創建返回的numpy矩陣,矩陣使用0填充,numberOfLines行,3列
    returnMat = zeros((numberOfLines, 3))
    classLabelVector = []
    index = 0
    # 解析文件數據到列表,循環處理文件中的每行數據
    for line in arrayOLines:
        # 去掉每行回車字符
        line = line.strip()
        # 將上一步得到的整行數據分割成一個元素列表    
        listFromLine = line.split('\t')
        # 選取列表的前3個元素并存儲到特征向量中
        returnMat[index, :] = listFromLine[0:3]
        # 將列表的最后一列存儲到向量中
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat, classLabelVector

在測試結果時,需要重載kNN模塊,需要導入模塊importlib
然后輸入如下命令:

importlib.reload(kNN)
datingDataMat, datingLabels = kNN.file2matrix('datingTestSet2.txt')

2.2分析數據:使用Matplotlib創建散點圖

本部分主要采用直觀的圖表來分析數據結構。
以下是算法詳細代碼:

import kNN
import numpy
import matplotlib
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,0], datingDataMat[:,1], 15.0*numpy.array(datingLabels), 15.0*numpy.array(datingLabels))
plt.show()

2.3準備數據:歸一化數值

由于kNN算法就是在求方差,數值偏大的屬性值的影響遠遠大于數值偏小的屬性值。故需要將數據進行歸一化處理,通常將取值范圍處理為0到1或-1到1之間。
以下是算法詳細代碼

def autoNorm(dataSet):
    # 參數0指取列的最值
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - tile(minVals, (m, 1))
    normDataSet = normDataSet / tile(ranges, (m, 1))
    return normDataSet, ranges, minVals

2.4測試算法:作為完整程序驗證分類器

機器學習一個非常重要的工作就是評估算法的正確率,通常使用已有數據的90%作為訓練樣本來訓練分類器,剩余10%的數據用于測試分類器。可以使用錯誤率來檢測分類器的性能。對于分類器而言,錯誤率就是分類器給出錯誤結果的次數除以測試數據的總數。
算法過程
此算法首先使用file2matrixautoNorm函數從文件讀取數據并將數據歸一化處理。接著確定哪些數據用于測試,哪些數據用做訓練樣本,然后將這兩部分數據輸入到分類器函數classify0,最后輸出錯誤率。
以下是算法詳細代碼

def datingClassTest() -> object:
    # 選取多少數據測試分類器
    hoRatio = 0.10
    # 得到數據矩陣和標簽向量
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    # 歸一化處理矩陣
    normMat, ranges, minVals = autoNorm(datingDataMat)
    # 獲取矩陣的行數
    m = normMat.shape[0]
    # 設置測試個數(10%)
    numTestVecs = int(m * hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        #第一個參數:前10%的數據用于inX;第二個參數:后90%用戶dataSet;第三個參數:后90%的數據的標簽;k=3
        classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3)
        print("分類后的結果為:,", classifierResult, "原結果為:", datingLabels[i])
        if (classifierResult != datingLabels[i]):
            errorCount += 1.0
    print("錯誤率是:", (errorCount / float(numTestVecs)))

2.5使用算法:構建完整可用系統

現在通過輸入看數據所占時間數、每年的飛行里程數、每周消耗的冰淇淋公升數這些數據來給出喜歡對方程度的預測值。
以下是算法詳細代碼

def classifyPerson():
    resultList = ['一點也不喜歡', '有一點喜歡', '非常喜歡']
    percentTats = float(input("看視頻所占的時間比:"))
    miles = float(input("每年的飛行里程數:"))
    iceCream = float(input("每周消耗的冰淇淋公升數:"))
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    normMat, ranges, minVals = autoNorm(datingDataMat)
    inArr = array([miles, percentTats, iceCream])
    classifierResult = classify0((inArr - minVals) / ranges, normMat, datingLabels, 3)
    print("你對這個人的喜歡程度:", resultList[classifierResult - 1])

源碼下載
個人主頁
未完。。。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容