K--最鄰近(K-NN)演算法
阿新 • • 發佈:2018-12-16
程式碼整理:
# -*- coding: utf-8 -* import numpy as np import matplotlib.pyplot as plt from collections import Counter def dist(A,B): a = np.asarray(A) b = np.asarray(B) a = a.ravel() b = b.ravel() d = a-b return np.linalg.norm(d) def cosSim(A,B): a = np.asarray(A) b = np.asarray(B) a = a.ravel() b = b.ravel() d1 = np.dot(a,b) d2 = np.linalg.norm(a)*np.linalg.norm(b) return d1/d2 #K_NN函式定義: #data表示測試資料 #predict表示待測試樣本 #k表示k_nn中的k值 #distfun表示選擇的距離 def k_nn_test(data,predict,k=3,distfun=dist): if len(data) >= k: print('K is set to a value less than total voting groups!') distances = [] for group in data: for features in data[group]: #計算每個樣本與測試樣本之間的距離,採用distfun距離演算法 test_distance = distfun(features,predict) #將距離以及類別組成列表存入distances中 distances.append([test_distance,group]) # print(distances) #i[0]為距離,i[1]為類別,我們需要的是類別 #取按照distances列表進行排序後的0到k-1個值 votes = [i[1] for i in sorted(distances)[:k] ] #使用collections.Counter類來統計跟蹤的值出現的次數 #most_common():取元素次數最多的前1個也就是那個多數派 vote_result = Counter(votes).most_common(1)[0][0] return vote_result if __name__ == '__main__': dataset = {'k':[[1,3],[2,4],[2,1]],'r':[[6,3],[7,7],[5,6]]} new_features = [4,4] #dataset(資料集)只是一個python字典,其中的鍵看作類,後面的值看作這個類相關的資料點 #new_features是將要預測其所屬類的點 #我們可以做一個快速圖表 for i in dataset: for i2 in dataset[i]: plt.scatter(i2[0],i2[1],s=100,color=i) plt.scatter(new_features[0],new_features[1],s=100) plt.show() result = k_nn_test(dataset,new_features) plt.scatter(new_features[0],new_features[1],s=100,color=result) plt.show()
def loadImage(filename,fsize=40): from PIL import Image image = Image.open(filename) img1 = image.resize((fsize,fsize)) image.close() img = np.asarray(img1) img1.close() x = img.ravel() #將陣列降為一維 return x #x是一張圖片生成的一個向量 def loadDataset(): import os Ylab = [chr(i+ord('A')) for i in range(26)] # Y是A到Z,26個字母構成的列表 fsize = 40 X = [] Y = [] for ypath in Ylab: #下面,最後需要[0]的作用是去掉了一層列表符號 pngfiles = [ dirs[2] for dirs in os.walk('/Users/he-jia/English_hand_writing/Img/daxie/'+ypath)][0] # pngfiles是資料夾A下面所有訓練圖片的檔名構成的列表 for file in pngfiles: #針對每一個A的訓練圖片 if not (file.endswith('.png') or file.endswith('.PNG') ): #如果不是png檔案可以跳過 continue x = loadImage('/Users/he-jia/English_hand_writing/Img/daxie/'+ypath+'/'+file,fsize) # loadImage函式用於將每一個測試圖片生成一個行向量 X.append(x) # X是一個列表 Y.append(ypath) return np.mat(X),np.asarray(Y) #這兩個函式都是將列表矩陣化, #當A資料夾裡的訓練圖片被遍歷後,X1=np.mat(X)最終是個55行4800列的矩陣,X1 是個二維矩陣,Y1 =np.asarry(Y)是由一個列向量構成的矩陣,26行1列 # 55*26 =1430,當A到Z資料夾裡的訓練圖片都被遍歷之後,X1=np.mat(X)最終是個1430行4800列的矩陣,Y1 =np.asarry(Y)是由一個列向量構成的矩陣,1430行1列 import sklearn.neighbors as knnlib import datetime begin = datetime.datetime.now() print(begin) print('------------------------') #訓練分類器 testx = loadImage('/Users/he-jia/English_hand_writing/test.png') charX,charY = loadDataset() #charX,charY 是兩個矩陣,一個1430行4800列,一個26行1列 k = int(np.sqrt(len(charY))) #k為樣本數量開方 knn = knnlib.KNeighborsClassifier(algorithm = 'ball_tree',n_neighbors=k,weights='distance',p=1) #建立knn分類器 #四個引數含義:量度距離,以曼哈頓距離演算法,k個近鄰,約等按球樹 print(charX.shape) print(charY.shape) knn = knn.fit(charX,charY) #訓練knn模型 testx = np.mat(testx) y = knn.predict(testx) #測試預測樣本,先要轉為矩陣 print('測試圖片結果為:',y) print('------------------------') end = datetime.datetime.now() print(end)