1. 程式人生 > >day-9 sklearn庫和python自帶庫實現最近鄰KNN算法

day-9 sklearn庫和python自帶庫實現最近鄰KNN算法

-m 寬度 ont 產生 res 長度 比較 target 1.2

  K最近鄰(k-Nearest Neighbor,KNN)分類算法,是一個理論上比較成熟的方法,也是最簡單的機器學習算法之一。該方法的思路是:如果一個樣本在特征空間中的k個最相似(即特征空間中最鄰近)的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別。誰和我隔得近,我就跟誰是一類,有點中國古語說的近墨者黑近朱者赤意思。KNN算法中,所選擇的鄰居都是已經正確分類的對象。該方法在定類決策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。 KNN方法雖然從原理上也依賴於極限定理,但在類別決策時,只與極少量的相鄰樣本有關。由於KNN方法主要靠周圍有限的鄰近的樣本,而不是靠判別類域的方法來確定所屬類別的,因此對於類域的交叉或重疊較多的待分樣本集來說,KNN方法較其他方法更為適合。

  優點:

  • 簡單,易於理解,易於實現,無需估計參數,無需訓練;
  • 適合對稀有事件進行分類;
  • 特別適合於多分類問題(multi-modal,對象具有多個類別標簽), kNN比SVM的表現要好。

  缺點:

  • 該算法在分類時有個主要的不足是,當樣本不平衡時,如一個類的樣本容量很大,而其他類樣本容量很小時,有可能導致當輸入一個新樣本時,該樣本的K個鄰居中大容量類的樣本占多數。 該算法只計算“最近的”鄰居樣本,某一類的樣本數量很大,那麽或者這類樣本並不接近目標樣本,或者這類樣本很靠近目標樣本。無論怎樣,數量並不能影響運行結果。
  • 該方法的另一個不足之處是計算量較大,因為對每一個待分類的文本都要計算它到全體已知樣本的距離,才能求得它的K個最近鄰點。
  • 可理解性差,無法給出像決策樹那樣的規則。

  kNN算法因其提出時間較早,隨著其他技術的不斷更新和完善,kNN算法的諸多不足之處也逐漸顯露,因此許多kNN算法的改進算法也應運而生。

  針對以上算法的不足,算法的改進方向主要分成了分類效率和分類效果兩方面。

  分類效率:事先對樣本屬性進行約簡,刪除對分類結果影響較小的屬性,快速的得出待分類樣本的類別。該算法比較適用於樣本容量比較大的類域的自動分類,而那些樣本容量較小的類域采用這種算法比較容易產生誤分。

  分類效果:采用權值的方法(和該樣本距離小的鄰居權值大)來改進,Han等人於2002年嘗試利用貪心法,針對文件分類實做可調整權重的k最近鄰居法WAkNN (weighted adjusted k nearest neighbor),以促進分類效果;而Li等人於2004年提出由於不同分類的文件本身有數量上有差異,因此也應該依照訓練集合中各種分類的文件數量,選取不同數目的最近鄰居,來參與分類。

  同樣,sklearn也為我們提供了一個算法接口,如下是代碼示例:

from sklearn import neighbors
from sklearn import datasets

knn = neighbors.KNeighborsClassifier()
iris = datasets.load_iris()
knn.fit(iris.data,iris.target)
predictedLabel = knn.predict([[0.1,0.2,0.3,0.4]])
print(predictedLabel)

  通過調用datasets.load_iris()接口,我們可以獲取一個150個實例的訓練數據集,記錄萼片長度,萼片寬度,花瓣長度,花瓣寬度(sepal length, sepal width, petal length and petal width),對應Iris setosa, Iris versicolor, Iris virginica類別。調用knn.predict([[0.1,0.2,0.3,0.4]])接口時,內部會將該測試數據與所有一直數據求歐幾裏得舉例,然後取K個最近點,算得最後的類別。

  如下是執行結果:

 技術分享圖片

  在此基礎上,我們利用python自帶庫,實現了該算法,訓練和測試數據集如下:  

