一步步教你輕鬆學KNN模型算法

一步步教你輕鬆學KNN模型算法( 白寧超 2018年7月24日08:52:16 )

導讀:機器學習算法中KNN屬於比較簡單的典型算法,既能夠作聚類又能夠作分類使用。本文經過一個模擬的實際案例進行講解。整個流程包括:採集數據、數據格式化處理、數據分析、數據歸一化處理、構造算法模型、評估算法模型和算法模型的應用。(本文原創,轉載必須註明出處: 一步步教你輕鬆學KNN模型算法javascript

目錄

機器學習:一步步教你輕鬆學KNN模型算法

機器學習:一步步教你輕鬆學決策樹算法

機器學習:一步步教你輕鬆學樸素貝葉斯模型算法理論篇1 

機器學習:一步步教你輕鬆學樸素貝葉斯模型實現篇2 

機器學習:一步步教你輕鬆學樸素貝葉斯模型算法Sklearn深度篇3

機器學習:一步步教你輕鬆學邏輯迴歸模型算法

機器學習:一步步教你輕鬆學K-means聚類算法

機器學習:一步步教你輕鬆學關聯規則Apriori算法

機器學習: 一步步教你輕鬆學支持向量機SVM算法之理論篇1

10 機器學習: 一步步教你輕鬆學支持向量機SVM算法之案例篇2

11 機器學習: 一步步教你輕鬆學主成分分析PCA降維算法

12 機器學習: 一步步教你輕鬆學支持向量機SVM降維算法

更多文章請點擊這裏>>

1 理論介紹

什麼是KNN?css

       k-近鄰(kNN,k-NearestNeighbor)算法是一種基本分類與迴歸方法,咱們這裏只討論分類問題中的 k-近鄰算法。k-近鄰算法的輸入爲實例的特徵向量,對應於特徵空間的點;輸出爲實例的類別,能夠取多類。k-鄰算法假設給定一個訓練數據集,其中的實例類別已定。分類時,對新的實例,根據其 k 個最近鄰的訓練實例的類別,經過多數表決等方式進行預測。所以,k近鄰算法不具備顯式的學習過程即屬於有監督學習範疇。k近鄰算法實際上利用訓練數據集對特徵向量空間進行劃分,並做爲其分類的「模型」。k值的選擇、距離度量以及分類決策規則是k近鄰算法的三個基本要素。html

KNN算法思想java

1 計算已知類別中數據集的點與當前點的距離。[即計算全部樣本點跟待分類樣本之間的距離]
2 按照距離遞增次序排序。[計算完樣本距離進行排序]
3 選取與當前點距離最小的k個點。[選取距離樣本最近的k個點]
4 肯定前k個點所在類別的出現頻率。[針對這k個點,統計下各個類別分別有多少個]
5 返回前k個點出現頻率最高的類別做爲當前點的預測分類。[k個點中某個類別最多,就將樣本劃歸改點]

KNN工做原理python

1 假設有一個帶有標籤的樣本數據集(訓練樣本集),其中包含每條數據與所屬分類的對應關係。
2 輸入沒有標籤的新數據後,將新數據的每一個特徵與樣本集中數據對應的特徵進行比較。
3 計算新數據與樣本數據集中每條數據的距離。
4 對求得的全部距離進行排序(從小到大,越小表示越類似)。
5 取前 k (k 通常小於等於 20 )個樣本數據對應的分類標籤。
6 求 k 個數據中出現次數最多的分類標籤做爲新數據的分類。

KNN算法流程jquery

1 蒐集數據:數據採集過程,其分爲非結構化數據,半結構化數據和數據化數據。諸如:網絡爬取,數據庫,文件等。
2 準備數據:格式化處理,對不一樣類別的數據進行統一的格式化處理。諸如:將pdf,word,excel,sql等等統一轉化爲txt文本。
3 分析數據:主要看看數據特色,有沒有缺失值,數據連續性仍是離散型,進而選擇不一樣模型。諸如:可視化數據分析
4 訓練數據:不適用於KNN,可是在其餘一些監督學習中會常常遇到,諸如:樸素貝葉斯分類等。
5 測試算法:評價指標,如計算錯誤率,準確率,召回率,F度量值等。
6 應用算法:針對完善的模型進行封裝重構,而後進行實際應用。

KNN優缺點git

優勢:精度高、對異常值不敏感、無數據輸入假定
缺點:計算複雜度高、空間複雜度好
適用數據範圍:數值型和標稱型

2 KNN算法實現與分析

2.1 數據準備

建立模擬數據集github

描述:如今你來了一個新的任務,任務其實很是簡單,就是根據吃冰淇淋和喝水的數量判斷成都天氣冷熱程度。你如今要作的就是去成都春熙路街頭採訪記錄一些遊客吃了多少冰淇淋,又喝了幾瓶水,他以爲成都天氣怎麼樣(這裏只考慮二分類問題,假設只有‘很是熱’和‘通常熱’)。其中特徵向量包括兩個分別是冰激凌數t1和喝水數t2,標籤類別分別是很是熱A和通常熱B。web

如今咱們開始行動,隨機採訪4個遊客(暫時不考慮樣本數量問題),詢問每一個遊客吃多少冰淇淋和喝多少水(兩個整型的特徵向量,不考慮特徵重要程度),並記錄下他們口中的成都天氣感覺(很是熱A與通常熱B)。而後經過採訪數據訓練一個KNN分類器,新的遊客只須要說出特徵向量自動判別成都天氣冷熱程度。建立模擬數據集代碼以下:算法

'''KNN建立數據源,返回數據集和標籤'''
def create_dataset():
    group = array(random.randint(0,10,size=(4,2))) # 數據集
    labels = ['A','A','B','B'] # 標籤
    return group,labels

運行查看數據集的特徵向量和分類標籤:

'''1 KNN模擬數據分類算法'''
dataset,labels = create_dataset()
print('特徵集:\n'+str(dataset))
print('標籤集:\n'+str(labels))

運行結果:

特徵集:
[[8 4]
 [7 1]
 [1 4]
 [3 0]]
標籤集:
['A', 'A', 'B', 'B']

分析解讀:

本段代碼沒有實際意義,只是幫助讀者理解特徵向量和分類標籤。能夠這麼理解,A表明很是熱,B表明通常熱,屬性1表明吃冰淇淋數量,屬性2表明喝水的數量。那麼樣本數據能夠解讀爲:

遊客     冰淇淋    喝水    冷熱程度        判斷描述

小王      8       4       A           小王吃了8個冰淇淋喝了4瓶水,成都天氣很是熱

小張      7       1       A           小張吃了7個冰淇淋喝了1瓶水,成都天氣很是熱

小李      1       4       B           小王吃了1個冰淇淋喝了4瓶水,成都天氣通常熱

小趙      3       0       B           小王吃了3個冰淇淋喝了0瓶水,成都天氣通常熱

思考:

計算機是不能直接處理天然語言,每每須要將天然語言轉化成特徵向量,再經過計算機處理。好比這裏不是吃喝看天氣狀況了,而是垃圾郵件自動識別,咱們就須要對郵件轉化成數值型特徵向量再輸入計算機進行處理。

規範文件數據集處理

以下是一個規範文件的數據集(已經通過數採集、數據格式化、數據預處理等),特徵向量包括3個,樣本屬於一個多分類的狀況。即咱們經過周飛行里程數、玩遊戲佔比、吃冰激凌數量判斷一我的的優秀程度。假設1表明普通,2表明比較優秀,3表明很是優秀。(ps:一我的一週都在飛機上度過忙碌的工做,又不太玩遊戲,關鍵還注意飲食,說明優秀是有道理的。)

周飛行里程數(km)   周玩遊戲佔比(%)    周消耗冰激凌(公升)        樣本分類
40920                8.326976            0.953952                3
14488                7.153469            1.673904                2
26052                1.441871            0.805124                1
...                  ...                 ...                    ...
75136                13.147394           0.428964                1
38344                1.669788            0.134296                1
72993                10.141740           1.032955                1

上面是處理好保存在txt文本的數據,計算機如何去識別並處理這些數據呢?這裏咱們分別提取特徵向量和標籤向量。數據集處理代碼以下:

'''對文件進行格式處理,便於分類器能夠理解'''
def file_matrix(filename):
    f = open(filename)
    arrayLines = f.readlines()
    returnMat = zeros((len(arrayLines),3))    # 數據集
    classLabelVactor = []                     # 標籤集
    index = 0
    for line in arrayLines:
        listFromLine = line.strip().split('    ')    # 分析數據,空格處理
        returnMat[index,:] = listFromLine[0:3]
        classLabelVactor.append(int(listFromLine[-1]))
        index +=1
    return returnMat,classLabelVactor

代碼說明:

1 zeros(Y,X):填充矩陣,須要導入NumPy包。Y向量表明樣本行數,X向量表明樣本特徵數即列數。
2 returnMat[index,:]:遍歷樣本特徵向量

運行查看數據集的特徵向量和分類標籤:

''' KNN針對文件的分類算法'''
filename = os.path.abspath(r'./datasource/datingTestSet2.txt')
dataset,labels = file_matrix(filename)
print('特徵集:\n'+str(dataset))
print('標籤集:\n'+str(labels))

運行結果:

特徵集:
[[4.0920000e+04 8.3269760e+00 9.5395200e-01]
 [1.4488000e+04 7.1534690e+00 1.6739040e+00]
 [2.6052000e+04 1.4418710e+00 8.0512400e-01]
 ...
 [2.6575000e+04 1.0650102e+01 8.6662700e-01]
 [4.8111000e+04 9.1345280e+00 7.2804500e-01]
 [4.3757000e+04 7.8826010e+00 1.3324460e+00]]
標籤集:
[3, 2, 1, 1, 1, 1, 3, 3, 1, 3, 1, 1, 2, 1, 1, 
 1, 1, 1, 2, 3, 2, 1, 2, 3, 2, 3, 2, 3, 2, 1, 
 3, 1, 3, 1, 2, 1, 1, 2, 3, 3, 1, 2, 3, 3, 3, 
 ...    
 3, 3, 1, 2, 3, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1]

不規範數據集處理

這裏咱們只是提供一個思路。好比作文本分類算法,如何將一篇篇新聞轉化爲規範的數值型數據集呢。假設Z政治新聞100篇,T體育新聞100篇,Y娛樂新聞100篇,K科技新聞100篇。咱們進行分類:

1 遍歷全部文本轉化統一的txt格式文件(2.2節會講到)
2 對所有ZTYK文本進行分詞和停用詞處理。
3 統計所有樣本詞頻尺寸(能夠採用TF-IDF或者深度學習方法處理)。
4 每一個樣本進行詞頻統計

最終模擬效果以下:

樣本      詞1      詞2      詞3      詞4      ...     詞n      標籤
p1       200       0       100      50       ...    20         Z
p2       100       0       80       40       ...    10         Z
p3       0         100     5        5        ...    200        T
p4       6         230     40       12       ...    670        T
p5       0         2       110      57       ...    234        Y
...      ...       ...     ...      ...      ...    ...        ...
pn       123       45      0        580      ...    24         K

2.2 數據格式化

數據文件轉化

天然語言處理、數據挖掘、機器學習技術應用越發普遍。針對大數據的預處理工做是一項龐雜、棘手的工做。首先數據採集和存儲,尤爲高質量數據採集每每不是那麼簡單。採集後的信息文件格式不一,諸如pdf,doc,docx,Excel,ppt等多種形式。然而最多見即是txt、pdf和word類型的文檔。這裏所謂格式轉化主要對pdf和word文檔進行文本格式轉換成txt。格式一致化之後再進行後續預處理工做。具體詳情請參照以前寫的數據分析:基於Python的自定義文件格式轉換系統一文。

文件格式化處理

這裏能夠採用多種方式,諸如上文提到的矩陣填充法,固然也能夠採用現成的工具。好比百度的Echarts中表格數據轉換工具。其支持純數組的轉換,數組+對象,地理座標等方式,還支持json數據的轉化,這對使用百度EChart可視化是很是友好的,也有助於可視化數據分析。文本數據格式效果以下圖:

圖2-1 文本數據表格轉化

[
    ['40920    8.326976    0.953952    3'],
    ['14488    7.153469    1.673904    2'],
    ['26052    1.441871    0.805124    1'],
    ['75136    13.147394    0.428964    1'],
    ['38344    1.669788    0.134296    1'],
    ['72993    10.141740    1.032955    1'],
    ...
    ['35948    6.830792    1.213192    3'],
    ['42666    13.276369    0.543880    3'],
    ['67497    8.631577    0.749278    1'],
    ['35483    12.273169    1.508053    3'],
    ['50242    3.723498    0.831917    1'],
    ['63275    8.385879    1.669485    1'],
    ['5569    4.875435    0.728658    2'],
    ['15669    0.000000    1.250185    2'],
    ['28488    10.528555    1.304844    3'],
    ['6487    3.540265    0.822483    2'],
    ['37708    2.991551    0.833920    1']
]

2.3 數據歸一化

數據歸一化

機器學習、數據挖掘、天然語言處理等數據科學工做中,數據前期準備、數據預處理過程、特徵提取等幾個步驟比較花費時間。同時,數據預處理的效果也直接影響了後續模型可否有效的工做。然而,目前的不少研究主要集中在模型的構建、優化等方面,對數據預處理的理論研究甚少,不少數據預處理工做仍然是靠工程師的經驗進行的。也不是全部數據都須要歸一化,諸如

1.  數據類型一致且分佈均勻。
2.  機率模型能夠不作歸一化,如決策樹。

數據歸一化優勢

1. 歸一化後加快了梯度降低求最優解的速度;
2. 歸一化有可能提升精度;

歸一化方法

1 sklearn線性歸一化

# 線性函數將原始數據線性化的方法轉換到[0, 1]的範圍   
min_max_scaler = preprocessing.MinMaxScaler()
X_train_minmax = min_max_scaler.fit_transform(X_train)
X_test_minmax = min_max_scaler.transform(X_test)

2 標準差標準化

# 通過處理的數據符合標準正態分佈,即均值爲0,標準差爲1,其轉化函數爲:
scaler = preprocessing.StandardScaler().fit(X_train)
scaler.transform(X_test)

3 非線性歸一化

常常用在數據分化比較大的場景,有些數值很大,有些很小。經過一些數學函數,將原始值進行映射。該方法包括 log、指數,正切等。須要根據數據分佈的狀況,決定非線性函數的曲線,好比log(V, 2)仍是log(V, 10)等。

線性歸一化方法代碼實現

'''數值歸一化:特徵值轉化爲0-1之間:newValue = (oldValue-min)/(max-min)'''
def norm_dataset(dataset):
    minVals = dataset.min(0)  # 參數0是取得列表中的最小值,而不是行中最小值
    maxVals = dataset.max(0)
    ranges = maxVals - minVals
    normdataset = zeros(shape(dataset)) # 生成原矩陣同樣大小的0矩陣

    m = dataset.shape[0]
    # tile:複製一樣大小的矩陣
    molecular = dataset - tile(minVals,(m,1))  # 分子: (oldValue-min)
    Denominator = tile(ranges,(m,1))           # 分母:(max-min)
    normdataset = molecular/Denominator     # 歸一化結果。

    return normdataset,ranges,minVals

數據歸一化前:

歸一化的數據結果:
[[4.0920000e+04 8.3269760e+00 9.5395200e-01]
 [1.4488000e+04 7.1534690e+00 1.6739040e+00]
 [2.6052000e+04 1.4418710e+00 8.0512400e-01]
 ...
 [2.6575000e+04 1.0650102e+01 8.6662700e-01]
 [4.8111000e+04 9.1345280e+00 7.2804500e-01]
 [4.3757000e+04 7.8826010e+00 1.3324460e+00]]

展開第一條信息「40920 8.326976 0.953952 3」,其中里程40000多,而公升數才0.9.二者根本不在同一個數量級上面,也就是說,若是特徵屬性相同的狀況下,公升數即便變更100倍對里程數的影響也微乎其微。而里程數輕微變化就直接影響公升數的結果。因此咱們將其放在同一尺度下進行處理,也就是本文采用的線性縮放方,數據歸一化後結果以下:

歸一化的數據結果:
[[0.44832535 0.39805139 0.56233353]
 [0.15873259 0.34195467 0.98724416]
 [0.28542943 0.06892523 0.47449629]
 ...
 [0.29115949 0.50910294 0.51079493]
 [0.52711097 0.43665451 0.4290048 ]
 [0.47940793 0.3768091  0.78571804]]

分析:

通過上述歸一化處理後,各個特徵指標都是0-1這樣一個範疇中進行比較。固然實際工做中不一樣特徵的權重不一樣,這個能夠經過增長權重方法處理便可,本文不在進行深刻討論。

2.4 數據分析

基於matplotlib的可視化分析

咱們對數據處理後,很不容易進行數據分析。畢竟密密麻麻的數字略顯冰冷無趣。咱們能夠將其可視化展現出來,進而查看數據稀疏程度,離散程度等等。咱們查看'玩遊戲所耗時間百分比','每週消耗在冰淇淋的公升數'兩個屬性的散點圖,實現代碼以下:

'''
散列表分析數據:
dataset:數據集
datingLabels:標籤集
Title:列表,標題、橫座標標題、縱座標標題。
'''
def analyze_data_plot(dataset,datingLabels,Title):
    fig = plt.figure()
    # 將畫布劃分爲1行1列1塊
    ax = fig.add_subplot(111)
    ax.scatter(dataset[:,1],dataset[:,2],15.0*array(datingLabels),15.0*array(datingLabels))

     # 設置散點圖標題和橫縱座標標題
    plt.title(Title[0],fontsize=25,fontname='宋體',fontproperties=myfont)
    plt.xlabel(Title[1],fontsize=15,fontname='宋體',fontproperties=myfont)
    plt.ylabel(Title[2],fontsize=15,fontname='宋體',fontproperties=myfont)

    # 設置刻度標記大小,axis='both'參數影響橫縱座標,labelsize刻度大小
    plt.tick_params(axis='both',which='major',labelsize=10)

    # 設置每一個座標軸取值範圍
    # plt.axis([-1,25,-1,2.0])

    # 截圖保存圖片
    # plt.savefig('datasets_plot.png',bbox_inches='tight')

    # 顯示圖形
    plt.show()

這裏注意一個問題,橫縱座標是亂碼顯示,解決這個問題,添加以下代碼:

#加入中文顯示
import  matplotlib.font_manager as fm
# 解決中文亂碼,本案例使用宋體字
myfont=fm.FontProperties(fname=r"C:\\Windows\\Fonts\\simsun.ttc")

調用可視化數據分析方法以下:

''' 文件數據圖形化分析數據 '''
dataset,labels = file_matrix(filename)
noredataset = norm_dataset(dataset)[0] # 數據歸一化
title = ['約會數據遊戲和飲食散列點','玩遊戲所耗時間百分比','每週消耗在冰淇淋的公升數']
visualplot.analyze_data_plot(noredataset,labels,title)

遊戲佔比與冰淇淋公升數關係散點圖可視化:

圖2-2 遊戲佔比與冰淇淋公升數關係散點圖

折線圖代碼實現以下:

'''折線圖'''
def line_chart(xvalues,yvalues):
    # 繪製折線圖,c顏色設置,alpha透明度
    plt.plot(xvalues,yvalues,linewidth=0.5,alpha=0.5,c='red') # num_squares數據值,linewidth設置線條粗細

    # 設置折線圖標題和橫縱座標標題
    plt.title("Python繪製折線圖",fontsize=30,fontname='宋體',fontproperties=myfont)
    plt.xlabel('橫座標',fontsize=20,fontname='宋體',fontproperties=myfont)
    plt.ylabel('縱座標',fontsize=20,fontname='宋體',fontproperties=myfont)

    # 設置刻度標記大小,axis='both'參數影響橫縱座標,labelsize刻度大小
    plt.tick_params(axis='both',labelsize=14)

    # 顯示圖形
    plt.show()

遊戲佔比與冰淇淋公升數關係折線圖可視化:(此處折線圖明顯不合適,只是突出另外一種分析方式。)

圖2-3 遊戲佔比與冰淇淋公升數關係折線圖

擴展:

更多matplotlib可視化實現效果圖參考文章 70個注意的Python小Notes:完整的matplotlib可視化

基於Echart的可視化分析

咱們上面採用的matplotlib可視化效果,採用該方式主要是結合python數據分析綁定比較方便。有些時候咱們爲了取得更加漂亮的可視化效果,能夠選擇百度echart進行分析,百度Echart使用簡單且文檔規範容易上手。咱們對原數據進行分析並轉化爲json代碼:

'''array數據轉化json'''
def norm_Json(dataset):
    noredataset = norm_dataset(dataset)[0] # 數據歸一化
    number1 = np.around(noredataset[:,1], decimals=4) # 獲取數據集第二列
    number2 = np.around(noredataset[:,2], decimals=4) # 獲取數據集第三列
    returnMat=zeros((dataset.shape[0],2))             # 二維矩陣
    returnMat[:,0] = number1
    returnMat[:,1] = number2

    file_path = os.path.abspath(r"./datasource/test.json")
    json.dump(returnMat.tolist(), codecs.open(file_path, 'w', encoding='utf-8'), separators=(',', ':'), sort_keys=True, indent=4)

生成json數據保存在指定文件中,打開文件查看數據以下:

[
    [
        0.3981,
        0.5623
    ],
    [
        0.342,
        0.9872
    ],
    [
        0.0689,
        0.4745
    ],
    [
        0.6285,
        0.2525
    ]
    ...
    [
        0.4367,
        0.429
    ],
    [
        0.3768,
        0.7857
    ]
]

從百度Echart實例中選擇一種散點圖並綁定json文件,其html代碼以下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>圖案例</title>
    <script src="https://cdn.bootcss.com/jquery/2.2.0/jquery.min.js"></script>
    <script type="text/javascript" src="./js/echarts.js"></script>
</head>
<body>
    <div id="chartmain" style="width:800px; height: 400px; margin:auto; ">
    </div>

    <script type="text/javascript">
        //初始化echarts實例
        var myChart = echarts.init(document.getElementById('chartmain'));
        $.getJSON('game-food.json', function (data) {
        var option = {
            title: {
                text: '玩遊戲時間佔比和飲食數據描述',
                left: 'center',
                top: 0
            },
            visualMap: {
                min: 15202,
                max: 159980,
                dimension: 1,
                orient: 'vertical',
                right: 10,
                top: 'center',
                text: ['優秀', '通常'],
                calculable: true,
                inRange: {
                    color: ['#f2c31a', '#24b7f2']
                }
            },
            tooltip: {
                trigger: 'item',
                axisPointer: {
                    type: 'cross'
                }
            },
            xAxis: [{
                type: 'value'
            }],
            yAxis: [{
                type: 'value'
            }],
            series: [{
                name: 'price-area',
                type: 'scatter',
                symbolSize: 5,
                data: data
            }]
        };
        myChart.setOption(option);
});
    </script>
</body>
</html>

json文件讀取須要在web運行環境中,單純的運行效果以下圖所示:

 

圖2-4 遊戲佔比與冰淇淋公升數Echarts關係散點圖

數據轉化工具

本文采用本身構建的方式進行json文件生成,此外咱們也能夠採用現有的數據轉化工具進行處理。好比百度的表格數據轉化工具(2.2節已經介紹了)。

另外一個即是在線json驗證格式工具:http://www.bejson.com/

2.5 KNN分類器實現

經過數據分析,咱們查看數據樣本是否偏態分別,數據規模狀況等等。針對性進行數據預處理後,編寫具體算法模型。本文主要是KNN分類器,其代碼以下:

''' 構造KNN分類器
    vecX:輸入向量,待測數據
    filename: 特徵集文件路徑
    isnorm:是否進行歸一化處理
    k:k值的選擇,默認選擇3
'''
def knn_classifier(vecX,dataset,labels,isnorm='Y',k=3):
    # 距離計算(方法1)
    if isnorm == 'Y':
        normMat,ranges,minVals = norm_dataset(dataset)     # 對數據進行歸一化處理
        normvecX = norm_dataset(vecX)
    else:
        normMat = dataset
        normvecX = vecX

    m = normMat.shape[0]
    # tile方法是在列向量vecX,datasetSize次,行向量vecX1次疊加
    diffMat = tile(normvecX,(m,1)) - normMat
    sqDiffMat = diffMat ** 2
    sqDistances = sqDiffMat.sum(axis=1)   # axis=0 是列相加,axis=1是行相加
    distances = sqDistances**0.5
    # print('vecX向量到數據集各點距離:\n'+str(distances))

    sortedDistIndexs = distances.argsort(axis=0)  # 距離排序,升序
    # print(sortedDistIndicies)

    classCount = {}   # 統計前k個類別出現頻率
    for i in range(k):
        votelabel = labels[sortedDistIndexs[i]]
        classCount[votelabel] = classCount.get(votelabel,0) + 1 #統計鍵值
    # 類別頻率出現最高的點,itemgetter(0)按照key排序,itemgetter(1)按照value排序
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    print(str(vecX)+'KNN的投票決策結果:\n'+str(sortedClassCount[0][0]))
    return sortedClassCount[0][0]

3 KNN算法模型評估

3.1 評價指標介紹

基本知識

混淆矩陣:正元組和負元組的合計

圖3-1 混淆矩陣表

評估度量:(其中P:正樣本數 N:負樣本數 TP:真正例 TN:真負例 FP:假正例 FN:假負例)

圖3-2 評估信息度量表

注意:學習器的準確率最好在檢驗集上估計,檢驗集的由訓練集模型時未使用的含有標記的元組組成數據。

各參數描述以下:

TP(真正例/真陽性):是指被學習器正確學習的正元組,令TP爲真正例的個數。

TN(真負例/真陰性):是指被學習器正確學習的負元組,令TN爲真負例的個數。

FP(假正例/假陽性):是被錯誤的標記爲正元組的負元組。令FP爲假正例的個數。

FN(假負例/假陰性):是被錯誤的標記爲負元組的正元組。令FN爲假負例的個數。

準確率:正確識別的元組所佔的比例。

評價指標優勢

通常採用精確率和召回率做爲度量的方法具備如下幾個優勢:

(1) 準確率數值對於小數據不是特別敏感,而精確率和召回率對於這樣數據比較敏感。 (2) 在相同實驗環境下,F度量這種傾向和咱們直觀感受是一致的,咱們對目標事件很敏感,甚至返回一些垃圾數據也在所不惜。 (3) 經過精確率和找回來衡量目標事件和垃圾事件的差別。

模型評估拓展

參見《天然語言處理理論與實戰》一書第13章模型評估

3.2 評估算法模型實現

本文只是對錯誤率進行評估,其也是knn分類器核心指標,實現代碼以下:

'''測試評估算法模型'''
def test_knn_perfor(filename):
    hoRatio = 0.1
    dataset,label = file_matrix(filename)              # 獲取訓練數據和標籤
    normMat,ranges,minVals = norm_dataset(dataset)     # 對數據進行歸一化處理
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)                       # 10%的測試數據條數

    errorCount = 0.0                                   # 統計錯誤分類數
    for i in range(numTestVecs):
        classifierResult = knn_classifier(normMat[i,:],normMat[numTestVecs:m,:],label[numTestVecs:m],3)          # 此處分類器能夠替換不一樣分類模型
        print('分類結果:'+str(classifierResult)+'\t\t準確結果:'+str(label[i]))

        if classifierResult != label[i]:
            errorCount += 1.0
        Global.all_FileNum += 1
    print('總的錯誤率爲:'+str(errorCount/float(numTestVecs))+"\n總測試數據量: "+str(Global.all_FileNum))

