該例子來自於《算法圖解》,看下圖中的水果是橙子仍是柚子?git
個人思惟過程相似於這樣:我腦子裏面有個圖表github
圖中左下的表示橙子,右上的表示柚子,取橙子和柚子的兩個特徵(大和紅),通常而言,柚子更大、更紅,上圖的水果又大又紅,所以多是柚子,那下面的水果呢?算法
一種辦法是看它的鄰居,離它最近的鄰居的三個鄰居中有兩個橙子一個柚子,所以這個水果極可能是橙子app
上面剛使用的方法就是KNN(K-近鄰算法),感受是否是很簡單測試
對未知類別屬性的數據集中的每一個點依次執行如下操做:spa
(1)計算已知類別數據集中的點與當前點之間的距離code
(2)按照距離遞增順序排序orm
(3)選取與當前點距離最小的K個點對象
(4)肯定前k個點所在類別的出現頻率blog
(5)返回前k個點出現頻率最高的類別做爲當前點的預測分類
使用Python按照上面的步驟實現算法
import numpy as np def knn(labels, dataset, in_data,k): """ labels:list dataset:ndarray in_data:ndarray k:int """ row = dataset.shape[0] sub_set = dataset - np.tile(in_data,(row,1)) sqrt_set = sub_set ** 2 distance = sqrt_set.sum(axis=1) ** 0.5 dic = {} sortedIndex_list = distance.argsort() # 算出鄰居中對應的label次數 result = {} for i in range(k): key = sortedIndex_list[i] result[labels[key]] = result.get(labels[key],0)+1 result_list=sorted(result.items(), key=lambda x: x[1],reverse=True) return result_list[0][0]
需求:
根據數據特徵值(玩遊戲所耗時間百分比、每一年得到的飛行里程數、每週消費的冰淇淋公升數),判斷對該約會對象的喜愛程度,絕對是否要去約會
準備工做:
(1)數據集:dataset\datingTestSet2.txt
(2)數據集特徵:
a. 玩遊戲所耗時間百分比 ---->數據集中的第一列
b. 每一年得到的飛行里程數 ---->數據集中的第二列
c. 每週消費的冰淇淋公升數 ---->數據集中的第三列
(3)樣本分類標籤:---->數據集中的第四列
(4)測試數據集:dataset\datingTestSet.txt
實現:
(1)從文件提取數據集和標籤
def file2matrix(filename): """將文件數據轉換爲numpy.ndarray""" list_lines = [] with open(filename,'r') as pf: lines = pf.readlines() for line in lines: list_lines.append([float(i) for i in line.strip().split('\t')]) matrix = np.array(list_lines) data_set = matrix[:,0:-1] class_labels = matrix[:,-1:] class_labels = class_labels.reshape(1,1000).tolist()[0] return data_set,class_labels
(2)對數據集中的特徵值數據進行歸一化處理
def auto_norm(dataset): """ 爲了防止各特徵值之間的數值差距太大而影響計算結果, 對矩陣數據進行歸一化處理,將每一個特徵值都轉換爲[0,1] """ min = dataset.min(0) max = dataset.max(0) sub = max - min norm_dataset = np.zeros(dataset.shape) row = dataset.shape[0] norm_dataset = dataset - np.tile(min,(row,1)) norm_dataset = norm_dataset / np.tile(sub,(row,1)) return norm_dataset,sub,min
(3)使用測試數據集對算法進行測試
def test_datingTestSet(): data_set,date_labels = file2matrix('dataset\\datingTestSet2.txt') norm_dataset,sub,min = auto_norm(data_set) #根據數據集測試KNN算法的正確率 rows = norm_dataset.shape[0] ok = 0 for i in range(rows): result = knn(date_labels,norm_dataset,norm_dataset[i,:],3) if result == date_labels[i]: ok += 1 else: print("測試錯誤結果爲{},正確結果爲{}".format(result, date_labels[i])) print("測試總記錄數爲{},成功記錄數爲{},KNN算法成功率爲{}".format(rows,ok,ok/rows))
輸出:
需求:
根據dataset\trainingDigits文件夾中的樣本數據和dataset\testDigits文件夾中的樣本數據測試KNN算法
實現:
(1)將每一個文件中的數據(32*32)轉換爲matrix(m*1024)
def imgae2matrix(filepath): filelist = os.listdir(filepath) m = len(filelist) array_m_1024 = np.zeros((m,1024)) k = 0 labels = [] for file in filelist: #對文件名進行處理獲得labels label = file.split('_')[0] labels.append(label) array_1_1024 = np.zeros((1,1024)) with open(os.path.join(filepath,file),'r') as pf: for i in range(32): line = pf.readline() for j in range(32): array_1_1024[0,32*i+j] = int(line[j]) array_m_1024[k,:] = array_1_1024 k+=1 return array_m_1024,labels
(2)使用knn算法測試成功率
def test_numbers(): array_m_1024,labels = imgae2matrix('dataset\\trainingDigits\\') test_array_m_1024,test_labels = imgae2matrix('dataset\\testDigits\\') ok = 0 rows = test_array_m_1024.shape[0] for i in range(rows): in_data = test_array_m_1024[i,:] result = knn(labels, array_m_1024, in_data,5) if result == test_labels[i]: ok += 1 else: print("測試錯誤結果爲{},正確結果爲{}".format(result, test_labels[i])) print("測試總記錄數爲{},成功記錄數爲{},KNN算法成功率爲{}".format(rows,ok,ok/rows))
(3)輸出
K-近鄰算法是分類數據最簡單有效的算法,使用算法時必須有接近實際數據的訓練樣本數據,若是訓練數據集很大,必須使用大量的存儲空間,此外因爲必須對數據集中的每一個數據計算距離值,實際使用時可能很是耗時。
K-近鄰算法的另外一個缺陷是它沒法給出任何數據的基礎結構信息,所以咱們也沒法知曉平均實例樣本和典型實例樣本具備什麼特徵。
代碼和數據集都已上傳至:https://github.com/lizoo6zhi/MachineLearn.samples