技術分享圖片
5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5.0,3.6,1.4,0.2,Iris-setosa
5.4,3.9,1.7,0.4,Iris-setosa
4.6,3.4,1.4,0.3,Iris-setosa
5.0,3.4,1.5,0.2,Iris-setosa
4.4,2.9,1.4,0.2,Iris-setosa
4.9,3.1,1.5,0.1,Iris-setosa
5.4,3.7,1.5,0.2,Iris-setosa
4.8,3.4,1.6,0.2,Iris-setosa
4.8,3.0,1.4,0.1,Iris-setosa
4.3,3.0,1.1,0.1,Iris-setosa
5.8,4.0,1.2,0.2,Iris-setosa
5.7,4.4,1.5,0.4,Iris-setosa
5.4,3.9,1.3,0.4,Iris-setosa
5.1,3.5,1.4,0.3,Iris-setosa
5.7,3.8,1.7,0.3,Iris-setosa
5.1,3.8,1.5,0.3,Iris-setosa
5.4,3.4,1.7,0.2,Iris-setosa
5.1,3.7,1.5,0.4,Iris-setosa
4.6,3.6,1.0,0.2,Iris-setosa
5.1,3.3,1.7,0.5,Iris-setosa
4.8,3.4,1.9,0.2,Iris-setosa
5.0,3.0,1.6,0.2,Iris-setosa
5.0,3.4,1.6,0.4,Iris-setosa
5.2,3.5,1.5,0.2,Iris-setosa
5.2,3.4,1.4,0.2,Iris-setosa
4.7,3.2,1.6,0.2,Iris-setosa
4.8,3.1,1.6,0.2,Iris-setosa
5.4,3.4,1.5,0.4,Iris-setosa
5.2,4.1,1.5,0.1,Iris-setosa
5.5,4.2,1.4,0.2,Iris-setosa
4.9,3.1,1.5,0.1,Iris-setosa
5.0,3.2,1.2,0.2,Iris-setosa
5.5,3.5,1.3,0.2,Iris-setosa
4.9,3.1,1.5,0.1,Iris-setosa
4.4,3.0,1.3,0.2,Iris-setosa
5.1,3.4,1.5,0.2,Iris-setosa
5.0,3.5,1.3,0.3,Iris-setosa
4.5,2.3,1.3,0.3,Iris-setosa
4.4,3.2,1.3,0.2,Iris-setosa
5.0,3.5,1.6,0.6,Iris-setosa
5.1,3.8,1.9,0.4,Iris-setosa
4.8,3.0,1.4,0.3,Iris-setosa
5.1,3.8,1.6,0.2,Iris-setosa
4.6,3.2,1.4,0.2,Iris-setosa
5.3,3.7,1.5,0.2,Iris-setosa
5.0,3.3,1.4,0.2,Iris-setosa
7.0,3.2,4.7,1.4,Iris-versicolor
6.4,3.2,4.5,1.5,Iris-versicolor
6.9,3.1,4.9,1.5,Iris-versicolor
5.5,2.3,4.0,1.3,Iris-versicolor
6.5,2.8,4.6,1.5,Iris-versicolor
5.7,2.8,4.5,1.3,Iris-versicolor
6.3,3.3,4.7,1.6,Iris-versicolor
4.9,2.4,3.3,1.0,Iris-versicolor
6.6,2.9,4.6,1.3,Iris-versicolor
5.2,2.7,3.9,1.4,Iris-versicolor
5.0,2.0,3.5,1.0,Iris-versicolor
5.9,3.0,4.2,1.5,Iris-versicolor
6.0,2.2,4.0,1.0,Iris-versicolor
6.1,2.9,4.7,1.4,Iris-versicolor
5.6,2.9,3.6,1.3,Iris-versicolor
6.7,3.1,4.4,1.4,Iris-versicolor
5.6,3.0,4.5,1.5,Iris-versicolor
5.8,2.7,4.1,1.0,Iris-versicolor
6.2,2.2,4.5,1.5,Iris-versicolor
5.6,2.5,3.9,1.1,Iris-versicolor
5.9,3.2,4.8,1.8,Iris-versicolor
6.1,2.8,4.0,1.3,Iris-versicolor
6.3,2.5,4.9,1.5,Iris-versicolor
6.1,2.8,4.7,1.2,Iris-versicolor
6.4,2.9,4.3,1.3,Iris-versicolor
6.6,3.0,4.4,1.4,Iris-versicolor
6.8,2.8,4.8,1.4,Iris-versicolor
6.7,3.0,5.0,1.7,Iris-versicolor
6.0,2.9,4.5,1.5,Iris-versicolor
5.7,2.6,3.5,1.0,Iris-versicolor
5.5,2.4,3.8,1.1,Iris-versicolor
5.5,2.4,3.7,1.0,Iris-versicolor
5.8,2.7,3.9,1.2,Iris-versicolor
6.0,2.7,5.1,1.6,Iris-versicolor
5.4,3.0,4.5,1.5,Iris-versicolor
6.0,3.4,4.5,1.6,Iris-versicolor
6.7,3.1,4.7,1.5,Iris-versicolor
6.3,2.3,4.4,1.3,Iris-versicolor
5.6,3.0,4.1,1.3,Iris-versicolor
5.5,2.5,4.0,1.3,Iris-versicolor
5.5,2.6,4.4,1.2,Iris-versicolor
6.1,3.0,4.6,1.4,Iris-versicolor
5.8,2.6,4.0,1.2,Iris-versicolor
5.0,2.3,3.3,1.0,Iris-versicolor
5.6,2.7,4.2,1.3,Iris-versicolor
5.7,3.0,4.2,1.2,Iris-versicolor
5.7,2.9,4.2,1.3,Iris-versicolor
6.2,2.9,4.3,1.3,Iris-versicolor
5.1,2.5,3.0,1.1,Iris-versicolor
5.7,2.8,4.1,1.3,Iris-versicolor
6.3,3.3,6.0,2.5,Iris-virginica
5.8,2.7,5.1,1.9,Iris-virginica
7.1,3.0,5.9,2.1,Iris-virginica
6.3,2.9,5.6,1.8,Iris-virginica
6.5,3.0,5.8,2.2,Iris-virginica
7.6,3.0,6.6,2.1,Iris-virginica
4.9,2.5,4.5,1.7,Iris-virginica
7.3,2.9,6.3,1.8,Iris-virginica
6.7,2.5,5.8,1.8,Iris-virginica
7.2,3.6,6.1,2.5,Iris-virginica
6.5,3.2,5.1,2.0,Iris-virginica
6.4,2.7,5.3,1.9,Iris-virginica
6.8,3.0,5.5,2.1,Iris-virginica
5.7,2.5,5.0,2.0,Iris-virginica
5.8,2.8,5.1,2.4,Iris-virginica
6.4,3.2,5.3,2.3,Iris-virginica
6.5,3.0,5.5,1.8,Iris-virginica
7.7,3.8,6.7,2.2,Iris-virginica
7.7,2.6,6.9,2.3,Iris-virginica
6.0,2.2,5.0,1.5,Iris-virginica
6.9,3.2,5.7,2.3,Iris-virginica
5.6,2.8,4.9,2.0,Iris-virginica
7.7,2.8,6.7,2.0,Iris-virginica
6.3,2.7,4.9,1.8,Iris-virginica
6.7,3.3,5.7,2.1,Iris-virginica
7.2,3.2,6.0,1.8,Iris-virginica
6.2,2.8,4.8,1.8,Iris-virginica
6.1,3.0,4.9,1.8,Iris-virginica
6.4,2.8,5.6,2.1,Iris-virginica
7.2,3.0,5.8,1.6,Iris-virginica
7.4,2.8,6.1,1.9,Iris-virginica
7.9,3.8,6.4,2.0,Iris-virginica
6.4,2.8,5.6,2.2,Iris-virginica
6.3,2.8,5.1,1.5,Iris-virginica
6.1,2.6,5.6,1.4,Iris-virginica
7.7,3.0,6.1,2.3,Iris-virginica
6.3,3.4,5.6,2.4,Iris-virginica
6.4,3.1,5.5,1.8,Iris-virginica
6.0,3.0,4.8,1.8,Iris-virginica
6.9,3.1,5.4,2.1,Iris-virginica
6.7,3.1,5.6,2.4,Iris-virginica
6.9,3.1,5.1,2.3,Iris-virginica
5.8,2.7,5.1,1.9,Iris-virginica
6.8,3.2,5.9,2.3,Iris-virginica
6.7,3.3,5.7,2.5,Iris-virginica
6.7,3.0,5.2,2.3,Iris-virginica
6.3,2.5,5.0,1.9,Iris-virginica
6.5,3.0,5.2,2.0,Iris-virginica
6.2,3.4,5.4,2.3,Iris-virginica
5.9,3.0,5.1,1.8,Iris-virginica
View Code

  主程序源碼如下:

