ML作業1——KNN+k折交叉驗證
阿新 • • 發佈:2019-01-10
程式碼:
# -*- coding: utf-8 -*- """ Created on Fri Mar 23 11:48:16 2018 @author: 安穎 """ import numpy as np import matplotlib.pyplot as plt #計算兩樣本間距離 def getinstance(x,y): #歐氏距離求平方和 for i in range(4): inst = pow(x[i]-y[i],2) return np.sqrt(inst) #knn 演算法 def knn(x,t_train,k): #距離矩陣 disarr = [] for i in range(len(t_train)): disarr.append(getinstance(x,t_train[i])) #argsort函式返回的是陣列值從小到大的索引值 index = list(np.argsort(disarr)) #記錄k近鄰點屬於不同類的數目 indexlable = [0]*3 for i in range(k): #y為第i近的點 y = t_train[index[i]] if y[4] == 1: indexlable[0] += 1 elif y[4] == 2: indexlable[1] += 1 else: indexlable[2] += 1 lable = np.argsort(indexlable) #返回同一類中最多的類 return (lable[2]+1) # k_fold 產生一個迭代器 #n為資料集,n_folds為折數 def k_fold(data,n_folds): #根據資料集格式,1/2/3類分別集中在三段 label_a = data[:50] label_b = data[50:100] label_c = data[100:] #構建一個折數為n_folds的陣列,每組中的數為均分的數目,用於k折交叉驗證迴圈產生訓練集和測試集 fold_sizes = (50 / n_folds) * np.ones(n_folds, dtype=np.int) #開始位置為0 current = 0 #迴圈產生訓練集和測試集 for fold_size in fold_sizes: start, stop = current, current + int(fold_size) #拼接訓練集 train_index = list(np.concatenate((label_a[:start], label_a[stop:]))) index1 = list(np.concatenate((label_b[:start], label_b[stop:]))) index2 = list(np.concatenate((label_c[:start], label_c[stop:]))) train_index.extend(index1) train_index.extend(index2) #拼接測試集 test_index = list(label_a[start:stop]) test_index.extend(label_b[start:stop]) test_index.extend(label_c[start:stop]) #yield 傳回函式 用.next()或在迴圈中呼叫 yield train_index, test_index current = stop # move one step forward #交叉驗證 #迴圈計算錯誤率求均值 def cross_validate(X,kn): error = 0.0 n_folds=5 kf = k_fold(X, n_folds) for train_index, test_index in kf: error += error_rate(test_index,train_index,kn) return round(error/n_folds , 2) #計算錯誤率 def error_rate(test,train,k): error = 0 for i in range(len(test)): #預測類別 pre_lable = knn(test[i],train,k) if pre_lable != int(test[i][4]): error += 1 return float(error/len(test)) if __name__ == '__main__': t_data = [] #資料預處理 with open('iris.txt', 'r') as data_txt: data = data_txt.readlines() for line in data: temp = line.split(',') t_data.append([float(temp[0]),float(temp[1]),float(temp[2]),float(temp[3]),int(temp[4])]) t_data = np.array(t_data) #最優錯誤率 minerror = 1.0 #y存放錯誤率陣列 y = [] for j in range(120): newerror = cross_validate(t_data,j+1) if minerror > newerror: minerror = newerror mink = j+1 y.append(newerror) x = range(1,121) #畫折線圖 plt.plot(x,y,linewidth=3,color='r') print("最小錯誤率為:"+str(minerror)+"此時k值為:"+str(mink))
知識點:
1、畫折線圖
import matplotlib.pyplot as plt
y = []
x = range(1,121)
plt.plot(x,y,linewidth=3,color='r')
2、append()方法是指在列表末尾增加一個數據項。格式為list.append(***)
extend()方法是指在列表末尾增加一個數據集合。格式為list.extend(anotherlist)
insert()方法是指在某個特定位置前面增加一個數據項。格式為list.insert(index,***)
3、yield關鍵字(還不太懂)
yield 的作用就是把一個函式變成一個 generator,帶有 yield 的函式不再是一個普通函式,Python 直譯器會將其視為一個 generator,呼叫 fab(5) 不會執行 fab 函式,而是返回一個 iterable 物件!在 for 迴圈執行時,每次迴圈都會執行 fab 函式內部的程式碼,執行到 yield b 時,fab 函式就返回一個迭代值,下次迭代時,程式碼從 yield b 的下一條語句繼續執行,而函式的本地變數看起來和上次中斷執行前是完全一樣的,於是函式繼續執行,直到再次遇到 yield。