運行效果以下:

[0.44832535 0.39805139 0.56233353]KNN的投票決策結果:
分類結果:3      準確結果:3
[0.15873259 0.34195467 0.98724416]KNN的投票決策結果:
分類結果:2      準確結果:2
...
分類結果:3      準確結果:3
[0.19385799 0.30474213 0.01919426]KNN的投票決策結果:
分類結果:2      準確結果:2
[0.24463971 0.10813023 0.60259472]KNN的投票決策結果:
分類結果:1      準確結果:1
[0.51022756 0.27138082 0.41804137]KNN的投票決策結果:
分類結果:3      準確結果:1

總的錯誤率爲:0.05
總測試數據量: 100
耗時:0.0300 s

評估結果分析:

本文采用封閉評估的方法,前100條數據做爲測試集,後900條數據做爲訓練集。如上結果最後一條信息代表knn分類器的結果是3,而標準結果是1.knn分類存在錯誤。將全部錯誤佔比分析出來即錯誤率。本文錯誤率5%,即準確率95%.

讀者能夠選取200:800、300:700等等數據進行測試查看錯誤率。

4 KNN算法模型的實際應用

knn分類器應用

通過如上的改進最終造成實際應用的算法模型API開發給外部程序使用,調用knn算法代碼以下:

'''調用可用算法'''
def show_classifyPerson(filename):
    resultlist = ['不喜歡','還能夠','特別喜歡']
    ffMiles = float(input('每一年飛行的歷程多少千米?\n'))
    percentTats = float(input('玩遊戲時間佔百分比多少?\n')) # [751,13,0.4][40920 ,8.326976,0.953952]
    iceCream = float(input('每週消費冰淇淋多少公升?\n'))

    dataset,labels = file_matrix(filename) # 數據格式化處理
    inArr = array([ffMiles,percentTats,iceCream])

    classifierResult = knn_classifier(inArr,dataset,labels,3) # 數據歸一化並進行分類
    print('預測的約會結果是:'+resultlist[classifierResult-1])