import math
import operator
import csv
import sys

__all__ = [loadDataSet, calculateEuclidean, getNeighbors, getNeighborsLabel, getAccuracy, main]

# 加載數據
def loadDataSet(file_name,file_mode):
    ‘‘‘
    從文本文件中讀取數據集,返回最後的數據集結果
    :param file_name: 輸入文件名稱
    :param file_mode: 打開文件模式
    :return
            traning_datasets: 訓練數據集
            test_datasets:測試數據集
    ‘‘‘
    traning_datasets = []
    test_datasets = []
    with open(file_name,file_mode) as csv_file:
        lines = csv.reader(csv_file)
        try:
            k = 0
            for row in lines:
                # 進行實數轉換 [5.1, 3.5, 1.4, 0.2, ‘Iris-setosa‘]
                for i in range(len(row)-1):
                    row[i] = float(row[i])
                if k%2 == 0:
                    traning_datasets.append(row)
                else:
                    test_datasets.append(row)
                k += 1
        except csv.Error as e:
            sys.exit(file %s, line %d: %s % (file_name, lines.line_num, e))
    return traning_datasets,test_datasets

# 計算歐幾裏得距離
def calculateEuclidean(single_data1,single_data2):
    ‘‘‘
    根據輸入的兩點,求歐幾裏得距離
    :param single_data1: 輸入點1
    :param single_data2: 輸入點2
    :return euclidean_distance: 兩點之間的歐幾裏得距離
    ‘‘‘
    euclidean_distance = 0.0
    if len(single_data1) != len(single_data2):
        return
    sum = 0.0
    for i in range(len(single_data1)-1):
        sum += float(math.pow((single_data1[i] - single_data2[i]),2))
    euclidean_distance = math.sqrt(sum)
    return euclidean_distance

