日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

周志华《机器学习》习题3.4——用UCI数据集比较10折交叉验证法和留一法

發布時間:2023/12/20 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 周志华《机器学习》习题3.4——用UCI数据集比较10折交叉验证法和留一法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.題目

選擇兩個 UCI 數據集,比較 10 折交叉驗證法和留一法所估計出的對率回歸的錯誤率。(本文就對一個UCI數據集用兩種評估方法實現了,畢竟再對另一個數據集的實現方法是一樣的)

2.下載UCI數據集

導入數據集的方法有很多,可以直接從官網下載數據集文件,也從keras庫里直接導入,本文使用第一種方法。
首先,進入UCI官網:https://archive.ics.uci.edu/ml/
在UCI主頁下的 Most Popular Data Sets 能看見由很多常用數據集,包含最常用的鳶(yuan)尾花、酒、車等等,本文就使用最經典的鳶尾花了。
點擊IRIS圖標進入鳶尾花數據集頁面:

這里表格包含了一些比較重要的信息:

同時,下方包含了對屬性和類別的說明。

像該數據集,用于分類任務,包含150條數據,每條數據含有4個屬性,不存在數據缺失,擁有3個類別(也就是多分類任務)。
確認數據集是我們想要的后,點擊Data Folder進入數據的文件目錄。

然后,點擊iris.data下載該數據集文件。

打開下載后的文件,可以看到,每條數據(對應每朵花)占一行,每行包含用逗號隔開的4個數字和1個字符串,每個數字對應一朵花的對應屬性值,字符串表示該條數據屬于的類別。

3.實現思路

3.1 評估方法

本題需要實現兩種評估算法,分別為10折交叉驗證留一法

首先,對于10折交叉驗證,其思想是將數據集劃分為10份(劃幾份就是幾折),然后任取1份做測試集,另取9份做訓練集,根據排列組合可知有10種取法,然后,對于每種取法,對學習器(本文使用對率回歸模型)進行訓練,然后用測試集測試,10輪后能得到10個正確率(注意每輪訓練都是重新訓練,也就是說,一共要訓練和測試10次),最后將10個正確率取平均值當作最后該模型的正確率。

然后,對于留一法,簡單來說就是m折交叉認證(m等于數據實例數),對于該數據集就是150折交叉驗證,每輪留1個做測試集,其余149個做訓練集,最后會得到150個準確率(當然,不是100%就是0%),然后取平均值作為模型正確率。

3.2 多分類方法

對于線性模型,多分類任務一般使用拆分策略,即將任務差分為多個二分類任務,拆分策略包括一對一(OvO)、一對多(OvR)和多對多(MvM)。本文將會使用OvR實現多分類。

這里講一下OvO,該策略會將任務中的多個類別兩兩組合,然后對于每個組合,將其看作一個二分類任務(例如本題有3個類,有3種組合方法,需要訓練三個二分類學習器),訓練完成后,在預測時,只需要將測試實例輸入到這些二分類學習器中,最后統計哪個類別結果多即可。

OvR則是將任務中的多個類別按照“一個類是正類,其余類都是負類”的規則劃分,例如本例中包含三個花的類別:Iris-setosa、Iris-versicolor、Iris-virginica,先將Iris-setosa視為正例,然后將Iris-versicolor、Iris-virginica視為反例,這樣就會形成一個二分類學習器,然后同理能一共得到三個二分類學習器,在預測時,只需要將測試實例分別輸入到三個學習器中,觀察三個學習器的結果,然后看哪個學習器輸出正例,則認為該實例屬于對應類別。而對于MvM,由于這里只有3個類別,使用MvM也會退化成OvR,所以無需使用了。

4. python實現

(1)讀取數據集
將數據集文件按照行依次讀取,每行按逗號分割,然后將用于表示類別的字符串轉換為數字(三個類對應數字1,2,3)。

import numpy as np import math import random# 讀取UCI數據集 def read_uci(dir):iris = []with open(dir, 'r+') as f:for line in f.readlines():iris.append(line.split(','))x = []y = []for iri in iris[:-1]:name = iri[4]x.append([float(xi) for xi in iri[:-1]])if "setosa" in name:y.append(1)elif "versicolor" in name:y.append(2)elif "virginica" in name:y.append(3)return x,y

(2) 二分類實現
實現多分類學習器前,先要實現二分類學習器,本文使用對率回歸模型,對對率回歸的損失函數進行梯度下降,其中對率回歸的損失函數為:
l(β)=∑i=1m[?yiβTx^i+ln?(eβTx^i+1)]\boldsymbol{l{}}(\boldsymbol{\beta}) = \sum_{i=1}^{m}[-y_{i}\beta^{T}\widehat{x}_{i}+\ln(e^{\beta^{T}\widehat{x}_{i}}+1)]l(β)=i=1m?[?yi?βTxi?+ln(eβTxi?+1)]
梯度下降公式為:
βt+1=βt?s?l(β)?β\boldsymbol{\beta} ^{t+1}=\boldsymbol{\beta} ^{t}-s\frac{\partial \boldsymbol{l{}}(\boldsymbol{\beta})}{\partial \boldsymbol{\beta}} βt+1=βt?s?β?l(β)?
按照上述公式實現梯度下降即可。然后說一下超參數,這里對beta設置初始值為全1,d表示收斂的界限,就是當beta在下降過程中如果不超過0.01則表示已經收斂,就不用繼續下降了,alpha表示步長(對應公式的s),n表示最大下降次數。這些值設置可以相對隨意,然后經過測試可以找到一個比較好的參數,本文就測試了6、7次,按照最高正確率選出的參數。