運行結果以下:

每一年飛行的歷程多少千米?
10000
玩遊戲時間佔百分比多少?
10
每週消費冰淇淋多少公升?
0.5
KNN的投票決策結果:
2
預測的約會結果是:還能夠

展望

咱們還能夠採用knn分類器進行實際應用,好比新聞分類系統。大體思路以下:

1 採集數據:選用復旦大學的文本分類新聞語料 2 準備數據:數據格式化、分詞、停用詞處理等 3 分析數據:看看數據特色,有沒有缺失值,數據連續性仍是離散型,進而選擇不一樣模型。諸如:可視化數據分析 4 數據轉化:採用IF-IDF或者神經網絡的方法對詞頻進行處理,最終轉化爲機器能夠處理的數值型矩陣。 5 構建模型:KNN新聞分類器模型構建。 6 測試算法:評價指標,如計算錯誤率,準確率,召回率,F度量值等。 7 應用算法:針對完善的模型進行封裝重構,而後進行實際的新聞分類應用。

5 參考文獻

  1. 歸一化學習:https://blog.csdn.net/hyq3235356/article/details/78472307
  2. 歸一化方法:https://blog.csdn.net/zxd1754771465/article/details/73558103
  3. 百度Echart轉化工具:http://echarts.baidu.com/spreadsheet.html
  4. 在線json驗證格式工具:http://www.bejson.com/
  5. 模型評估:http://www.cnblogs.com/baiboy/p/mxpg2.html

完整代碼下載

機器學習和天然語言QQ羣:436303759。 微信公衆號:datathinks

天然語言處理和機器學習QQ交流羣:436303759 天然語言處理和機器學習微信公衆號:datathinks

源碼請進QQ羣文件下載:

做者聲明

本文版權歸做者全部,旨在技術交流使用。未經做者贊成禁止轉載,轉載後需在文章頁面明顯位置給出原文鏈接,不然相關責任自行承擔。轉載必須註明出處【伏草唯存】:一步步教你輕鬆學KNN模型算法

相關文章
相關標籤/搜索