# 獲取最近鄰點
def getNeighbors(test_data_set,tranning_data_set,k):
    ‘‘‘
    根據測試數據、訓練數據集和K值,求取最近K個鄰點
    :param test_data_set:
    :param tranning_data_set:
    :param k:
    :return neighbors:訓練數據集中K個最近鄰點
    ‘‘‘
    neighbors = []
    results = []
    for i in range(len(tranning_data_set)):
        euclidistance = calculateEuclidean(test_data_set,tranning_data_set[i])
        results.append((tranning_data_set[i],euclidistance))
        results.sort(key=operator.itemgetter(1))
    for i in range(k):
        neighbors.append(results[i][0])
    return neighbors

# 獲取結果
def getNeighborsLabel(neighbors):
    ‘‘‘
    輸入最近鄰點,求取其所屬分類
    :param neighbors:K個最近鄰點
    :return result:判定數據所屬類
    ‘‘‘
    results = {}
    for row in neighbors:
        if row[-1] not in results.keys():
            results[row[-1]] = 1
        else:
            results[row[-1]] += 1
    # 對字典進行排序
    sorted_results = sorted(results.items(),key=operator.itemgetter(1),reverse=True)
    result = sorted_results[0][0]
    return result

# 獲取準確率
def getAccuracy(predictions):
    ‘‘‘
    獲取準確率
    :param predictions:預測結果集
    :return accuracy: 準確率
    ‘‘‘
    accuracy = 0.0
    sum = 0
    for row in predictions:
        if row[1] == row[0][-1]:
            sum += 1
    accuracy = float(sum/len(predictions))*100.0
    return accuracy

def main():
    predictions = []

    traning_datasets,test_datasets = loadDataSet(ririsdata.txt,r)

    for test_data in test_datasets:
        neighbors = getNeighbors(test_data,traning_datasets,k=10)
        result = getNeighborsLabel(neighbors)
        predictions.append((test_data,result))
        print(> predicted = , result, ,actual = , test_data)

    accuracy = getAccuracy(predictions)
    print(準確率為:%f%%%(accuracy))

if __name__ == "__main__":
    import KNN_euklidean
    print(help(KNN_euklidean))
    main()

  在該樣本集下,測試的準確率為96%,實際準確率會隨樣本而變化:

  技術分享圖片

day-9 sklearn庫和python自帶庫實現最近鄰KNN算法