def train_2(x:np.array, y:np.array):beta = np.array([1.0,1.0,1.0,1.0,1.0]).Td = 0.01 # 變化量小于d時表示收斂alpha = 0.005n = 500 for i in range(n):dl_sum = 0for i in range(np.shape(x)[0]):xi_hat = np.r_[x[i], 1].Tei = np.math.exp(beta.T.dot(xi_hat))p1 = ei / (1 + ei)dl = xi_hat.dot(y[i]-p1)dl_sum -= dl # print(dl_sum)if np.all(dl_sum < d) and np.all(dl_sum > -d):breakbeta -= alpha * dl_sum;return beta

(3)三分類學習器
二分類實現完,就可以實現三分類了,主要就是把y,也就是標簽處理一下,這里第一個循環用于將1類看為正類,2、3類分為反類,以此類推,第二個循環是,2正,1、3反,第三個循環是,3正,1,2反。

def train_3(x, y):y1 = []for yi in y:if yi == 1:y1.append(1)else:y1.append(0)beta1 = train_2(x, y1)print("學習器1訓練完成,參數:", beta1)y2 = []for yi in y:if yi == 2:y2.append(1)else:y2.append(0)beta2 = train_2(x, y2)print("學習器2訓練完成,參數:", beta2)y3 = []for yi in y:if yi == 3:y3.append(1)else:y3.append(0)beta3 = train_2(x, y3)print("學習器3訓練完成,參數:", beta3)return beta1, beta2, beta3

(4)10折交叉驗證
這里為了實現每折數據的類別比例都是1:1:1,將數據集先按照類別分開,然后在各自打亂,最后再分成10部分,取9部分訓練1部分測試。

def cv10_devide_test(x, y):sumn = len(x)r_rate_sum = 0x1 = []x2 = []x3 = []for i in range(sumn):if y[i] == 1:x1.append(x[i])elif y[i] == 2:x2.append(x[i])elif y[i] == 3:x3.append(x[i])random.shuffle(x1)random.shuffle(x2)random.shuffle(x3)for i in range(10):train_x = []train_y = []test_x = []test_y = []x1_delta = len(x1)/10x2_delta = len(x2)/10x3_delta = len(x3)/10for j in range(len(x1)):if j >= i*x1_delta and j < (i+1)*x1_delta:test_x.append(x1[j])test_y.append(1)else:train_x.append(x1[j])train_y.append(1)for j in range(len(x2)):if j >= i*x2_delta and j < (i+1)*x2_delta:test_x.append(x2[j])test_y.append(2)else:train_x.append(x2[j])train_y.append(2)for j in range(len(x3)):if j >= i*x3_delta and j < (i+1)*x3_delta:test_x.append(x3[j])test_y.append(3)else:train_x.append(x3[j])train_y.append(3)# print("train_x:", train_x) # print("train_y:", train_y) # print("test_x:", test_x) # print("test_y:", test_y)beta1, beta2, beta3 = train_3(train_x, train_y)print(f"第{i+1}折訓練完成")r_rate = test(beta1, beta2, beta3, test_x, test_y)r_rate_sum += r_rateavg_r_rate = r_rate_sum/10print("交叉驗證平均正確率為:",avg_r_rate)return train_x, train_y, test_x, test_y

(5)留一法
留一法與上面交叉驗證一樣,區別在于只留一個進行測試,所以要進行150次訓練測試,運行時間會長一些。

def cv1_devide_test(x, y):sumn = len(x)r_rate_sum = 0for i in range(sumn):train_x = []train_y = []test_x = []test_y = []for j in range(sumn):if j == i:test_x.append(x[j])test_y.append(y[j])else:train_x.append(x[j])train_y.append(y[j])beta1, beta2, beta3 = train_3(train_x, train_y)r_rate = test(beta1, beta2, beta3, test_x, test_y)r_rate_sum += r_rateprint(f"第{i+1}折訓練完成")avg_r_rate = r_rate_sum/sumnprint("留一法平均正確率為:",avg_r_rate)return train_x, train_y, test_x, test_y

(6)其他函數

# sigmoid函數 def sigmoid(x):if x<-500:x = -500return 1 / (1 + math.exp(-x))# 判斷兩個浮點是是否相同 def float_equal(a, b):delta = a-bif delta > -1e-5 and delta < 1e-5:return Trueelse:return False# 預測 def predict(beta, x):y = 0for i in range(len(x)):y += x[i] * beta[i]y += beta[len(x)]return sigmoid(y)# 測試 def test(beta1, beta2, beta3, test_x, test_y):right = 0for i in range(len(test_x)):y1 = predict(beta1, test_x[i])y2 = predict(beta2, test_x[i])y3 = predict(beta3, test_x[i])if y1 >= 0.5 and test_y[i] == 1:right += 1elif y2 >= 0.5 and test_y[i] == 2:right += 1elif y3 >= 0.5 and test_y[i] == 3:right += 1r_rate = right/len(test_x)print("測試樣例總數:", len(test_x))print("通過樣例數:", right)print("正確率為:", r_rate)return r_rate

(7)主程序

if __name__ == "__main__":x,y = read_uci("./iris.data")cv10_devide_test(x, y)cv1_devide_test(x, y)

7. 結果

10折交叉驗證結果:

留一法運行結果:

10折交叉驗證準確率是86%,留一法是84%,但不代表交叉驗證要好,因為在測試運行過程中,該程序的準確率是有浮動的,比如說前幾次交叉驗證會經常出現81%左右的結果,由于留一法需要運行時間比較長,我就只運行了一次。
所以如果要想得到嚴謹的比較結果,就可以多運行幾個結果,然后再進行比較。

總結

以上是生活随笔為你收集整理的周志华《机器学习》习题3.4——用UCI数据集比较10折交叉验证法和留一法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。